|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "ContainerLayerComposite.h" |
|
7 #include <algorithm> // for min |
|
8 #include "FrameMetrics.h" // for FrameMetrics |
|
9 #include "Units.h" // for LayerRect, LayerPixel, etc |
|
10 #include "gfx2DGlue.h" // for ToMatrix4x4 |
|
11 #include "gfx3DMatrix.h" // for gfx3DMatrix |
|
12 #include "gfxPrefs.h" // for gfxPrefs |
|
13 #include "gfxUtils.h" // for gfxUtils, etc |
|
14 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc |
|
15 #include "mozilla/RefPtr.h" // for RefPtr |
|
16 #include "mozilla/gfx/BaseRect.h" // for BaseRect |
|
17 #include "mozilla/gfx/Matrix.h" // for Matrix4x4 |
|
18 #include "mozilla/gfx/Point.h" // for Point, IntPoint |
|
19 #include "mozilla/gfx/Rect.h" // for IntRect, Rect |
|
20 #include "mozilla/layers/Compositor.h" // for Compositor, etc |
|
21 #include "mozilla/layers/CompositorTypes.h" // for DIAGNOSTIC_CONTAINER |
|
22 #include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc |
|
23 #include "mozilla/layers/TextureHost.h" // for CompositingRenderTarget |
|
24 #include "mozilla/mozalloc.h" // for operator delete, etc |
|
25 #include "nsAutoPtr.h" // for nsRefPtr |
|
26 #include "nsDebug.h" // for NS_ASSERTION |
|
27 #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc |
|
28 #include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE |
|
29 #include "nsPoint.h" // for nsIntPoint |
|
30 #include "nsRect.h" // for nsIntRect |
|
31 #include "nsRegion.h" // for nsIntRegion |
|
32 #include "nsTArray.h" // for nsAutoTArray |
|
33 #include "TextRenderer.h" // for TextRenderer |
|
34 #include <vector> |
|
35 |
|
36 namespace mozilla { |
|
37 namespace layers { |
|
38 |
|
39 /** |
|
40 * Returns a rectangle of content painted opaquely by aLayer. Very consertative; |
|
41 * bails by returning an empty rect in any tricky situations. |
|
42 */ |
|
43 static nsIntRect |
|
44 GetOpaqueRect(Layer* aLayer) |
|
45 { |
|
46 nsIntRect result; |
|
47 gfx::Matrix matrix; |
|
48 bool is2D = aLayer->GetBaseTransform().Is2D(&matrix); |
|
49 |
|
50 // Just bail if there's anything difficult to handle. |
|
51 if (!is2D || aLayer->GetMaskLayer() || |
|
52 aLayer->GetEffectiveOpacity() != 1.0f || |
|
53 matrix.HasNonIntegerTranslation()) { |
|
54 return result; |
|
55 } |
|
56 |
|
57 if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) { |
|
58 result = aLayer->GetEffectiveVisibleRegion().GetLargestRectangle(); |
|
59 } else { |
|
60 // Drill down into RefLayers because that's what we particularly care about; |
|
61 // layer construction for aLayer will not have known about the opaqueness |
|
62 // of any RefLayer subtrees. |
|
63 RefLayer* refLayer = aLayer->AsRefLayer(); |
|
64 if (refLayer && refLayer->GetFirstChild()) { |
|
65 result = GetOpaqueRect(refLayer->GetFirstChild()); |
|
66 } |
|
67 } |
|
68 |
|
69 // Translate our opaque region to cover the child |
|
70 gfx::Point point = matrix.GetTranslation(); |
|
71 result.MoveBy(static_cast<int>(point.x), static_cast<int>(point.y)); |
|
72 |
|
73 const nsIntRect* clipRect = aLayer->GetEffectiveClipRect(); |
|
74 if (clipRect) { |
|
75 result.IntersectRect(result, *clipRect); |
|
76 } |
|
77 |
|
78 return result; |
|
79 } |
|
80 |
|
81 struct LayerVelocityUserData : public LayerUserData { |
|
82 public: |
|
83 LayerVelocityUserData() { |
|
84 MOZ_COUNT_CTOR(LayerVelocityUserData); |
|
85 } |
|
86 ~LayerVelocityUserData() { |
|
87 MOZ_COUNT_DTOR(LayerVelocityUserData); |
|
88 } |
|
89 |
|
90 struct VelocityData { |
|
91 VelocityData(TimeStamp frameTime, int scrollX, int scrollY) |
|
92 : mFrameTime(frameTime) |
|
93 , mPoint(scrollX, scrollY) |
|
94 {} |
|
95 |
|
96 TimeStamp mFrameTime; |
|
97 gfx::Point mPoint; |
|
98 }; |
|
99 std::vector<VelocityData> mData; |
|
100 }; |
|
101 |
|
102 static gfx::Point GetScrollData(Layer* aLayer) { |
|
103 gfx::Matrix matrix; |
|
104 if (aLayer->GetLocalTransform().Is2D(&matrix)) { |
|
105 return matrix.GetTranslation(); |
|
106 } |
|
107 |
|
108 gfx::Point origin; |
|
109 return origin; |
|
110 } |
|
111 |
|
112 static void DrawLayerInfo(const nsIntRect& aClipRect, |
|
113 LayerManagerComposite* aManager, |
|
114 Layer* aLayer) |
|
115 { |
|
116 |
|
117 if (aLayer->GetType() == Layer::LayerType::TYPE_CONTAINER) { |
|
118 // XXX - should figure out a way to render this, but for now this |
|
119 // is hard to do, since it will often get superimposed over the first |
|
120 // child of the layer, which is bad. |
|
121 return; |
|
122 } |
|
123 |
|
124 nsAutoCString layerInfo; |
|
125 aLayer->PrintInfo(layerInfo, ""); |
|
126 |
|
127 nsIntRegion visibleRegion = aLayer->GetVisibleRegion(); |
|
128 |
|
129 uint32_t maxWidth = std::min<uint32_t>(visibleRegion.GetBounds().width, 500); |
|
130 |
|
131 nsIntPoint topLeft = visibleRegion.GetBounds().TopLeft(); |
|
132 aManager->GetTextRenderer()->RenderText(layerInfo.get(), gfx::IntPoint(topLeft.x, topLeft.y), |
|
133 aLayer->GetEffectiveTransform(), 16, |
|
134 maxWidth); |
|
135 |
|
136 } |
|
137 |
|
138 static LayerVelocityUserData* GetVelocityData(Layer* aLayer) { |
|
139 static char sLayerVelocityUserDataKey; |
|
140 void* key = reinterpret_cast<void*>(&sLayerVelocityUserDataKey); |
|
141 if (!aLayer->HasUserData(key)) { |
|
142 LayerVelocityUserData* newData = new LayerVelocityUserData(); |
|
143 aLayer->SetUserData(key, newData); |
|
144 } |
|
145 |
|
146 return static_cast<LayerVelocityUserData*>(aLayer->GetUserData(key)); |
|
147 } |
|
148 |
|
149 static void DrawVelGraph(const nsIntRect& aClipRect, |
|
150 LayerManagerComposite* aManager, |
|
151 Layer* aLayer) { |
|
152 Compositor* compositor = aManager->GetCompositor(); |
|
153 gfx::Rect clipRect(aClipRect.x, aClipRect.y, |
|
154 aClipRect.width, aClipRect.height); |
|
155 |
|
156 TimeStamp now = TimeStamp::Now(); |
|
157 LayerVelocityUserData* velocityData = GetVelocityData(aLayer); |
|
158 |
|
159 if (velocityData->mData.size() >= 1 && |
|
160 now > velocityData->mData[velocityData->mData.size() - 1].mFrameTime + |
|
161 TimeDuration::FromMilliseconds(200)) { |
|
162 // clear stale data |
|
163 velocityData->mData.clear(); |
|
164 } |
|
165 |
|
166 const gfx::Point layerTransform = GetScrollData(aLayer); |
|
167 velocityData->mData.push_back( |
|
168 LayerVelocityUserData::VelocityData(now, |
|
169 static_cast<int>(layerTransform.x), static_cast<int>(layerTransform.y))); |
|
170 |
|
171 // TODO: dump to file |
|
172 // XXX: Uncomment these lines to enable ScrollGraph logging. This is |
|
173 // useful for HVGA phones or to output the data to accurate |
|
174 // graphing software. |
|
175 // printf_stderr("ScrollGraph (%p): %f, %f\n", |
|
176 // aLayer, layerTransform.x, layerTransform.y); |
|
177 |
|
178 // Keep a circular buffer of 100. |
|
179 size_t circularBufferSize = 100; |
|
180 if (velocityData->mData.size() > circularBufferSize) { |
|
181 velocityData->mData.erase(velocityData->mData.begin()); |
|
182 } |
|
183 |
|
184 if (velocityData->mData.size() == 1) { |
|
185 return; |
|
186 } |
|
187 |
|
188 // Clear and disable the graph when it's flat |
|
189 for (size_t i = 1; i < velocityData->mData.size(); i++) { |
|
190 if (velocityData->mData[i - 1].mPoint != velocityData->mData[i].mPoint) { |
|
191 break; |
|
192 } |
|
193 if (i == velocityData->mData.size() - 1) { |
|
194 velocityData->mData.clear(); |
|
195 return; |
|
196 } |
|
197 } |
|
198 |
|
199 if (aLayer->GetEffectiveVisibleRegion().GetBounds().width < 300 || |
|
200 aLayer->GetEffectiveVisibleRegion().GetBounds().height < 300) { |
|
201 // Don't want a graph for smaller layers |
|
202 return; |
|
203 } |
|
204 |
|
205 aManager->SetDebugOverlayWantsNextFrame(true); |
|
206 |
|
207 const gfx::Matrix4x4& transform = aLayer->GetEffectiveTransform(); |
|
208 nsIntRect bounds = aLayer->GetEffectiveVisibleRegion().GetBounds(); |
|
209 gfx::Rect graphBounds = gfx::Rect(bounds.x, bounds.y, |
|
210 bounds.width, bounds.height); |
|
211 gfx::Rect graphRect = gfx::Rect(bounds.x, bounds.y, 200, 100); |
|
212 |
|
213 float opacity = 1.0; |
|
214 EffectChain effects; |
|
215 effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(0.2f,0,0,1)); |
|
216 compositor->DrawQuad(graphRect, |
|
217 clipRect, |
|
218 effects, |
|
219 opacity, |
|
220 transform); |
|
221 |
|
222 std::vector<gfx::Point> graph; |
|
223 int yScaleFactor = 3; |
|
224 for (int32_t i = (int32_t)velocityData->mData.size() - 2; i >= 0; i--) { |
|
225 const gfx::Point& p1 = velocityData->mData[i+1].mPoint; |
|
226 const gfx::Point& p2 = velocityData->mData[i].mPoint; |
|
227 int vel = sqrt((p1.x - p2.x) * (p1.x - p2.x) + |
|
228 (p1.y - p2.y) * (p1.y - p2.y)); |
|
229 graph.push_back( |
|
230 gfx::Point(bounds.x + graphRect.width / circularBufferSize * i, |
|
231 graphBounds.y + graphRect.height - vel/yScaleFactor)); |
|
232 } |
|
233 |
|
234 compositor->DrawLines(graph, clipRect, gfx::Color(0,1,0,1), |
|
235 opacity, transform); |
|
236 } |
|
237 |
|
238 // ContainerRender is shared between RefLayer and ContainerLayer |
|
239 template<class ContainerT> void |
|
240 ContainerRender(ContainerT* aContainer, |
|
241 LayerManagerComposite* aManager, |
|
242 const nsIntRect& aClipRect) |
|
243 { |
|
244 /** |
|
245 * Setup our temporary surface for rendering the contents of this container. |
|
246 */ |
|
247 RefPtr<CompositingRenderTarget> surface; |
|
248 |
|
249 Compositor* compositor = aManager->GetCompositor(); |
|
250 |
|
251 RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget(); |
|
252 |
|
253 nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds(); |
|
254 |
|
255 aContainer->mSupportsComponentAlphaChildren = false; |
|
256 |
|
257 float opacity = aContainer->GetEffectiveOpacity(); |
|
258 |
|
259 bool needsSurface = aContainer->UseIntermediateSurface(); |
|
260 if (needsSurface) { |
|
261 SurfaceInitMode mode = INIT_MODE_CLEAR; |
|
262 bool surfaceCopyNeeded = false; |
|
263 gfx::IntRect surfaceRect = gfx::IntRect(visibleRect.x, visibleRect.y, |
|
264 visibleRect.width, visibleRect.height); |
|
265 gfx::IntPoint sourcePoint = gfx::IntPoint(visibleRect.x, visibleRect.y); |
|
266 // we're about to create a framebuffer backed by textures to use as an intermediate |
|
267 // surface. What to do if its size (as given by framebufferRect) would exceed the |
|
268 // maximum texture size supported by the GL? The present code chooses the compromise |
|
269 // of just clamping the framebuffer's size to the max supported size. |
|
270 // This gives us a lower resolution rendering of the intermediate surface (children layers). |
|
271 // See bug 827170 for a discussion. |
|
272 int32_t maxTextureSize = compositor->GetMaxTextureSize(); |
|
273 surfaceRect.width = std::min(maxTextureSize, surfaceRect.width); |
|
274 surfaceRect.height = std::min(maxTextureSize, surfaceRect.height); |
|
275 if (aContainer->GetEffectiveVisibleRegion().GetNumRects() == 1 && |
|
276 (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE)) |
|
277 { |
|
278 // don't need a background, we're going to paint all opaque stuff |
|
279 aContainer->mSupportsComponentAlphaChildren = true; |
|
280 mode = INIT_MODE_NONE; |
|
281 } else { |
|
282 const gfx::Matrix4x4& transform3D = aContainer->GetEffectiveTransform(); |
|
283 gfx::Matrix transform; |
|
284 // If we have an opaque ancestor layer, then we can be sure that |
|
285 // all the pixels we draw into are either opaque already or will be |
|
286 // covered by something opaque. Otherwise copying up the background is |
|
287 // not safe. |
|
288 if (ContainerLayer::HasOpaqueAncestorLayer(aContainer) && |
|
289 transform3D.Is2D(&transform) && !ThebesMatrix(transform).HasNonIntegerTranslation()) { |
|
290 surfaceCopyNeeded = gfxPrefs::ComponentAlphaEnabled(); |
|
291 sourcePoint.x += transform._31; |
|
292 sourcePoint.y += transform._32; |
|
293 aContainer->mSupportsComponentAlphaChildren |
|
294 = gfxPrefs::ComponentAlphaEnabled(); |
|
295 } |
|
296 } |
|
297 |
|
298 sourcePoint -= compositor->GetCurrentRenderTarget()->GetOrigin(); |
|
299 if (surfaceCopyNeeded) { |
|
300 surface = compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget, sourcePoint); |
|
301 } else { |
|
302 surface = compositor->CreateRenderTarget(surfaceRect, mode); |
|
303 } |
|
304 |
|
305 if (!surface) { |
|
306 return; |
|
307 } |
|
308 |
|
309 compositor->SetRenderTarget(surface); |
|
310 } else { |
|
311 surface = previousTarget; |
|
312 aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) || |
|
313 (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren()); |
|
314 } |
|
315 |
|
316 nsAutoTArray<Layer*, 12> children; |
|
317 aContainer->SortChildrenBy3DZOrder(children); |
|
318 |
|
319 /** |
|
320 * Render this container's contents. |
|
321 */ |
|
322 for (uint32_t i = 0; i < children.Length(); i++) { |
|
323 LayerComposite* layerToRender = static_cast<LayerComposite*>(children.ElementAt(i)->ImplData()); |
|
324 |
|
325 if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty() && |
|
326 !layerToRender->GetLayer()->AsContainerLayer()) { |
|
327 continue; |
|
328 } |
|
329 |
|
330 nsIntRect clipRect = layerToRender->GetLayer()-> |
|
331 CalculateScissorRect(aClipRect, &aManager->GetWorldTransform()); |
|
332 if (clipRect.IsEmpty()) { |
|
333 continue; |
|
334 } |
|
335 |
|
336 nsIntRegion savedVisibleRegion; |
|
337 bool restoreVisibleRegion = false; |
|
338 if (i + 1 < children.Length() && |
|
339 layerToRender->GetLayer()->GetEffectiveTransform().IsIdentity()) { |
|
340 LayerComposite* nextLayer = static_cast<LayerComposite*>(children.ElementAt(i + 1)->ImplData()); |
|
341 nsIntRect nextLayerOpaqueRect; |
|
342 if (nextLayer && nextLayer->GetLayer()) { |
|
343 nextLayerOpaqueRect = GetOpaqueRect(nextLayer->GetLayer()); |
|
344 } |
|
345 if (!nextLayerOpaqueRect.IsEmpty()) { |
|
346 savedVisibleRegion = layerToRender->GetShadowVisibleRegion(); |
|
347 nsIntRegion visibleRegion; |
|
348 visibleRegion.Sub(savedVisibleRegion, nextLayerOpaqueRect); |
|
349 if (visibleRegion.IsEmpty()) { |
|
350 continue; |
|
351 } |
|
352 layerToRender->SetShadowVisibleRegion(visibleRegion); |
|
353 restoreVisibleRegion = true; |
|
354 } |
|
355 } |
|
356 |
|
357 if (layerToRender->HasLayerBeenComposited()) { |
|
358 // Composer2D will compose this layer so skip GPU composition |
|
359 // this time & reset composition flag for next composition phase |
|
360 layerToRender->SetLayerComposited(false); |
|
361 nsIntRect clearRect = layerToRender->GetClearRect(); |
|
362 if (!clearRect.IsEmpty()) { |
|
363 // Clear layer's visible rect on FrameBuffer with transparent pixels |
|
364 gfx::Rect fbRect(clearRect.x, clearRect.y, clearRect.width, clearRect.height); |
|
365 compositor->ClearRect(fbRect); |
|
366 layerToRender->SetClearRect(nsIntRect(0, 0, 0, 0)); |
|
367 } |
|
368 } else { |
|
369 layerToRender->RenderLayer(clipRect); |
|
370 } |
|
371 |
|
372 if (restoreVisibleRegion) { |
|
373 // Restore the region in case it's not covered by opaque content next time |
|
374 layerToRender->SetShadowVisibleRegion(savedVisibleRegion); |
|
375 } |
|
376 |
|
377 if (gfxPrefs::LayersScrollGraph()) { |
|
378 DrawVelGraph(clipRect, aManager, layerToRender->GetLayer()); |
|
379 } |
|
380 |
|
381 if (gfxPrefs::DrawLayerInfo()) { |
|
382 DrawLayerInfo(clipRect, aManager, layerToRender->GetLayer()); |
|
383 } |
|
384 // invariant: our GL context should be current here, I don't think we can |
|
385 // assert it though |
|
386 } |
|
387 |
|
388 if (needsSurface) { |
|
389 // Unbind the current surface and rebind the previous one. |
|
390 #ifdef MOZ_DUMP_PAINTING |
|
391 if (gfxUtils::sDumpPainting) { |
|
392 RefPtr<gfx::DataSourceSurface> surf = surface->Dump(aManager->GetCompositor()); |
|
393 WriteSnapshotToDumpFile(aContainer, surf); |
|
394 } |
|
395 #endif |
|
396 |
|
397 compositor->SetRenderTarget(previousTarget); |
|
398 EffectChain effectChain(aContainer); |
|
399 LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(aContainer->GetMaskLayer(), |
|
400 effectChain, |
|
401 !aContainer->GetTransform().CanDraw2D()); |
|
402 |
|
403 effectChain.mPrimaryEffect = new EffectRenderTarget(surface); |
|
404 |
|
405 gfx::Rect rect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height); |
|
406 gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); |
|
407 aManager->GetCompositor()->DrawQuad(rect, clipRect, effectChain, opacity, |
|
408 aContainer->GetEffectiveTransform()); |
|
409 } |
|
410 |
|
411 if (aContainer->GetFrameMetrics().IsScrollable()) { |
|
412 const FrameMetrics& frame = aContainer->GetFrameMetrics(); |
|
413 LayerRect layerBounds = ParentLayerRect(frame.mCompositionBounds) * ParentLayerToLayerScale(1.0); |
|
414 gfx::Rect rect(layerBounds.x, layerBounds.y, layerBounds.width, layerBounds.height); |
|
415 gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); |
|
416 aManager->GetCompositor()->DrawDiagnostics(DIAGNOSTIC_CONTAINER, |
|
417 rect, clipRect, |
|
418 aContainer->GetEffectiveTransform()); |
|
419 } |
|
420 } |
|
421 |
|
422 ContainerLayerComposite::ContainerLayerComposite(LayerManagerComposite *aManager) |
|
423 : ContainerLayer(aManager, nullptr) |
|
424 , LayerComposite(aManager) |
|
425 { |
|
426 MOZ_COUNT_CTOR(ContainerLayerComposite); |
|
427 mImplData = static_cast<LayerComposite*>(this); |
|
428 } |
|
429 |
|
430 ContainerLayerComposite::~ContainerLayerComposite() |
|
431 { |
|
432 MOZ_COUNT_DTOR(ContainerLayerComposite); |
|
433 |
|
434 // We don't Destroy() on destruction here because this destructor |
|
435 // can be called after remote content has crashed, and it may not be |
|
436 // safe to free the IPC resources of our children. Those resources |
|
437 // are automatically cleaned up by IPDL-generated code. |
|
438 // |
|
439 // In the common case of normal shutdown, either |
|
440 // LayerManagerComposite::Destroy(), a parent |
|
441 // *ContainerLayerComposite::Destroy(), or Disconnect() will trigger |
|
442 // cleanup of our resources. |
|
443 while (mFirstChild) { |
|
444 RemoveChild(mFirstChild); |
|
445 } |
|
446 } |
|
447 |
|
448 void |
|
449 ContainerLayerComposite::Destroy() |
|
450 { |
|
451 if (!mDestroyed) { |
|
452 while (mFirstChild) { |
|
453 static_cast<LayerComposite*>(GetFirstChild()->ImplData())->Destroy(); |
|
454 RemoveChild(mFirstChild); |
|
455 } |
|
456 mDestroyed = true; |
|
457 } |
|
458 } |
|
459 |
|
460 LayerComposite* |
|
461 ContainerLayerComposite::GetFirstChildComposite() |
|
462 { |
|
463 if (!mFirstChild) { |
|
464 return nullptr; |
|
465 } |
|
466 return static_cast<LayerComposite*>(mFirstChild->ImplData()); |
|
467 } |
|
468 |
|
469 void |
|
470 ContainerLayerComposite::RenderLayer(const nsIntRect& aClipRect) |
|
471 { |
|
472 ContainerRender(this, mCompositeManager, aClipRect); |
|
473 } |
|
474 |
|
475 void |
|
476 ContainerLayerComposite::CleanupResources() |
|
477 { |
|
478 for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) { |
|
479 LayerComposite* layerToCleanup = static_cast<LayerComposite*>(l->ImplData()); |
|
480 layerToCleanup->CleanupResources(); |
|
481 } |
|
482 } |
|
483 |
|
484 RefLayerComposite::RefLayerComposite(LayerManagerComposite* aManager) |
|
485 : RefLayer(aManager, nullptr) |
|
486 , LayerComposite(aManager) |
|
487 { |
|
488 mImplData = static_cast<LayerComposite*>(this); |
|
489 } |
|
490 |
|
491 RefLayerComposite::~RefLayerComposite() |
|
492 { |
|
493 Destroy(); |
|
494 } |
|
495 |
|
496 void |
|
497 RefLayerComposite::Destroy() |
|
498 { |
|
499 MOZ_ASSERT(!mFirstChild); |
|
500 mDestroyed = true; |
|
501 } |
|
502 |
|
503 LayerComposite* |
|
504 RefLayerComposite::GetFirstChildComposite() |
|
505 { |
|
506 if (!mFirstChild) { |
|
507 return nullptr; |
|
508 } |
|
509 return static_cast<LayerComposite*>(mFirstChild->ImplData()); |
|
510 } |
|
511 |
|
512 void |
|
513 RefLayerComposite::RenderLayer(const nsIntRect& aClipRect) |
|
514 { |
|
515 ContainerRender(this, mCompositeManager, aClipRect); |
|
516 } |
|
517 |
|
518 void |
|
519 RefLayerComposite::CleanupResources() |
|
520 { |
|
521 } |
|
522 |
|
523 } /* layers */ |
|
524 } /* mozilla */ |