CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / gfx / layers / Layers.cpp
blob5c1e30cecadeedbf8f6a69b104429cb7e1dfc261
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=8 et :
3 */
4 /* ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at:
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is Mozilla Code.
19 * The Initial Developer of the Original Code is
20 * The Mozilla Foundation
21 * Portions created by the Initial Developer are Copyright (C) 2010
22 * the Initial Developer. All Rights Reserved.
24 * Contributor(s):
25 * Chris Jones <jones.chris.g@gmail.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #ifdef MOZ_IPC
42 # include "mozilla/layers/ShadowLayers.h"
43 #endif // MOZ_IPC
45 #include "ImageLayers.h"
46 #include "Layers.h"
47 #include "gfxPlatform.h"
48 #include "ReadbackLayer.h"
50 using namespace mozilla::layers;
52 typedef FrameMetrics::ViewID ViewID;
53 const ViewID FrameMetrics::NULL_SCROLL_ID = 0;
54 const ViewID FrameMetrics::ROOT_SCROLL_ID = 1;
55 const ViewID FrameMetrics::START_SCROLL_ID = 2;
57 #ifdef MOZ_LAYERS_HAVE_LOG
58 FILE*
59 FILEOrDefault(FILE* aFile)
61 return aFile ? aFile : stderr;
63 #endif // MOZ_LAYERS_HAVE_LOG
65 namespace {
67 // XXX pretty general utilities, could centralize
69 nsACString&
70 AppendToString(nsACString& s, const void* p,
71 const char* pfx="", const char* sfx="")
73 s += pfx;
74 s += nsPrintfCString(64, "%p", p);
75 return s += sfx;
78 nsACString&
79 AppendToString(nsACString& s, const gfxPattern::GraphicsFilter& f,
80 const char* pfx="", const char* sfx="")
82 s += pfx;
83 switch (f) {
84 case gfxPattern::FILTER_FAST: s += "fast"; break;
85 case gfxPattern::FILTER_GOOD: s += "good"; break;
86 case gfxPattern::FILTER_BEST: s += "best"; break;
87 case gfxPattern::FILTER_NEAREST: s += "nearest"; break;
88 case gfxPattern::FILTER_BILINEAR: s += "bilinear"; break;
89 case gfxPattern::FILTER_GAUSSIAN: s += "gaussian"; break;
90 default:
91 NS_ERROR("unknown filter type");
92 s += "???";
94 return s += sfx;
97 nsACString&
98 AppendToString(nsACString& s, ViewID n,
99 const char* pfx="", const char* sfx="")
101 s += pfx;
102 s.AppendInt(n);
103 return s += sfx;
106 nsACString&
107 AppendToString(nsACString& s, const gfxRGBA& c,
108 const char* pfx="", const char* sfx="")
110 s += pfx;
111 s += nsPrintfCString(
112 128, "rgba(%d, %d, %d, %g)",
113 PRUint8(c.r*255.0), PRUint8(c.g*255.0), PRUint8(c.b*255.0), c.a);
114 return s += sfx;
117 nsACString&
118 AppendToString(nsACString& s, const gfx3DMatrix& m,
119 const char* pfx="", const char* sfx="")
121 s += pfx;
122 if (m.IsIdentity())
123 s += "[ I ]";
124 else {
125 gfxMatrix matrix;
126 if (m.Is2D(&matrix)) {
127 s += nsPrintfCString(
128 96, "[ %g %g; %g %g; %g %g; ]",
129 matrix.xx, matrix.yx, matrix.xy, matrix.yy, matrix.x0, matrix.y0);
130 } else {
131 s += nsPrintfCString(
132 256, "[ %g %g %g %g; %g %g %g %g; %g %g %g %g; %g %g %g %g; ]",
133 m._11, m._12, m._13, m._14,
134 m._21, m._22, m._23, m._24,
135 m._31, m._32, m._33, m._34,
136 m._41, m._42, m._43, m._44);
139 return s += sfx;
142 nsACString&
143 AppendToString(nsACString& s, const nsIntPoint& p,
144 const char* pfx="", const char* sfx="")
146 s += pfx;
147 s += nsPrintfCString(128, "(x=%d, y=%d)", p.x, p.y);
148 return s += sfx;
151 nsACString&
152 AppendToString(nsACString& s, const nsIntRect& r,
153 const char* pfx="", const char* sfx="")
155 s += pfx;
156 s += nsPrintfCString(
157 256, "(x=%d, y=%d, w=%d, h=%d)",
158 r.x, r.y, r.width, r.height);
159 return s += sfx;
162 nsACString&
163 AppendToString(nsACString& s, const nsIntRegion& r,
164 const char* pfx="", const char* sfx="")
166 s += pfx;
168 nsIntRegionRectIterator it(r);
169 s += "< ";
170 while (const nsIntRect* sr = it.Next())
171 AppendToString(s, *sr) += "; ";
172 s += ">";
174 return s += sfx;
177 nsACString&
178 AppendToString(nsACString& s, const nsIntSize& sz,
179 const char* pfx="", const char* sfx="")
181 s += pfx;
182 s += nsPrintfCString(128, "(w=%d, h=%d)", sz.width, sz.height);
183 return s += sfx;
186 nsACString&
187 AppendToString(nsACString& s, const FrameMetrics& m,
188 const char* pfx="", const char* sfx="")
190 s += pfx;
191 AppendToString(s, m.mViewport, "{ viewport=");
192 AppendToString(s, m.mViewportScrollOffset, " viewportScroll=");
193 AppendToString(s, m.mDisplayPort, " displayport=");
194 AppendToString(s, m.mScrollId, " scrollId=", " }");
195 return s += sfx;
198 } // namespace <anon>
200 namespace mozilla {
201 namespace layers {
203 //--------------------------------------------------
204 // LayerManager
205 already_AddRefed<gfxASurface>
206 LayerManager::CreateOptimalSurface(const gfxIntSize &aSize,
207 gfxASurface::gfxImageFormat aFormat)
209 return gfxPlatform::GetPlatform()->
210 CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFormat));
213 #ifdef DEBUG
214 void
215 LayerManager::Mutated(Layer* aLayer)
217 NS_ABORT_IF_FALSE(!aLayer->GetTileSourceRect() ||
218 (LAYERS_BASIC == GetBackendType() &&
219 Layer::TYPE_IMAGE == aLayer->GetType()),
220 "Tiling not supported for this manager/layer type");
222 #endif // DEBUG
224 //--------------------------------------------------
225 // Layer
227 PRBool
228 Layer::CanUseOpaqueSurface()
230 // If the visible content in the layer is opaque, there is no need
231 // for an alpha channel.
232 if (GetContentFlags() & CONTENT_OPAQUE)
233 return PR_TRUE;
234 // Also, if this layer is the bottommost layer in a container which
235 // doesn't need an alpha channel, we can use an opaque surface for this
236 // layer too. Any transparent areas must be covered by something else
237 // in the container.
238 ContainerLayer* parent = GetParent();
239 return parent && parent->GetFirstChild() == this &&
240 parent->CanUseOpaqueSurface();
243 #ifdef MOZ_IPC
244 // NB: eventually these methods will be defined unconditionally, and
245 // can be moved into Layers.h
246 const nsIntRect*
247 Layer::GetEffectiveClipRect()
249 if (ShadowLayer* shadow = AsShadowLayer()) {
250 return shadow->GetShadowClipRect();
252 return GetClipRect();
255 const nsIntRegion&
256 Layer::GetEffectiveVisibleRegion()
258 if (ShadowLayer* shadow = AsShadowLayer()) {
259 return shadow->GetShadowVisibleRegion();
261 return GetVisibleRegion();
264 #else
266 const nsIntRect* Layer::GetEffectiveClipRect() { return GetClipRect(); }
267 const nsIntRegion& Layer::GetEffectiveVisibleRegion() { return GetVisibleRegion(); }
269 #endif // MOZ_IPC
271 gfx3DMatrix
272 Layer::SnapTransform(const gfx3DMatrix& aTransform,
273 const gfxRect& aSnapRect,
274 gfxMatrix* aResidualTransform)
276 if (aResidualTransform) {
277 *aResidualTransform = gfxMatrix();
280 gfxMatrix matrix2D;
281 gfx3DMatrix result;
282 if (mManager->IsSnappingEffectiveTransforms() &&
283 aTransform.Is2D(&matrix2D) &&
284 matrix2D.HasNonIntegerTranslation() &&
285 !matrix2D.IsSingular() &&
286 !matrix2D.HasNonAxisAlignedTransform()) {
287 gfxMatrix snappedMatrix;
288 gfxPoint topLeft = matrix2D.Transform(aSnapRect.TopLeft());
289 topLeft.Round();
290 // first compute scale factors that scale aSnapRect to the snapped rect
291 if (aSnapRect.IsEmpty()) {
292 snappedMatrix.xx = matrix2D.xx;
293 snappedMatrix.yy = matrix2D.yy;
294 } else {
295 gfxPoint bottomRight = matrix2D.Transform(aSnapRect.BottomRight());
296 bottomRight.Round();
297 snappedMatrix.xx = (bottomRight.x - topLeft.x)/aSnapRect.Width();
298 snappedMatrix.yy = (bottomRight.y - topLeft.y)/aSnapRect.Height();
300 // compute translation factors that will move aSnapRect to the snapped rect
301 // given those scale factors
302 snappedMatrix.x0 = topLeft.x - aSnapRect.pos.x*snappedMatrix.xx;
303 snappedMatrix.y0 = topLeft.y - aSnapRect.pos.y*snappedMatrix.yy;
304 result = gfx3DMatrix::From2D(snappedMatrix);
305 if (aResidualTransform && !snappedMatrix.IsSingular()) {
306 // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
307 // (i.e., appying snappedMatrix after aResidualTransform gives the
308 // ideal transform.
309 gfxMatrix snappedMatrixInverse = snappedMatrix;
310 snappedMatrixInverse.Invert();
311 *aResidualTransform = matrix2D * snappedMatrixInverse;
313 } else {
314 result = aTransform;
316 return result;
319 const gfx3DMatrix&
320 Layer::GetLocalTransform()
322 #ifdef MOZ_IPC
323 if (ShadowLayer* shadow = AsShadowLayer())
324 return shadow->GetShadowTransform();
325 #endif
326 return mTransform;
329 float
330 Layer::GetEffectiveOpacity()
332 float opacity = GetOpacity();
333 for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
334 c = c->GetParent()) {
335 opacity *= c->GetOpacity();
337 return opacity;
340 PRBool
341 ContainerLayer::HasMultipleChildren()
343 PRUint32 count = 0;
344 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
345 const nsIntRect *clipRect = child->GetEffectiveClipRect();
346 if (clipRect && clipRect->IsEmpty())
347 continue;
348 if (child->GetVisibleRegion().IsEmpty())
349 continue;
350 ++count;
351 if (count > 1)
352 return PR_TRUE;
355 return PR_FALSE;
358 void
359 ContainerLayer::DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
361 gfxMatrix residual;
362 gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
363 mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), &residual);
365 PRBool useIntermediateSurface;
366 float opacity = GetEffectiveOpacity();
367 if (opacity != 1.0f && HasMultipleChildren()) {
368 useIntermediateSurface = PR_TRUE;
369 } else {
370 useIntermediateSurface = PR_FALSE;
371 gfxMatrix contTransform;
372 if (!mEffectiveTransform.Is2D(&contTransform) ||
373 !contTransform.PreservesAxisAlignedRectangles()) {
374 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
375 const nsIntRect *clipRect = child->GetEffectiveClipRect();
376 /* We can't (easily) forward our transform to children with a non-empty clip
377 * rect since it would need to be adjusted for the transform.
378 * TODO: This is easily solvable for translation/scaling transforms.
380 if (clipRect && !clipRect->IsEmpty() && !child->GetVisibleRegion().IsEmpty()) {
381 useIntermediateSurface = PR_TRUE;
382 break;
388 mUseIntermediateSurface = useIntermediateSurface;
389 if (useIntermediateSurface) {
390 ComputeEffectiveTransformsForChildren(gfx3DMatrix::From2D(residual));
391 } else {
392 ComputeEffectiveTransformsForChildren(idealTransform);
396 void
397 ContainerLayer::ComputeEffectiveTransformsForChildren(const gfx3DMatrix& aTransformToSurface)
399 for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
400 l->ComputeEffectiveTransforms(aTransformToSurface);
404 void
405 ContainerLayer::DidRemoveChild(Layer* aLayer)
407 ThebesLayer* tl = aLayer->AsThebesLayer();
408 if (tl && tl->UsedForReadback()) {
409 for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
410 if (l->GetType() == TYPE_READBACK) {
411 static_cast<ReadbackLayer*>(l)->NotifyThebesLayerRemoved(tl);
415 if (aLayer->GetType() == TYPE_READBACK) {
416 static_cast<ReadbackLayer*>(aLayer)->NotifyRemoved();
420 void
421 ContainerLayer::DidInsertChild(Layer* aLayer)
423 if (aLayer->GetType() == TYPE_READBACK) {
424 mMayHaveReadbackChild = PR_TRUE;
428 #ifdef MOZ_LAYERS_HAVE_LOG
430 static nsACString& PrintInfo(nsACString& aTo, ShadowLayer* aShadowLayer);
432 void
433 Layer::Dump(FILE* aFile, const char* aPrefix)
435 DumpSelf(aFile, aPrefix);
437 if (Layer* kid = GetFirstChild()) {
438 nsCAutoString pfx(aPrefix);
439 pfx += " ";
440 kid->Dump(aFile, pfx.get());
443 if (Layer* next = GetNextSibling())
444 next->Dump(aFile, aPrefix);
447 void
448 Layer::DumpSelf(FILE* aFile, const char* aPrefix)
450 nsCAutoString str;
451 PrintInfo(str, aPrefix);
452 fprintf(FILEOrDefault(aFile), "%s\n", str.get());
455 void
456 Layer::Log(const char* aPrefix)
458 if (!IsLogEnabled())
459 return;
461 LogSelf(aPrefix);
463 if (Layer* kid = GetFirstChild()) {
464 nsCAutoString pfx(aPrefix);
465 pfx += " ";
466 kid->Log(pfx.get());
469 if (Layer* next = GetNextSibling())
470 next->Log(aPrefix);
473 void
474 Layer::LogSelf(const char* aPrefix)
476 if (!IsLogEnabled())
477 return;
479 nsCAutoString str;
480 PrintInfo(str, aPrefix);
481 MOZ_LAYERS_LOG(("%s", str.get()));
484 nsACString&
485 Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
487 aTo += aPrefix;
488 aTo += nsPrintfCString(64, "%s%s (0x%p)", mManager->Name(), Name(), this);
490 ::PrintInfo(aTo, AsShadowLayer());
492 if (mUseClipRect) {
493 AppendToString(aTo, mClipRect, " [clip=", "]");
495 if (!mTransform.IsIdentity()) {
496 AppendToString(aTo, mTransform, " [transform=", "]");
498 if (!mVisibleRegion.IsEmpty()) {
499 AppendToString(aTo, mVisibleRegion, " [visible=", "]");
501 if (1.0 != mOpacity) {
502 aTo.AppendPrintf(" [opacity=%g]", mOpacity);
504 if (const nsIntRect* tileSourceRect = GetTileSourceRect()) {
505 AppendToString(aTo, *tileSourceRect, " [tileSrc=", "]");
507 if (GetContentFlags() & CONTENT_OPAQUE) {
508 aTo += " [opaqueContent]";
510 if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) {
511 aTo += " [componentAlpha]";
514 return aTo;
517 nsACString&
518 ThebesLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
520 Layer::PrintInfo(aTo, aPrefix);
521 if (!mValidRegion.IsEmpty()) {
522 AppendToString(aTo, mValidRegion, " [valid=", "]");
524 if (mXResolution != 1.0 || mYResolution != 1.0) {
525 aTo.AppendPrintf(" [xres=%g yres=%g]", mXResolution, mYResolution);
527 return aTo;
530 nsACString&
531 ContainerLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
533 Layer::PrintInfo(aTo, aPrefix);
534 if (!mFrameMetrics.IsDefault()) {
535 AppendToString(aTo, mFrameMetrics, " [metrics=", "]");
537 if (UseIntermediateSurface()) {
538 aTo += " [usesTmpSurf]";
540 return aTo;
543 nsACString&
544 ColorLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
546 Layer::PrintInfo(aTo, aPrefix);
547 AppendToString(aTo, mColor, " [color=", "]");
548 return aTo;
551 nsACString&
552 CanvasLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
554 Layer::PrintInfo(aTo, aPrefix);
555 if (mFilter != gfxPattern::FILTER_GOOD) {
556 AppendToString(aTo, mFilter, " [filter=", "]");
558 return aTo;
561 nsACString&
562 ImageLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
564 Layer::PrintInfo(aTo, aPrefix);
565 if (mFilter != gfxPattern::FILTER_GOOD) {
566 AppendToString(aTo, mFilter, " [filter=", "]");
568 return aTo;
571 nsACString&
572 ReadbackLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
574 Layer::PrintInfo(aTo, aPrefix);
575 AppendToString(aTo, mSize, " [size=", "]");
576 if (mBackgroundLayer) {
577 AppendToString(aTo, mBackgroundLayer, " [backgroundLayer=", "]");
578 AppendToString(aTo, mBackgroundLayerOffset, " [backgroundOffset=", "]");
579 } else if (mBackgroundColor.a == 1.0) {
580 AppendToString(aTo, mBackgroundColor, " [backgroundColor=", "]");
581 } else {
582 aTo += " [nobackground]";
584 return aTo;
587 //--------------------------------------------------
588 // LayerManager
590 void
591 LayerManager::Dump(FILE* aFile, const char* aPrefix)
593 FILE* file = FILEOrDefault(aFile);
595 DumpSelf(file, aPrefix);
597 nsCAutoString pfx(aPrefix);
598 pfx += " ";
599 if (!GetRoot()) {
600 fprintf(file, "%s(null)", pfx.get());
601 return;
604 GetRoot()->Dump(file, pfx.get());
607 void
608 LayerManager::DumpSelf(FILE* aFile, const char* aPrefix)
610 nsCAutoString str;
611 PrintInfo(str, aPrefix);
612 fprintf(FILEOrDefault(aFile), "%s\n", str.get());
615 void
616 LayerManager::Log(const char* aPrefix)
618 if (!IsLogEnabled())
619 return;
621 LogSelf(aPrefix);
623 nsCAutoString pfx(aPrefix);
624 pfx += " ";
625 if (!GetRoot()) {
626 MOZ_LAYERS_LOG(("%s(null)", pfx.get()));
627 return;
630 GetRoot()->Log(pfx.get());
633 void
634 LayerManager::LogSelf(const char* aPrefix)
636 nsCAutoString str;
637 PrintInfo(str, aPrefix);
638 MOZ_LAYERS_LOG(("%s", str.get()));
641 nsACString&
642 LayerManager::PrintInfo(nsACString& aTo, const char* aPrefix)
644 aTo += aPrefix;
645 return aTo += nsPrintfCString(64, "%sLayerManager (0x%p)", Name(), this);
648 /*static*/ void
649 LayerManager::InitLog()
651 if (!sLog)
652 sLog = PR_NewLogModule("Layers");
655 /*static*/ bool
656 LayerManager::IsLogEnabled()
658 NS_ABORT_IF_FALSE(!!sLog,
659 "layer manager must be created before logging is allowed");
660 return PR_LOG_TEST(sLog, PR_LOG_DEBUG);
663 # ifdef MOZ_IPC
664 static nsACString&
665 PrintInfo(nsACString& aTo, ShadowLayer* aShadowLayer)
667 if (!aShadowLayer) {
668 return aTo;
670 if (const nsIntRect* clipRect = aShadowLayer->GetShadowClipRect()) {
671 AppendToString(aTo, *clipRect, " [shadow-clip=", "]");
673 if (!aShadowLayer->GetShadowTransform().IsIdentity()) {
674 AppendToString(aTo, aShadowLayer->GetShadowTransform(), " [shadow-transform=", "]");
676 if (!aShadowLayer->GetShadowVisibleRegion().IsEmpty()) {
677 AppendToString(aTo, aShadowLayer->GetShadowVisibleRegion(), " [shadow-visible=", "]");
679 return aTo;
681 # else
682 static nsACString& PrintInfo(nsACString& aTo, ShadowLayer* aShadowLayer)
684 return aTo;
686 # endif // MOZ_IPC
688 #else // !MOZ_LAYERS_HAVE_LOG
690 void Layer::Dump(FILE* aFile, const char* aPrefix) {}
691 void Layer::DumpSelf(FILE* aFile, const char* aPrefix) {}
692 void Layer::Log(const char* aPrefix) {}
693 void Layer::LogSelf(const char* aPrefix) {}
694 nsACString&
695 Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
696 { return aTo; }
698 nsACString&
699 ThebesLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
700 { return aTo; }
702 nsACString&
703 ContainerLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
704 { return aTo; }
706 nsACString&
707 ColorLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
708 { return aTo; }
710 nsACString&
711 CanvasLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
712 { return aTo; }
714 nsACString&
715 ImageLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
716 { return aTo; }
718 nsACString&
719 ReadbackLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
720 { return aTo; }
722 void LayerManager::Dump(FILE* aFile, const char* aPrefix) {}
723 void LayerManager::DumpSelf(FILE* aFile, const char* aPrefix) {}
724 void LayerManager::Log(const char* aPrefix) {}
725 void LayerManager::LogSelf(const char* aPrefix) {}
727 nsACString&
728 LayerManager::PrintInfo(nsACString& aTo, const char* aPrefix)
729 { return aTo; }
731 /*static*/ void LayerManager::InitLog() {}
732 /*static*/ bool LayerManager::IsLogEnabled() { return false; }
734 #endif // MOZ_LAYERS_HAVE_LOG
736 PRLogModuleInfo* LayerManager::sLog;
738 } // namespace layers
739 } // namespace mozilla