|
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 #if ENABLE(3D_CANVAS) |
|
32 #include "WebGLRenderingContext.h" |
|
33 #endif |
|
34 #include "CSSPropertyNames.h" |
|
35 #include "CSSStyleSelector.h" |
|
36 #include "FrameView.h" |
|
37 #include "GraphicsContext.h" |
|
38 #include "GraphicsLayer.h" |
|
39 #include "HTMLCanvasElement.h" |
|
40 #include "HTMLElement.h" |
|
41 #include "HTMLIFrameElement.h" |
|
42 #include "HTMLMediaElement.h" |
|
43 #include "HTMLNames.h" |
|
44 #include "InspectorTimelineAgent.h" |
|
45 #include "KeyframeList.h" |
|
46 #include "PluginViewBase.h" |
|
47 #include "RenderBox.h" |
|
48 #include "RenderIFrame.h" |
|
49 #include "RenderImage.h" |
|
50 #include "RenderLayerCompositor.h" |
|
51 #include "RenderEmbeddedObject.h" |
|
52 #include "RenderVideo.h" |
|
53 #include "RenderView.h" |
|
54 #include "Settings.h" |
|
55 |
|
56 #include "RenderLayerBacking.h" |
|
57 |
|
58 using namespace std; |
|
59 |
|
60 namespace WebCore { |
|
61 |
|
62 using namespace HTMLNames; |
|
63 |
|
64 static bool hasBorderOutlineOrShadow(const RenderStyle*); |
|
65 static bool hasBoxDecorationsOrBackground(const RenderObject*); |
|
66 static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle*); |
|
67 static IntRect clipBox(RenderBox* renderer); |
|
68 |
|
69 static inline bool is3DCanvas(RenderObject* renderer) |
|
70 { |
|
71 #if ENABLE(3D_CANVAS) |
|
72 if (renderer->isCanvas()) |
|
73 return static_cast<HTMLCanvasElement*>(renderer->node())->is3D(); |
|
74 #else |
|
75 UNUSED_PARAM(renderer); |
|
76 #endif |
|
77 return false; |
|
78 } |
|
79 |
|
80 RenderLayerBacking::RenderLayerBacking(RenderLayer* layer) |
|
81 : m_owningLayer(layer) |
|
82 , m_artificiallyInflatedBounds(false) |
|
83 { |
|
84 createGraphicsLayer(); |
|
85 } |
|
86 |
|
87 RenderLayerBacking::~RenderLayerBacking() |
|
88 { |
|
89 updateClippingLayers(false, false); |
|
90 updateForegroundLayer(false); |
|
91 updateMaskLayer(false); |
|
92 destroyGraphicsLayer(); |
|
93 } |
|
94 |
|
95 void RenderLayerBacking::createGraphicsLayer() |
|
96 { |
|
97 m_graphicsLayer = GraphicsLayer::create(this); |
|
98 |
|
99 #ifndef NDEBUG |
|
100 m_graphicsLayer->setName(nameForLayer()); |
|
101 #endif // NDEBUG |
|
102 |
|
103 updateLayerOpacity(renderer()->style()); |
|
104 updateLayerTransform(renderer()->style()); |
|
105 } |
|
106 |
|
107 void RenderLayerBacking::destroyGraphicsLayer() |
|
108 { |
|
109 if (m_graphicsLayer) |
|
110 m_graphicsLayer->removeFromParent(); |
|
111 |
|
112 m_graphicsLayer = 0; |
|
113 m_foregroundLayer = 0; |
|
114 m_clippingLayer = 0; |
|
115 m_maskLayer = 0; |
|
116 } |
|
117 |
|
118 void RenderLayerBacking::updateLayerOpacity(const RenderStyle* style) |
|
119 { |
|
120 m_graphicsLayer->setOpacity(compositingOpacity(style->opacity())); |
|
121 } |
|
122 |
|
123 void RenderLayerBacking::updateLayerTransform(const RenderStyle* style) |
|
124 { |
|
125 // FIXME: This could use m_owningLayer->transform(), but that currently has transform-origin |
|
126 // baked into it, and we don't want that. |
|
127 TransformationMatrix t; |
|
128 if (m_owningLayer->hasTransform()) { |
|
129 style->applyTransform(t, toRenderBox(renderer())->borderBoxRect().size(), RenderStyle::ExcludeTransformOrigin); |
|
130 makeMatrixRenderable(t, compositor()->hasAcceleratedCompositing()); |
|
131 } |
|
132 |
|
133 m_graphicsLayer->setTransform(t); |
|
134 } |
|
135 |
|
136 static bool hasNonZeroTransformOrigin(const RenderObject* renderer) |
|
137 { |
|
138 RenderStyle* style = renderer->style(); |
|
139 return (style->transformOriginX().type() == Fixed && style->transformOriginX().value()) |
|
140 || (style->transformOriginY().type() == Fixed && style->transformOriginY().value()); |
|
141 } |
|
142 |
|
143 static RenderLayer* enclosingOverflowClipAncestor(RenderLayer* layer, bool& crossesTransform) |
|
144 { |
|
145 crossesTransform = false; |
|
146 |
|
147 for (RenderLayer* curr = layer->parent(); curr; curr = curr->parent()) { |
|
148 if (curr->renderer()->hasOverflowClip()) |
|
149 return curr; |
|
150 |
|
151 if (curr->hasTransform()) |
|
152 crossesTransform = true; |
|
153 } |
|
154 |
|
155 return 0; |
|
156 } |
|
157 |
|
158 void RenderLayerBacking::updateCompositedBounds() |
|
159 { |
|
160 IntRect layerBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer); |
|
161 |
|
162 // Clip to the size of the document or enclosing overflow-scroll layer. |
|
163 if (compositor()->compositingConsultsOverlap() && !m_owningLayer->hasTransform()) { |
|
164 bool crossesTransform; |
|
165 RenderLayer* overflowAncestor = enclosingOverflowClipAncestor(m_owningLayer, crossesTransform); |
|
166 // If an ancestor is transformed, we can't currently compute the correct rect to intersect with. |
|
167 // We'd need RenderObject::convertContainerToLocalQuad(), which doesn't yet exist. |
|
168 if (!crossesTransform) { |
|
169 IntRect clippingBounds; |
|
170 RenderLayer* boundsRelativeLayer; |
|
171 |
|
172 if (overflowAncestor) { |
|
173 RenderBox* overflowBox = toRenderBox(overflowAncestor->renderer()); |
|
174 // If scrollbars are visible, then constrain the layer to the scrollable area, so we can avoid redraws |
|
175 // on scrolling. Otherwise just clip to the visible area (it can still be scrolled via JS, but we'll come |
|
176 // back through this code when the scroll offset changes). |
|
177 if (overflowBox->scrollsOverflow()) |
|
178 clippingBounds = IntRect(-overflowAncestor->scrollXOffset(), -overflowAncestor->scrollYOffset(), overflowBox->scrollWidth(), overflowBox->scrollHeight()); |
|
179 else |
|
180 clippingBounds = clipBox(overflowBox); |
|
181 |
|
182 boundsRelativeLayer = overflowAncestor; |
|
183 } else { |
|
184 RenderView* view = m_owningLayer->renderer()->view(); |
|
185 clippingBounds = view->layoutOverflowRect(); |
|
186 boundsRelativeLayer = view->layer(); |
|
187 } |
|
188 |
|
189 int deltaX = 0; |
|
190 int deltaY = 0; |
|
191 m_owningLayer->convertToLayerCoords(boundsRelativeLayer, deltaX, deltaY); |
|
192 clippingBounds.move(-deltaX, -deltaY); |
|
193 layerBounds.intersect(clippingBounds); |
|
194 } |
|
195 } |
|
196 |
|
197 // If the element has a transform-origin that has fixed lengths, and the renderer has zero size, |
|
198 // then we need to ensure that the compositing layer has non-zero size so that we can apply |
|
199 // the transform-origin via the GraphicsLayer anchorPoint (which is expressed as a fractional value). |
|
200 if (layerBounds.isEmpty() && hasNonZeroTransformOrigin(renderer())) { |
|
201 layerBounds.setWidth(1); |
|
202 layerBounds.setHeight(1); |
|
203 m_artificiallyInflatedBounds = true; |
|
204 } else |
|
205 m_artificiallyInflatedBounds = false; |
|
206 |
|
207 setCompositedBounds(layerBounds); |
|
208 } |
|
209 |
|
210 void RenderLayerBacking::updateAfterWidgetResize() |
|
211 { |
|
212 if (renderer()->isRenderIFrame()) { |
|
213 if (RenderLayerCompositor* innerCompositor = RenderLayerCompositor::iframeContentsCompositor(toRenderIFrame(renderer()))) |
|
214 innerCompositor->updateContentLayerOffset(contentsBox().location()); |
|
215 } |
|
216 } |
|
217 |
|
218 void RenderLayerBacking::updateAfterLayout(UpdateDepth updateDepth, bool isUpdateRoot) |
|
219 { |
|
220 RenderLayerCompositor* layerCompositor = compositor(); |
|
221 if (!layerCompositor->compositingLayersNeedRebuild()) { |
|
222 // Calling updateGraphicsLayerGeometry() here gives incorrect results, because the |
|
223 // position of this layer's GraphicsLayer depends on the position of our compositing |
|
224 // ancestor's GraphicsLayer. That cannot be determined until all the descendant |
|
225 // RenderLayers of that ancestor have been processed via updateLayerPositions(). |
|
226 // |
|
227 // The solution is to update compositing children of this layer here, |
|
228 // via updateCompositingChildrenGeometry(). |
|
229 updateCompositedBounds(); |
|
230 layerCompositor->updateCompositingDescendantGeometry(m_owningLayer, m_owningLayer, updateDepth); |
|
231 |
|
232 if (isUpdateRoot) { |
|
233 updateGraphicsLayerGeometry(); |
|
234 layerCompositor->updateRootLayerPosition(); |
|
235 } |
|
236 } |
|
237 } |
|
238 |
|
239 bool RenderLayerBacking::updateGraphicsLayerConfiguration() |
|
240 { |
|
241 RenderLayerCompositor* compositor = this->compositor(); |
|
242 |
|
243 bool layerConfigChanged = false; |
|
244 if (updateForegroundLayer(compositor->needsContentsCompositingLayer(m_owningLayer))) |
|
245 layerConfigChanged = true; |
|
246 |
|
247 if (updateClippingLayers(compositor->clippedByAncestor(m_owningLayer), compositor->clipsCompositingDescendants(m_owningLayer))) |
|
248 layerConfigChanged = true; |
|
249 |
|
250 if (updateMaskLayer(m_owningLayer->renderer()->hasMask())) |
|
251 m_graphicsLayer->setMaskLayer(m_maskLayer.get()); |
|
252 |
|
253 if (m_owningLayer->hasReflection()) { |
|
254 if (m_owningLayer->reflectionLayer()->backing()) { |
|
255 GraphicsLayer* reflectionLayer = m_owningLayer->reflectionLayer()->backing()->graphicsLayer(); |
|
256 m_graphicsLayer->setReplicatedByLayer(reflectionLayer); |
|
257 } |
|
258 } else |
|
259 m_graphicsLayer->setReplicatedByLayer(0); |
|
260 |
|
261 if (isDirectlyCompositedImage()) |
|
262 updateImageContents(); |
|
263 |
|
264 if (renderer()->isEmbeddedObject() && toRenderEmbeddedObject(renderer())->allowsAcceleratedCompositing()) { |
|
265 PluginViewBase* pluginViewBase = static_cast<PluginViewBase*>(toRenderEmbeddedObject(renderer())->widget()); |
|
266 m_graphicsLayer->setContentsToMedia(pluginViewBase->platformLayer()); |
|
267 } |
|
268 #if ENABLE(VIDEO) |
|
269 else if (renderer()->isVideo()) { |
|
270 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(renderer()->node()); |
|
271 m_graphicsLayer->setContentsToMedia(mediaElement->platformLayer()); |
|
272 } |
|
273 #endif |
|
274 #if ENABLE(3D_CANVAS) |
|
275 else if (is3DCanvas(renderer())) { |
|
276 HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer()->node()); |
|
277 WebGLRenderingContext* context = static_cast<WebGLRenderingContext*>(canvas->renderingContext()); |
|
278 if (context->graphicsContext3D()->platformLayer()) |
|
279 m_graphicsLayer->setContentsToWebGL(context->graphicsContext3D()->platformLayer()); |
|
280 } |
|
281 #endif |
|
282 |
|
283 if (renderer()->isRenderIFrame()) |
|
284 layerConfigChanged = RenderLayerCompositor::parentIFrameContentLayers(toRenderIFrame(renderer())); |
|
285 |
|
286 return layerConfigChanged; |
|
287 } |
|
288 |
|
289 static IntRect clipBox(RenderBox* renderer) |
|
290 { |
|
291 IntRect result = ClipRects::infiniteRect(); |
|
292 if (renderer->hasOverflowClip()) |
|
293 result = renderer->overflowClipRect(0, 0); |
|
294 |
|
295 if (renderer->hasClip()) |
|
296 result.intersect(renderer->clipRect(0, 0)); |
|
297 |
|
298 return result; |
|
299 } |
|
300 |
|
301 void RenderLayerBacking::updateGraphicsLayerGeometry() |
|
302 { |
|
303 // If we haven't built z-order lists yet, wait until later. |
|
304 if (m_owningLayer->isStackingContext() && m_owningLayer->m_zOrderListsDirty) |
|
305 return; |
|
306 |
|
307 // Set transform property, if it is not animating. We have to do this here because the transform |
|
308 // is affected by the layer dimensions. |
|
309 if (!renderer()->animation()->isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyWebkitTransform)) |
|
310 updateLayerTransform(renderer()->style()); |
|
311 |
|
312 // Set opacity, if it is not animating. |
|
313 if (!renderer()->animation()->isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyOpacity)) |
|
314 updateLayerOpacity(renderer()->style()); |
|
315 |
|
316 RenderStyle* style = renderer()->style(); |
|
317 m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D && !renderer()->hasReflection()); |
|
318 m_graphicsLayer->setBackfaceVisibility(style->backfaceVisibility() == BackfaceVisibilityVisible); |
|
319 |
|
320 RenderLayer* compAncestor = m_owningLayer->ancestorCompositingLayer(); |
|
321 |
|
322 // We compute everything relative to the enclosing compositing layer. |
|
323 IntRect ancestorCompositingBounds; |
|
324 if (compAncestor) { |
|
325 ASSERT(compAncestor->backing()); |
|
326 ancestorCompositingBounds = compAncestor->backing()->compositedBounds(); |
|
327 } |
|
328 |
|
329 IntRect localCompositingBounds = compositedBounds(); |
|
330 |
|
331 IntRect relativeCompositingBounds(localCompositingBounds); |
|
332 int deltaX = 0, deltaY = 0; |
|
333 m_owningLayer->convertToLayerCoords(compAncestor, deltaX, deltaY); |
|
334 relativeCompositingBounds.move(deltaX, deltaY); |
|
335 |
|
336 IntPoint graphicsLayerParentLocation; |
|
337 if (compAncestor && compAncestor->backing()->hasClippingLayer()) { |
|
338 // If the compositing ancestor has a layer to clip children, we parent in that, and therefore |
|
339 // position relative to it. |
|
340 IntRect clippingBox = clipBox(toRenderBox(compAncestor->renderer())); |
|
341 graphicsLayerParentLocation = clippingBox.location(); |
|
342 } else |
|
343 graphicsLayerParentLocation = ancestorCompositingBounds.location(); |
|
344 |
|
345 if (compAncestor && m_ancestorClippingLayer) { |
|
346 // Call calculateRects to get the backgroundRect which is what is used to clip the contents of this |
|
347 // layer. Note that we call it with temporaryClipRects = true because normally when computing clip rects |
|
348 // for a compositing layer, rootLayer is the layer itself. |
|
349 IntRect parentClipRect = m_owningLayer->backgroundClipRect(compAncestor, true); |
|
350 m_ancestorClippingLayer->setPosition(FloatPoint() + (parentClipRect.location() - graphicsLayerParentLocation)); |
|
351 m_ancestorClippingLayer->setSize(parentClipRect.size()); |
|
352 |
|
353 // backgroundRect is relative to compAncestor, so subtract deltaX/deltaY to get back to local coords. |
|
354 IntSize rendererOffset(parentClipRect.location().x() - deltaX, parentClipRect.location().y() - deltaY); |
|
355 m_ancestorClippingLayer->setOffsetFromRenderer(rendererOffset); |
|
356 |
|
357 // The primary layer is then parented in, and positioned relative to this clipping layer. |
|
358 graphicsLayerParentLocation = parentClipRect.location(); |
|
359 } |
|
360 |
|
361 m_graphicsLayer->setPosition(FloatPoint() + (relativeCompositingBounds.location() - graphicsLayerParentLocation)); |
|
362 |
|
363 IntSize oldOffsetFromRenderer = m_graphicsLayer->offsetFromRenderer(); |
|
364 m_graphicsLayer->setOffsetFromRenderer(localCompositingBounds.location() - IntPoint()); |
|
365 // If the compositing layer offset changes, we need to repaint. |
|
366 if (oldOffsetFromRenderer != m_graphicsLayer->offsetFromRenderer()) |
|
367 m_graphicsLayer->setNeedsDisplay(); |
|
368 |
|
369 FloatSize oldSize = m_graphicsLayer->size(); |
|
370 FloatSize newSize = relativeCompositingBounds.size(); |
|
371 if (oldSize != newSize) { |
|
372 m_graphicsLayer->setSize(newSize); |
|
373 // A bounds change will almost always require redisplay. Usually that redisplay |
|
374 // will happen because of a repaint elsewhere, but not always: |
|
375 // e.g. see RenderView::setMaximalOutlineSize() |
|
376 m_graphicsLayer->setNeedsDisplay(); |
|
377 } |
|
378 |
|
379 // If we have a layer that clips children, position it. |
|
380 IntRect clippingBox; |
|
381 if (m_clippingLayer) { |
|
382 clippingBox = clipBox(toRenderBox(renderer())); |
|
383 m_clippingLayer->setPosition(FloatPoint() + (clippingBox.location() - localCompositingBounds.location())); |
|
384 m_clippingLayer->setSize(clippingBox.size()); |
|
385 m_clippingLayer->setOffsetFromRenderer(clippingBox.location() - IntPoint()); |
|
386 } |
|
387 |
|
388 if (m_maskLayer) { |
|
389 m_maskLayer->setSize(m_graphicsLayer->size()); |
|
390 m_maskLayer->setPosition(FloatPoint()); |
|
391 } |
|
392 |
|
393 if (m_owningLayer->hasTransform()) { |
|
394 const IntRect borderBox = toRenderBox(renderer())->borderBoxRect(); |
|
395 |
|
396 // Get layout bounds in the coords of compAncestor to match relativeCompositingBounds. |
|
397 IntRect layerBounds = IntRect(deltaX, deltaY, borderBox.width(), borderBox.height()); |
|
398 |
|
399 // Update properties that depend on layer dimensions |
|
400 FloatPoint3D transformOrigin = computeTransformOrigin(borderBox); |
|
401 // Compute the anchor point, which is in the center of the renderer box unless transform-origin is set. |
|
402 FloatPoint3D anchor(relativeCompositingBounds.width() != 0.0f ? ((layerBounds.x() - relativeCompositingBounds.x()) + transformOrigin.x()) / relativeCompositingBounds.width() : 0.5f, |
|
403 relativeCompositingBounds.height() != 0.0f ? ((layerBounds.y() - relativeCompositingBounds.y()) + transformOrigin.y()) / relativeCompositingBounds.height() : 0.5f, |
|
404 transformOrigin.z()); |
|
405 m_graphicsLayer->setAnchorPoint(anchor); |
|
406 |
|
407 RenderStyle* style = renderer()->style(); |
|
408 if (style->hasPerspective()) { |
|
409 TransformationMatrix t = owningLayer()->perspectiveTransform(); |
|
410 |
|
411 if (m_clippingLayer) { |
|
412 m_clippingLayer->setChildrenTransform(t); |
|
413 m_graphicsLayer->setChildrenTransform(TransformationMatrix()); |
|
414 } |
|
415 else |
|
416 m_graphicsLayer->setChildrenTransform(t); |
|
417 } else { |
|
418 if (m_clippingLayer) |
|
419 m_clippingLayer->setChildrenTransform(TransformationMatrix()); |
|
420 else |
|
421 m_graphicsLayer->setChildrenTransform(TransformationMatrix()); |
|
422 } |
|
423 } else { |
|
424 m_graphicsLayer->setAnchorPoint(FloatPoint3D(0.5f, 0.5f, 0)); |
|
425 } |
|
426 |
|
427 if (m_foregroundLayer) { |
|
428 FloatPoint foregroundPosition; |
|
429 FloatSize foregroundSize = newSize; |
|
430 IntSize foregroundOffset = m_graphicsLayer->offsetFromRenderer(); |
|
431 // If we have a clipping layer (which clips descendants), then the foreground layer is a child of it, |
|
432 // so that it gets correctly sorted with children. In that case, position relative to the clipping layer. |
|
433 if (m_clippingLayer) { |
|
434 foregroundPosition = FloatPoint() + (localCompositingBounds.location() - clippingBox.location()); |
|
435 foregroundSize = FloatSize(clippingBox.size()); |
|
436 foregroundOffset = clippingBox.location() - IntPoint(); |
|
437 } |
|
438 |
|
439 m_foregroundLayer->setPosition(foregroundPosition); |
|
440 m_foregroundLayer->setSize(foregroundSize); |
|
441 m_foregroundLayer->setOffsetFromRenderer(foregroundOffset); |
|
442 } |
|
443 |
|
444 if (m_owningLayer->reflectionLayer() && m_owningLayer->reflectionLayer()->isComposited()) { |
|
445 RenderLayerBacking* reflectionBacking = m_owningLayer->reflectionLayer()->backing(); |
|
446 reflectionBacking->updateGraphicsLayerGeometry(); |
|
447 |
|
448 // The reflection layer has the bounds of m_owningLayer->reflectionLayer(), |
|
449 // but the reflected layer is the bounds of this layer, so we need to position it appropriately. |
|
450 FloatRect layerBounds = compositedBounds(); |
|
451 FloatRect reflectionLayerBounds = reflectionBacking->compositedBounds(); |
|
452 reflectionBacking->graphicsLayer()->setReplicatedLayerPosition(FloatPoint() + (layerBounds.location() - reflectionLayerBounds.location())); |
|
453 } |
|
454 |
|
455 m_graphicsLayer->setContentsRect(contentsBox()); |
|
456 updateDrawsContent(); |
|
457 updateAfterWidgetResize(); |
|
458 } |
|
459 |
|
460 void RenderLayerBacking::updateInternalHierarchy() |
|
461 { |
|
462 // m_foregroundLayer has to be inserted in the correct order with child layers, |
|
463 // so it's not inserted here. |
|
464 if (m_ancestorClippingLayer) { |
|
465 m_ancestorClippingLayer->removeAllChildren(); |
|
466 m_graphicsLayer->removeFromParent(); |
|
467 m_ancestorClippingLayer->addChild(m_graphicsLayer.get()); |
|
468 } |
|
469 |
|
470 if (m_clippingLayer) { |
|
471 m_clippingLayer->removeFromParent(); |
|
472 m_graphicsLayer->addChild(m_clippingLayer.get()); |
|
473 } |
|
474 } |
|
475 |
|
476 void RenderLayerBacking::updateDrawsContent() |
|
477 { |
|
478 m_graphicsLayer->setDrawsContent(containsPaintedContent()); |
|
479 } |
|
480 |
|
481 // Return true if the layers changed. |
|
482 bool RenderLayerBacking::updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip) |
|
483 { |
|
484 bool layersChanged = false; |
|
485 |
|
486 if (needsAncestorClip) { |
|
487 if (!m_ancestorClippingLayer) { |
|
488 m_ancestorClippingLayer = GraphicsLayer::create(this); |
|
489 #ifndef NDEBUG |
|
490 m_ancestorClippingLayer->setName("Ancestor clipping Layer"); |
|
491 #endif |
|
492 m_ancestorClippingLayer->setMasksToBounds(true); |
|
493 layersChanged = true; |
|
494 } |
|
495 } else if (m_ancestorClippingLayer) { |
|
496 m_ancestorClippingLayer->removeFromParent(); |
|
497 m_ancestorClippingLayer = 0; |
|
498 layersChanged = true; |
|
499 } |
|
500 |
|
501 if (needsDescendantClip) { |
|
502 if (!m_clippingLayer) { |
|
503 m_clippingLayer = GraphicsLayer::create(this); |
|
504 #ifndef NDEBUG |
|
505 m_clippingLayer->setName("Child clipping Layer"); |
|
506 #endif |
|
507 m_clippingLayer->setMasksToBounds(true); |
|
508 layersChanged = true; |
|
509 } |
|
510 } else if (m_clippingLayer) { |
|
511 m_clippingLayer->removeFromParent(); |
|
512 m_clippingLayer = 0; |
|
513 layersChanged = true; |
|
514 } |
|
515 |
|
516 if (layersChanged) |
|
517 updateInternalHierarchy(); |
|
518 |
|
519 return layersChanged; |
|
520 } |
|
521 |
|
522 bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer) |
|
523 { |
|
524 bool layerChanged = false; |
|
525 if (needsForegroundLayer) { |
|
526 if (!m_foregroundLayer) { |
|
527 m_foregroundLayer = GraphicsLayer::create(this); |
|
528 #ifndef NDEBUG |
|
529 m_foregroundLayer->setName(nameForLayer() + " (foreground)"); |
|
530 #endif |
|
531 m_foregroundLayer->setDrawsContent(true); |
|
532 m_foregroundLayer->setPaintingPhase(GraphicsLayerPaintForeground); |
|
533 layerChanged = true; |
|
534 } |
|
535 } else if (m_foregroundLayer) { |
|
536 m_foregroundLayer->removeFromParent(); |
|
537 m_foregroundLayer = 0; |
|
538 layerChanged = true; |
|
539 } |
|
540 |
|
541 if (layerChanged) |
|
542 m_graphicsLayer->setPaintingPhase(paintingPhaseForPrimaryLayer()); |
|
543 |
|
544 return layerChanged; |
|
545 } |
|
546 |
|
547 bool RenderLayerBacking::updateMaskLayer(bool needsMaskLayer) |
|
548 { |
|
549 bool layerChanged = false; |
|
550 if (needsMaskLayer) { |
|
551 if (!m_maskLayer) { |
|
552 m_maskLayer = GraphicsLayer::create(this); |
|
553 #ifndef NDEBUG |
|
554 m_maskLayer->setName("Mask"); |
|
555 #endif |
|
556 m_maskLayer->setDrawsContent(true); |
|
557 m_maskLayer->setPaintingPhase(GraphicsLayerPaintMask); |
|
558 layerChanged = true; |
|
559 } |
|
560 } else if (m_maskLayer) { |
|
561 m_maskLayer = 0; |
|
562 layerChanged = true; |
|
563 } |
|
564 |
|
565 if (layerChanged) |
|
566 m_graphicsLayer->setPaintingPhase(paintingPhaseForPrimaryLayer()); |
|
567 |
|
568 return layerChanged; |
|
569 } |
|
570 |
|
571 GraphicsLayerPaintingPhase RenderLayerBacking::paintingPhaseForPrimaryLayer() const |
|
572 { |
|
573 unsigned phase = GraphicsLayerPaintBackground; |
|
574 if (!m_foregroundLayer) |
|
575 phase |= GraphicsLayerPaintForeground; |
|
576 if (!m_maskLayer) |
|
577 phase |= GraphicsLayerPaintMask; |
|
578 |
|
579 return static_cast<GraphicsLayerPaintingPhase>(phase); |
|
580 } |
|
581 |
|
582 float RenderLayerBacking::compositingOpacity(float rendererOpacity) const |
|
583 { |
|
584 float finalOpacity = rendererOpacity; |
|
585 |
|
586 for (RenderLayer* curr = m_owningLayer->parent(); curr; curr = curr->parent()) { |
|
587 // We only care about parents that are stacking contexts. |
|
588 // Recall that opacity creates stacking context. |
|
589 if (!curr->isStackingContext()) |
|
590 continue; |
|
591 |
|
592 // If we found a compositing layer, we want to compute opacity |
|
593 // relative to it. So we can break here. |
|
594 if (curr->isComposited()) |
|
595 break; |
|
596 |
|
597 finalOpacity *= curr->renderer()->opacity(); |
|
598 } |
|
599 |
|
600 return finalOpacity; |
|
601 } |
|
602 |
|
603 static bool hasBorderOutlineOrShadow(const RenderStyle* style) |
|
604 { |
|
605 return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow(); |
|
606 } |
|
607 |
|
608 static bool hasBoxDecorationsOrBackground(const RenderObject* renderer) |
|
609 { |
|
610 return hasBorderOutlineOrShadow(renderer->style()) || renderer->hasBackground(); |
|
611 } |
|
612 |
|
613 static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle* style) |
|
614 { |
|
615 return hasBorderOutlineOrShadow(style) || style->hasBackgroundImage(); |
|
616 } |
|
617 |
|
618 bool RenderLayerBacking::rendererHasBackground() const |
|
619 { |
|
620 // FIXME: share more code here |
|
621 if (renderer()->node() && renderer()->node()->isDocumentNode()) { |
|
622 RenderObject* htmlObject = renderer()->firstChild(); |
|
623 if (!htmlObject) |
|
624 return false; |
|
625 |
|
626 if (htmlObject->hasBackground()) |
|
627 return true; |
|
628 |
|
629 RenderObject* bodyObject = htmlObject->firstChild(); |
|
630 if (!bodyObject) |
|
631 return false; |
|
632 |
|
633 return bodyObject->hasBackground(); |
|
634 } |
|
635 |
|
636 return renderer()->hasBackground(); |
|
637 } |
|
638 |
|
639 const Color RenderLayerBacking::rendererBackgroundColor() const |
|
640 { |
|
641 // FIXME: share more code here |
|
642 if (renderer()->node() && renderer()->node()->isDocumentNode()) { |
|
643 RenderObject* htmlObject = renderer()->firstChild(); |
|
644 if (htmlObject->hasBackground()) |
|
645 return htmlObject->style()->visitedDependentColor(CSSPropertyBackgroundColor); |
|
646 |
|
647 RenderObject* bodyObject = htmlObject->firstChild(); |
|
648 return bodyObject->style()->visitedDependentColor(CSSPropertyBackgroundColor); |
|
649 } |
|
650 |
|
651 return renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor); |
|
652 } |
|
653 |
|
654 // A "simple container layer" is a RenderLayer which has no visible content to render. |
|
655 // It may have no children, or all its children may be themselves composited. |
|
656 // This is a useful optimization, because it allows us to avoid allocating backing store. |
|
657 bool RenderLayerBacking::isSimpleContainerCompositingLayer() const |
|
658 { |
|
659 RenderObject* renderObject = renderer(); |
|
660 if (renderObject->isReplaced() || // replaced objects are not containers |
|
661 renderObject->hasMask()) // masks require special treatment |
|
662 return false; |
|
663 |
|
664 RenderStyle* style = renderObject->style(); |
|
665 |
|
666 // Reject anything that has a border, a border-radius or outline, |
|
667 // or any background (color or image). |
|
668 // FIXME: we could optimize layers for simple backgrounds. |
|
669 if (hasBoxDecorationsOrBackground(renderObject)) |
|
670 return false; |
|
671 |
|
672 // If we have got this far and the renderer has no children, then we're ok. |
|
673 if (!renderObject->firstChild()) |
|
674 return true; |
|
675 |
|
676 if (renderObject->node() && renderObject->node()->isDocumentNode()) { |
|
677 // Look to see if the root object has a non-simple backgound |
|
678 RenderObject* rootObject = renderObject->document()->documentElement()->renderer(); |
|
679 if (!rootObject) |
|
680 return false; |
|
681 |
|
682 style = rootObject->style(); |
|
683 |
|
684 // Reject anything that has a border, a border-radius or outline, |
|
685 // or is not a simple background (no background, or solid color). |
|
686 if (hasBoxDecorationsOrBackgroundImage(style)) |
|
687 return false; |
|
688 |
|
689 // Now look at the body's renderer. |
|
690 HTMLElement* body = renderObject->document()->body(); |
|
691 RenderObject* bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0; |
|
692 if (!bodyObject) |
|
693 return false; |
|
694 |
|
695 style = bodyObject->style(); |
|
696 |
|
697 if (hasBoxDecorationsOrBackgroundImage(style)) |
|
698 return false; |
|
699 |
|
700 // Ceck to see if all the body's children are compositing layers. |
|
701 if (hasNonCompositingContent()) |
|
702 return false; |
|
703 |
|
704 return true; |
|
705 } |
|
706 |
|
707 // Check to see if all the renderer's children are compositing layers. |
|
708 if (hasNonCompositingContent()) |
|
709 return false; |
|
710 |
|
711 return true; |
|
712 } |
|
713 |
|
714 // Conservative test for having no rendered children. |
|
715 bool RenderLayerBacking::hasNonCompositingContent() const |
|
716 { |
|
717 if (m_owningLayer->hasOverflowControls()) |
|
718 return true; |
|
719 |
|
720 // Some HTML can cause whitespace text nodes to have renderers, like: |
|
721 // <div> |
|
722 // <img src=...> |
|
723 // </div> |
|
724 // so test for 0x0 RenderTexts here |
|
725 for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) { |
|
726 if (!child->hasLayer()) { |
|
727 if (child->isRenderInline() || !child->isBox()) |
|
728 return true; |
|
729 |
|
730 if (toRenderBox(child)->width() > 0 || toRenderBox(child)->height() > 0) |
|
731 return true; |
|
732 } |
|
733 } |
|
734 |
|
735 if (m_owningLayer->isStackingContext()) { |
|
736 // Use the m_hasCompositingDescendant bit to optimize? |
|
737 if (Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList()) { |
|
738 size_t listSize = negZOrderList->size(); |
|
739 for (size_t i = 0; i < listSize; ++i) { |
|
740 RenderLayer* curLayer = negZOrderList->at(i); |
|
741 if (!curLayer->isComposited()) |
|
742 return true; |
|
743 } |
|
744 } |
|
745 |
|
746 if (Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList()) { |
|
747 size_t listSize = posZOrderList->size(); |
|
748 for (size_t i = 0; i < listSize; ++i) { |
|
749 RenderLayer* curLayer = posZOrderList->at(i); |
|
750 if (!curLayer->isComposited()) |
|
751 return true; |
|
752 } |
|
753 } |
|
754 } |
|
755 |
|
756 if (Vector<RenderLayer*>* normalFlowList = m_owningLayer->normalFlowList()) { |
|
757 size_t listSize = normalFlowList->size(); |
|
758 for (size_t i = 0; i < listSize; ++i) { |
|
759 RenderLayer* curLayer = normalFlowList->at(i); |
|
760 if (!curLayer->isComposited()) |
|
761 return true; |
|
762 } |
|
763 } |
|
764 |
|
765 return false; |
|
766 } |
|
767 |
|
768 bool RenderLayerBacking::containsPaintedContent() const |
|
769 { |
|
770 if (isSimpleContainerCompositingLayer() || paintingGoesToWindow() || m_artificiallyInflatedBounds || m_owningLayer->isReflection()) |
|
771 return false; |
|
772 |
|
773 if (isDirectlyCompositedImage()) |
|
774 return false; |
|
775 |
|
776 // FIXME: we could optimize cases where the image, video or canvas is known to fill the border box entirely, |
|
777 // and set background color on the layer in that case, instead of allocating backing store and painting. |
|
778 if (renderer()->isVideo() || is3DCanvas(renderer())) |
|
779 return hasBoxDecorationsOrBackground(renderer()); |
|
780 |
|
781 return true; |
|
782 } |
|
783 |
|
784 // An image can be directly compositing if it's the sole content of the layer, and has no box decorations |
|
785 // that require painting. Direct compositing saves backing store. |
|
786 bool RenderLayerBacking::isDirectlyCompositedImage() const |
|
787 { |
|
788 RenderObject* renderObject = renderer(); |
|
789 return renderObject->isImage() && !hasBoxDecorationsOrBackground(renderObject) && !renderObject->hasClip(); |
|
790 } |
|
791 |
|
792 void RenderLayerBacking::rendererContentChanged() |
|
793 { |
|
794 if (isDirectlyCompositedImage()) { |
|
795 updateImageContents(); |
|
796 return; |
|
797 } |
|
798 |
|
799 #if ENABLE(3D_CANVAS) |
|
800 if (is3DCanvas(renderer())) { |
|
801 m_graphicsLayer->setContentsNeedsDisplay(); |
|
802 return; |
|
803 } |
|
804 #endif |
|
805 } |
|
806 |
|
807 void RenderLayerBacking::updateImageContents() |
|
808 { |
|
809 ASSERT(renderer()->isImage()); |
|
810 RenderImage* imageRenderer = toRenderImage(renderer()); |
|
811 |
|
812 CachedImage* cachedImage = imageRenderer->cachedImage(); |
|
813 if (!cachedImage) |
|
814 return; |
|
815 |
|
816 Image* image = cachedImage->image(); |
|
817 if (!image) |
|
818 return; |
|
819 |
|
820 // We have to wait until the image is fully loaded before setting it on the layer. |
|
821 if (!cachedImage->isLoaded()) |
|
822 return; |
|
823 |
|
824 // This is a no-op if the layer doesn't have an inner layer for the image. |
|
825 m_graphicsLayer->setContentsToImage(image); |
|
826 |
|
827 // Image animation is "lazy", in that it automatically stops unless someone is drawing |
|
828 // the image. So we have to kick the animation each time; this has the downside that the |
|
829 // image will keep animating, even if its layer is not visible. |
|
830 image->startAnimation(); |
|
831 } |
|
832 |
|
833 FloatPoint3D RenderLayerBacking::computeTransformOrigin(const IntRect& borderBox) const |
|
834 { |
|
835 RenderStyle* style = renderer()->style(); |
|
836 |
|
837 FloatPoint3D origin; |
|
838 origin.setX(style->transformOriginX().calcFloatValue(borderBox.width())); |
|
839 origin.setY(style->transformOriginY().calcFloatValue(borderBox.height())); |
|
840 origin.setZ(style->transformOriginZ()); |
|
841 |
|
842 return origin; |
|
843 } |
|
844 |
|
845 FloatPoint RenderLayerBacking::computePerspectiveOrigin(const IntRect& borderBox) const |
|
846 { |
|
847 RenderStyle* style = renderer()->style(); |
|
848 |
|
849 float boxWidth = borderBox.width(); |
|
850 float boxHeight = borderBox.height(); |
|
851 |
|
852 FloatPoint origin; |
|
853 origin.setX(style->perspectiveOriginX().calcFloatValue(boxWidth)); |
|
854 origin.setY(style->perspectiveOriginY().calcFloatValue(boxHeight)); |
|
855 |
|
856 return origin; |
|
857 } |
|
858 |
|
859 // Return the offset from the top-left of this compositing layer at which the renderer's contents are painted. |
|
860 IntSize RenderLayerBacking::contentOffsetInCompostingLayer() const |
|
861 { |
|
862 return IntSize(-m_compositedBounds.x(), -m_compositedBounds.y()); |
|
863 } |
|
864 |
|
865 IntRect RenderLayerBacking::contentsBox() const |
|
866 { |
|
867 if (!renderer()->isBox()) |
|
868 return IntRect(); |
|
869 |
|
870 IntRect contentsRect; |
|
871 #if ENABLE(VIDEO) |
|
872 if (renderer()->isVideo()) { |
|
873 RenderVideo* videoRenderer = toRenderVideo(renderer()); |
|
874 contentsRect = videoRenderer->videoBox(); |
|
875 } else |
|
876 #endif |
|
877 contentsRect = toRenderBox(renderer())->contentBoxRect(); |
|
878 |
|
879 IntSize contentOffset = contentOffsetInCompostingLayer(); |
|
880 contentsRect.move(contentOffset); |
|
881 return contentsRect; |
|
882 } |
|
883 |
|
884 // Map the given point from coordinates in the GraphicsLayer to RenderLayer coordinates. |
|
885 FloatPoint RenderLayerBacking::graphicsLayerToContentsCoordinates(const GraphicsLayer* graphicsLayer, const FloatPoint& point) |
|
886 { |
|
887 return point + FloatSize(graphicsLayer->offsetFromRenderer()); |
|
888 } |
|
889 |
|
890 // Map the given point from coordinates in the RenderLayer to GraphicsLayer coordinates. |
|
891 FloatPoint RenderLayerBacking::contentsToGraphicsLayerCoordinates(const GraphicsLayer* graphicsLayer, const FloatPoint& point) |
|
892 { |
|
893 return point - FloatSize(graphicsLayer->offsetFromRenderer()); |
|
894 } |
|
895 |
|
896 bool RenderLayerBacking::paintingGoesToWindow() const |
|
897 { |
|
898 if (m_owningLayer->isRootLayer()) |
|
899 return compositor()->rootLayerAttachment() == RenderLayerCompositor::RootLayerAttachedViaChromeClient; |
|
900 |
|
901 return false; |
|
902 } |
|
903 |
|
904 void RenderLayerBacking::setContentsNeedDisplay() |
|
905 { |
|
906 if (m_graphicsLayer && m_graphicsLayer->drawsContent()) |
|
907 m_graphicsLayer->setNeedsDisplay(); |
|
908 |
|
909 if (m_foregroundLayer && m_foregroundLayer->drawsContent()) |
|
910 m_foregroundLayer->setNeedsDisplay(); |
|
911 |
|
912 if (m_maskLayer && m_maskLayer->drawsContent()) |
|
913 m_maskLayer->setNeedsDisplay(); |
|
914 } |
|
915 |
|
916 // r is in the coordinate space of the layer's render object |
|
917 void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r) |
|
918 { |
|
919 if (m_graphicsLayer && m_graphicsLayer->drawsContent()) { |
|
920 FloatPoint dirtyOrigin = contentsToGraphicsLayerCoordinates(m_graphicsLayer.get(), FloatPoint(r.x(), r.y())); |
|
921 FloatRect dirtyRect(dirtyOrigin, r.size()); |
|
922 FloatRect bounds(FloatPoint(), m_graphicsLayer->size()); |
|
923 if (bounds.intersects(dirtyRect)) |
|
924 m_graphicsLayer->setNeedsDisplayInRect(dirtyRect); |
|
925 } |
|
926 |
|
927 if (m_foregroundLayer && m_foregroundLayer->drawsContent()) { |
|
928 // FIXME: do incremental repaint |
|
929 m_foregroundLayer->setNeedsDisplay(); |
|
930 } |
|
931 |
|
932 if (m_maskLayer && m_maskLayer->drawsContent()) { |
|
933 // FIXME: do incremental repaint |
|
934 m_maskLayer->setNeedsDisplay(); |
|
935 } |
|
936 } |
|
937 |
|
938 static void setClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect) |
|
939 { |
|
940 if (paintDirtyRect == clipRect) |
|
941 return; |
|
942 p->save(); |
|
943 p->clip(clipRect); |
|
944 } |
|
945 |
|
946 static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect) |
|
947 { |
|
948 if (paintDirtyRect == clipRect) |
|
949 return; |
|
950 p->restore(); |
|
951 } |
|
952 |
|
953 // Share this with RenderLayer::paintLayer, which would have to be educated about GraphicsLayerPaintingPhase? |
|
954 void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* context, |
|
955 const IntRect& paintDirtyRect, // in the coords of rootLayer |
|
956 PaintBehavior paintBehavior, GraphicsLayerPaintingPhase paintingPhase, |
|
957 RenderObject* paintingRoot) |
|
958 { |
|
959 if (paintingGoesToWindow()) { |
|
960 ASSERT_NOT_REACHED(); |
|
961 return; |
|
962 } |
|
963 |
|
964 m_owningLayer->updateLayerListsIfNeeded(); |
|
965 |
|
966 // Calculate the clip rects we should use. |
|
967 IntRect layerBounds, damageRect, clipRectToApply, outlineRect; |
|
968 m_owningLayer->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect); |
|
969 |
|
970 int x = layerBounds.x(); // layerBounds is computed relative to rootLayer |
|
971 int y = layerBounds.y(); |
|
972 int tx = x - m_owningLayer->renderBoxX(); |
|
973 int ty = y - m_owningLayer->renderBoxY(); |
|
974 |
|
975 // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which |
|
976 // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set). |
|
977 // Else, our renderer tree may or may not contain the painting root, so we pass that root along |
|
978 // so it will be tested against as we decend through the renderers. |
|
979 RenderObject *paintingRootForRenderer = 0; |
|
980 if (paintingRoot && !renderer()->isDescendantOf(paintingRoot)) |
|
981 paintingRootForRenderer = paintingRoot; |
|
982 |
|
983 bool shouldPaint = (m_owningLayer->hasVisibleContent() || m_owningLayer->hasVisibleDescendant()) && m_owningLayer->isSelfPaintingLayer(); |
|
984 |
|
985 if (shouldPaint && (paintingPhase & GraphicsLayerPaintBackground)) { |
|
986 // Paint our background first, before painting any child layers. |
|
987 // Establish the clip used to paint our background. |
|
988 setClip(context, paintDirtyRect, damageRect); |
|
989 |
|
990 PaintInfo info(context, damageRect, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0); |
|
991 renderer()->paint(info, tx, ty); |
|
992 |
|
993 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with |
|
994 // z-index. We paint after we painted the background/border, so that the scrollbars will |
|
995 // sit above the background/border. |
|
996 m_owningLayer->paintOverflowControls(context, x, y, damageRect); |
|
997 |
|
998 // Restore the clip. |
|
999 restoreClip(context, paintDirtyRect, damageRect); |
|
1000 |
|
1001 // Now walk the sorted list of children with negative z-indices. Only RenderLayers without compositing layers will paint. |
|
1002 m_owningLayer->paintList(m_owningLayer->negZOrderList(), rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, 0, 0); |
|
1003 } |
|
1004 |
|
1005 bool forceBlackText = paintBehavior & PaintBehaviorForceBlackText; |
|
1006 bool selectionOnly = paintBehavior & PaintBehaviorSelectionOnly; |
|
1007 |
|
1008 if (shouldPaint && (paintingPhase & GraphicsLayerPaintForeground)) { |
|
1009 // Set up the clip used when painting our children. |
|
1010 setClip(context, paintDirtyRect, clipRectToApply); |
|
1011 PaintInfo paintInfo(context, clipRectToApply, |
|
1012 selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds, |
|
1013 forceBlackText, paintingRootForRenderer, 0); |
|
1014 renderer()->paint(paintInfo, tx, ty); |
|
1015 |
|
1016 if (!selectionOnly) { |
|
1017 paintInfo.phase = PaintPhaseFloat; |
|
1018 renderer()->paint(paintInfo, tx, ty); |
|
1019 |
|
1020 paintInfo.phase = PaintPhaseForeground; |
|
1021 renderer()->paint(paintInfo, tx, ty); |
|
1022 |
|
1023 paintInfo.phase = PaintPhaseChildOutlines; |
|
1024 renderer()->paint(paintInfo, tx, ty); |
|
1025 } |
|
1026 |
|
1027 // Now restore our clip. |
|
1028 restoreClip(context, paintDirtyRect, clipRectToApply); |
|
1029 |
|
1030 if (!outlineRect.isEmpty()) { |
|
1031 // Paint our own outline |
|
1032 PaintInfo paintInfo(context, outlineRect, PaintPhaseSelfOutline, false, paintingRootForRenderer, 0); |
|
1033 setClip(context, paintDirtyRect, outlineRect); |
|
1034 renderer()->paint(paintInfo, tx, ty); |
|
1035 restoreClip(context, paintDirtyRect, outlineRect); |
|
1036 } |
|
1037 |
|
1038 // Paint any child layers that have overflow. |
|
1039 m_owningLayer->paintList(m_owningLayer->normalFlowList(), rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, 0, 0); |
|
1040 |
|
1041 // Now walk the sorted list of children with positive z-indices. |
|
1042 m_owningLayer->paintList(m_owningLayer->posZOrderList(), rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, 0, 0); |
|
1043 } |
|
1044 |
|
1045 if (shouldPaint && (paintingPhase & GraphicsLayerPaintMask)) { |
|
1046 if (renderer()->hasMask() && !selectionOnly && !damageRect.isEmpty()) { |
|
1047 setClip(context, paintDirtyRect, damageRect); |
|
1048 |
|
1049 // Paint the mask. |
|
1050 PaintInfo paintInfo(context, damageRect, PaintPhaseMask, false, paintingRootForRenderer, 0); |
|
1051 renderer()->paint(paintInfo, tx, ty); |
|
1052 |
|
1053 // Restore the clip. |
|
1054 restoreClip(context, paintDirtyRect, damageRect); |
|
1055 } |
|
1056 } |
|
1057 |
|
1058 ASSERT(!m_owningLayer->m_usedTransparency); |
|
1059 } |
|
1060 |
|
1061 #if ENABLE(INSPECTOR) |
|
1062 static InspectorTimelineAgent* inspectorTimelineAgent(RenderObject* renderer) |
|
1063 { |
|
1064 Frame* frame = renderer->frame(); |
|
1065 if (!frame) |
|
1066 return 0; |
|
1067 Page* page = frame->page(); |
|
1068 if (!page) |
|
1069 return 0; |
|
1070 return page->inspectorTimelineAgent(); |
|
1071 } |
|
1072 #endif |
|
1073 |
|
1074 // Up-call from compositing layer drawing callback. |
|
1075 void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const IntRect& clip) |
|
1076 { |
|
1077 #if ENABLE(INSPECTOR) |
|
1078 if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent(m_owningLayer->renderer())) |
|
1079 timelineAgent->willPaint(clip); |
|
1080 #endif |
|
1081 |
|
1082 // We have to use the same root as for hit testing, because both methods |
|
1083 // can compute and cache clipRects. |
|
1084 IntRect enclosingBBox = compositedBounds(); |
|
1085 |
|
1086 IntRect clipRect(clip); |
|
1087 |
|
1088 // Set up the coordinate space to be in the layer's rendering coordinates. |
|
1089 context.translate(-enclosingBBox.x(), -enclosingBBox.y()); |
|
1090 |
|
1091 // Offset the clip. |
|
1092 clipRect.move(enclosingBBox.x(), enclosingBBox.y()); |
|
1093 |
|
1094 // The dirtyRect is in the coords of the painting root. |
|
1095 IntRect dirtyRect = enclosingBBox; |
|
1096 dirtyRect.intersect(clipRect); |
|
1097 |
|
1098 paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase, renderer()); |
|
1099 |
|
1100 #if ENABLE(INSPECTOR) |
|
1101 if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent(m_owningLayer->renderer())) |
|
1102 timelineAgent->didPaint(); |
|
1103 #endif |
|
1104 } |
|
1105 |
|
1106 bool RenderLayerBacking::showDebugBorders() const |
|
1107 { |
|
1108 return compositor() ? compositor()->showDebugBorders() : false; |
|
1109 } |
|
1110 |
|
1111 bool RenderLayerBacking::showRepaintCounter() const |
|
1112 { |
|
1113 return compositor() ? compositor()->showRepaintCounter() : false; |
|
1114 } |
|
1115 |
|
1116 bool RenderLayerBacking::startAnimation(double timeOffset, const Animation* anim, const KeyframeList& keyframes) |
|
1117 { |
|
1118 bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity); |
|
1119 bool hasTransform = keyframes.containsProperty(CSSPropertyWebkitTransform); |
|
1120 |
|
1121 if (!hasOpacity && !hasTransform) |
|
1122 return false; |
|
1123 |
|
1124 KeyframeValueList transformVector(AnimatedPropertyWebkitTransform); |
|
1125 KeyframeValueList opacityVector(AnimatedPropertyOpacity); |
|
1126 |
|
1127 for (Vector<KeyframeValue>::const_iterator it = keyframes.beginKeyframes(); it != keyframes.endKeyframes(); ++it) { |
|
1128 const RenderStyle* keyframeStyle = it->style(); |
|
1129 float key = it->key(); |
|
1130 |
|
1131 if (!keyframeStyle) |
|
1132 continue; |
|
1133 |
|
1134 // get timing function |
|
1135 const TimingFunction* tf = keyframeStyle->hasAnimations() ? &((*keyframeStyle->animations()).animation(0)->timingFunction()) : 0; |
|
1136 |
|
1137 if (hasTransform) |
|
1138 transformVector.insert(new TransformAnimationValue(key, &(keyframeStyle->transform()), tf)); |
|
1139 |
|
1140 if (hasOpacity) |
|
1141 opacityVector.insert(new FloatAnimationValue(key, keyframeStyle->opacity(), tf)); |
|
1142 } |
|
1143 |
|
1144 bool didAnimateTransform = !hasTransform; |
|
1145 bool didAnimateOpacity = !hasOpacity; |
|
1146 |
|
1147 if (hasTransform && m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), anim, keyframes.animationName(), timeOffset)) |
|
1148 didAnimateTransform = true; |
|
1149 |
|
1150 if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), timeOffset)) |
|
1151 didAnimateOpacity = true; |
|
1152 |
|
1153 bool runningAcceleratedAnimation = didAnimateTransform && didAnimateOpacity; |
|
1154 if (runningAcceleratedAnimation) |
|
1155 compositor()->didStartAcceleratedAnimation(); |
|
1156 |
|
1157 return runningAcceleratedAnimation; |
|
1158 } |
|
1159 |
|
1160 bool RenderLayerBacking::startTransition(double timeOffset, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle) |
|
1161 { |
|
1162 bool didAnimate = false; |
|
1163 ASSERT(property != cAnimateAll); |
|
1164 |
|
1165 if (property == (int)CSSPropertyOpacity) { |
|
1166 const Animation* opacityAnim = toStyle->transitionForProperty(CSSPropertyOpacity); |
|
1167 if (opacityAnim && !opacityAnim->isEmptyOrZeroDuration()) { |
|
1168 KeyframeValueList opacityVector(AnimatedPropertyOpacity); |
|
1169 opacityVector.insert(new FloatAnimationValue(0, compositingOpacity(fromStyle->opacity()))); |
|
1170 opacityVector.insert(new FloatAnimationValue(1, compositingOpacity(toStyle->opacity()))); |
|
1171 // The boxSize param is only used for transform animations (which can only run on RenderBoxes), so we pass an empty size here. |
|
1172 if (m_graphicsLayer->addAnimation(opacityVector, IntSize(), opacityAnim, String(), timeOffset)) { |
|
1173 // To ensure that the correct opacity is visible when the animation ends, also set the final opacity. |
|
1174 updateLayerOpacity(toStyle); |
|
1175 didAnimate = true; |
|
1176 } |
|
1177 } |
|
1178 } |
|
1179 |
|
1180 if (property == (int)CSSPropertyWebkitTransform && m_owningLayer->hasTransform()) { |
|
1181 const Animation* transformAnim = toStyle->transitionForProperty(CSSPropertyWebkitTransform); |
|
1182 if (transformAnim && !transformAnim->isEmptyOrZeroDuration()) { |
|
1183 KeyframeValueList transformVector(AnimatedPropertyWebkitTransform); |
|
1184 transformVector.insert(new TransformAnimationValue(0, &fromStyle->transform())); |
|
1185 transformVector.insert(new TransformAnimationValue(1, &toStyle->transform())); |
|
1186 if (m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), transformAnim, String(), timeOffset)) { |
|
1187 // To ensure that the correct transform is visible when the animation ends, also set the final opacity. |
|
1188 updateLayerTransform(toStyle); |
|
1189 didAnimate = true; |
|
1190 } |
|
1191 } |
|
1192 } |
|
1193 |
|
1194 if (didAnimate) |
|
1195 compositor()->didStartAcceleratedAnimation(); |
|
1196 |
|
1197 return didAnimate; |
|
1198 } |
|
1199 |
|
1200 void RenderLayerBacking::notifyAnimationStarted(const GraphicsLayer*, double time) |
|
1201 { |
|
1202 renderer()->animation()->notifyAnimationStarted(renderer(), time); |
|
1203 } |
|
1204 |
|
1205 void RenderLayerBacking::notifySyncRequired(const GraphicsLayer*) |
|
1206 { |
|
1207 if (!renderer()->documentBeingDestroyed()) |
|
1208 compositor()->scheduleSync(); |
|
1209 } |
|
1210 |
|
1211 void RenderLayerBacking::animationFinished(const String& animationName) |
|
1212 { |
|
1213 m_graphicsLayer->removeAnimationsForKeyframes(animationName); |
|
1214 } |
|
1215 |
|
1216 void RenderLayerBacking::animationPaused(double timeOffset, const String& animationName) |
|
1217 { |
|
1218 m_graphicsLayer->pauseAnimation(animationName, timeOffset); |
|
1219 } |
|
1220 |
|
1221 void RenderLayerBacking::transitionFinished(int property) |
|
1222 { |
|
1223 AnimatedPropertyID animatedProperty = cssToGraphicsLayerProperty(property); |
|
1224 if (animatedProperty != AnimatedPropertyInvalid) |
|
1225 m_graphicsLayer->removeAnimationsForProperty(animatedProperty); |
|
1226 } |
|
1227 |
|
1228 void RenderLayerBacking::suspendAnimations(double time) |
|
1229 { |
|
1230 m_graphicsLayer->suspendAnimations(time); |
|
1231 } |
|
1232 |
|
1233 void RenderLayerBacking::resumeAnimations() |
|
1234 { |
|
1235 m_graphicsLayer->resumeAnimations(); |
|
1236 } |
|
1237 |
|
1238 IntRect RenderLayerBacking::compositedBounds() const |
|
1239 { |
|
1240 return m_compositedBounds; |
|
1241 } |
|
1242 |
|
1243 void RenderLayerBacking::setCompositedBounds(const IntRect& bounds) |
|
1244 { |
|
1245 m_compositedBounds = bounds; |
|
1246 |
|
1247 } |
|
1248 int RenderLayerBacking::graphicsLayerToCSSProperty(AnimatedPropertyID property) |
|
1249 { |
|
1250 int cssProperty = CSSPropertyInvalid; |
|
1251 switch (property) { |
|
1252 case AnimatedPropertyWebkitTransform: |
|
1253 cssProperty = CSSPropertyWebkitTransform; |
|
1254 break; |
|
1255 case AnimatedPropertyOpacity: |
|
1256 cssProperty = CSSPropertyOpacity; |
|
1257 break; |
|
1258 case AnimatedPropertyBackgroundColor: |
|
1259 cssProperty = CSSPropertyBackgroundColor; |
|
1260 break; |
|
1261 case AnimatedPropertyInvalid: |
|
1262 ASSERT_NOT_REACHED(); |
|
1263 } |
|
1264 return cssProperty; |
|
1265 } |
|
1266 |
|
1267 AnimatedPropertyID RenderLayerBacking::cssToGraphicsLayerProperty(int cssProperty) |
|
1268 { |
|
1269 switch (cssProperty) { |
|
1270 case CSSPropertyWebkitTransform: |
|
1271 return AnimatedPropertyWebkitTransform; |
|
1272 case CSSPropertyOpacity: |
|
1273 return AnimatedPropertyOpacity; |
|
1274 case CSSPropertyBackgroundColor: |
|
1275 return AnimatedPropertyBackgroundColor; |
|
1276 // It's fine if we see other css properties here; they are just not accelerated. |
|
1277 } |
|
1278 return AnimatedPropertyInvalid; |
|
1279 } |
|
1280 |
|
1281 #ifndef NDEBUG |
|
1282 String RenderLayerBacking::nameForLayer() const |
|
1283 { |
|
1284 String name = renderer()->renderName(); |
|
1285 if (Node* node = renderer()->node()) { |
|
1286 if (node->isElementNode()) |
|
1287 name += " " + static_cast<Element*>(node)->tagName(); |
|
1288 if (node->hasID()) |
|
1289 name += " \'" + static_cast<Element*>(node)->getIdAttribute() + "\'"; |
|
1290 } |
|
1291 |
|
1292 if (m_owningLayer->isReflection()) |
|
1293 name += " (reflection)"; |
|
1294 |
|
1295 return name; |
|
1296 } |
|
1297 #endif |
|
1298 |
|
1299 CompositingLayerType RenderLayerBacking::compositingLayerType() const |
|
1300 { |
|
1301 if (m_graphicsLayer->hasContentsLayer()) |
|
1302 return MediaCompositingLayer; |
|
1303 |
|
1304 if (m_graphicsLayer->drawsContent()) |
|
1305 return m_graphicsLayer->usingTiledLayer() ? TiledCompositingLayer : NormalCompositingLayer; |
|
1306 |
|
1307 return ContainerCompositingLayer; |
|
1308 } |
|
1309 |
|
1310 } // namespace WebCore |
|
1311 |
|
1312 #endif // USE(ACCELERATED_COMPOSITING) |