Bug 622328 - Fixup widget's UpdateTransparentRegion now that layout's transparent...
[mozilla-central.git] / gfx / layers / Layers.cpp
bloba1ffd9eb93665f244e884fa4596259efe67d6c8a
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"
49 using namespace mozilla::layers;
51 typedef FrameMetrics::ViewID ViewID;
52 const ViewID FrameMetrics::NULL_SCROLL_ID = 0;
53 const ViewID FrameMetrics::ROOT_SCROLL_ID = 1;
54 const ViewID FrameMetrics::START_SCROLL_ID = 2;
56 #ifdef MOZ_LAYERS_HAVE_LOG
57 FILE*
58 FILEOrDefault(FILE* aFile)
60 return aFile ? aFile : stderr;
62 #endif // MOZ_LAYERS_HAVE_LOG
64 namespace {
66 // XXX pretty general utilities, could centralize
68 nsACString&
69 AppendToString(nsACString& s, const gfxPattern::GraphicsFilter& f,
70 const char* pfx="", const char* sfx="")
72 s += pfx;
73 switch (f) {
74 case gfxPattern::FILTER_FAST: s += "fast"; break;
75 case gfxPattern::FILTER_GOOD: s += "good"; break;
76 case gfxPattern::FILTER_BEST: s += "best"; break;
77 case gfxPattern::FILTER_NEAREST: s += "nearest"; break;
78 case gfxPattern::FILTER_BILINEAR: s += "bilinear"; break;
79 case gfxPattern::FILTER_GAUSSIAN: s += "gaussian"; break;
80 default:
81 NS_ERROR("unknown filter type");
82 s += "???";
84 return s += sfx;
87 nsACString&
88 AppendToString(nsACString& s, ViewID n,
89 const char* pfx="", const char* sfx="")
91 s += pfx;
92 s.AppendInt(n);
93 return s += sfx;
96 nsACString&
97 AppendToString(nsACString& s, const gfxRGBA& c,
98 const char* pfx="", const char* sfx="")
100 s += pfx;
101 s += nsPrintfCString(
102 128, "rgba(%d, %d, %d, %g)",
103 PRUint8(c.r*255.0), PRUint8(c.g*255.0), PRUint8(c.b*255.0), c.a);
104 return s += sfx;
107 nsACString&
108 AppendToString(nsACString& s, const gfx3DMatrix& m,
109 const char* pfx="", const char* sfx="")
111 s += pfx;
112 if (m.IsIdentity())
113 s += "[ I ]";
114 else {
115 gfxMatrix matrix;
116 if (m.Is2D(&matrix)) {
117 s += nsPrintfCString(
118 96, "[ %g %g; %g %g; %g %g; ]",
119 matrix.xx, matrix.yx, matrix.xy, matrix.yy, matrix.x0, matrix.y0);
120 } else {
121 s += nsPrintfCString(
122 256, "[ %g %g %g %g; %g %g %g %g; %g %g %g %g; %g %g %g %g; ]",
123 m._11, m._12, m._13, m._14,
124 m._21, m._22, m._23, m._24,
125 m._31, m._32, m._33, m._34,
126 m._41, m._42, m._43, m._44);
129 return s += sfx;
132 nsACString&
133 AppendToString(nsACString& s, const nsIntPoint& p,
134 const char* pfx="", const char* sfx="")
136 s += pfx;
137 s += nsPrintfCString(128, "(x=%d, y=%d)", p.x, p.y);
138 return s += sfx;
141 nsACString&
142 AppendToString(nsACString& s, const nsIntRect& r,
143 const char* pfx="", const char* sfx="")
145 s += pfx;
146 s += nsPrintfCString(
147 256, "(x=%d, y=%d, w=%d, h=%d)",
148 r.x, r.y, r.width, r.height);
149 return s += sfx;
152 nsACString&
153 AppendToString(nsACString& s, const nsIntRegion& r,
154 const char* pfx="", const char* sfx="")
156 s += pfx;
158 nsIntRegionRectIterator it(r);
159 s += "< ";
160 while (const nsIntRect* sr = it.Next())
161 AppendToString(s, *sr) += "; ";
162 s += ">";
164 return s += sfx;
167 nsACString&
168 AppendToString(nsACString& s, const nsIntSize& sz,
169 const char* pfx="", const char* sfx="")
171 s += pfx;
172 s += nsPrintfCString(128, "(w=%d, h=%d)", sz.width, sz.height);
173 return s += sfx;
176 nsACString&
177 AppendToString(nsACString& s, const FrameMetrics& m,
178 const char* pfx="", const char* sfx="")
180 s += pfx;
181 AppendToString(s, m.mViewport, "{ viewport=");
182 AppendToString(s, m.mViewportScrollOffset, " viewportScroll=");
183 AppendToString(s, m.mDisplayPort, " displayport=");
184 AppendToString(s, m.mScrollId, " scrollId=", " }");
185 return s += sfx;
188 } // namespace <anon>
190 namespace mozilla {
191 namespace layers {
193 //--------------------------------------------------
194 // LayerManager
195 already_AddRefed<gfxASurface>
196 LayerManager::CreateOptimalSurface(const gfxIntSize &aSize,
197 gfxASurface::gfxImageFormat aFormat)
199 return gfxPlatform::GetPlatform()->
200 CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFormat));
203 #ifdef DEBUG
204 void
205 LayerManager::Mutated(Layer* aLayer)
207 NS_ABORT_IF_FALSE(!aLayer->GetTileSourceRect() ||
208 (LAYERS_BASIC == GetBackendType() &&
209 Layer::TYPE_IMAGE == aLayer->GetType()),
210 "Tiling not supported for this manager/layer type");
212 #endif // DEBUG
214 //--------------------------------------------------
215 // Layer
217 PRBool
218 Layer::CanUseOpaqueSurface()
220 // If the visible content in the layer is opaque, there is no need
221 // for an alpha channel.
222 if (GetContentFlags() & CONTENT_OPAQUE)
223 return PR_TRUE;
224 // Also, if this layer is the bottommost layer in a container which
225 // doesn't need an alpha channel, we can use an opaque surface for this
226 // layer too. Any transparent areas must be covered by something else
227 // in the container.
228 ContainerLayer* parent = GetParent();
229 return parent && parent->GetFirstChild() == this &&
230 parent->CanUseOpaqueSurface();
233 #ifdef MOZ_IPC
234 // NB: eventually these methods will be defined unconditionally, and
235 // can be moved into Layers.h
236 const nsIntRect*
237 Layer::GetEffectiveClipRect()
239 if (ShadowLayer* shadow = AsShadowLayer()) {
240 return shadow->GetShadowClipRect();
242 return GetClipRect();
245 const nsIntRegion&
246 Layer::GetEffectiveVisibleRegion()
248 if (ShadowLayer* shadow = AsShadowLayer()) {
249 return shadow->GetShadowVisibleRegion();
251 return GetVisibleRegion();
254 #else
256 const nsIntRect* Layer::GetEffectiveClipRect() { return GetClipRect(); }
257 const nsIntRegion& Layer::GetEffectiveVisibleRegion() { return GetVisibleRegion(); }
259 #endif // MOZ_IPC
261 gfx3DMatrix
262 Layer::SnapTransform(const gfx3DMatrix& aTransform,
263 const gfxRect& aSnapRect,
264 gfxMatrix* aResidualTransform)
266 if (aResidualTransform) {
267 *aResidualTransform = gfxMatrix();
270 gfxMatrix matrix2D;
271 gfx3DMatrix result;
272 if (mManager->IsSnappingEffectiveTransforms() &&
273 aTransform.Is2D(&matrix2D) &&
274 matrix2D.HasNonIntegerTranslation() &&
275 !matrix2D.IsSingular() &&
276 !matrix2D.HasNonAxisAlignedTransform()) {
277 gfxMatrix snappedMatrix;
278 gfxPoint topLeft = matrix2D.Transform(aSnapRect.TopLeft());
279 topLeft.Round();
280 // first compute scale factors that scale aSnapRect to the snapped rect
281 if (aSnapRect.IsEmpty()) {
282 snappedMatrix.xx = matrix2D.xx;
283 snappedMatrix.yy = matrix2D.yy;
284 } else {
285 gfxPoint bottomRight = matrix2D.Transform(aSnapRect.BottomRight());
286 bottomRight.Round();
287 snappedMatrix.xx = (bottomRight.x - topLeft.x)/aSnapRect.Width();
288 snappedMatrix.yy = (bottomRight.y - topLeft.y)/aSnapRect.Height();
290 // compute translation factors that will move aSnapRect to the snapped rect
291 // given those scale factors
292 snappedMatrix.x0 = topLeft.x - aSnapRect.pos.x*snappedMatrix.xx;
293 snappedMatrix.y0 = topLeft.y - aSnapRect.pos.y*snappedMatrix.yy;
294 result = gfx3DMatrix::From2D(snappedMatrix);
295 if (aResidualTransform && !snappedMatrix.IsSingular()) {
296 // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
297 // (i.e., appying snappedMatrix after aResidualTransform gives the
298 // ideal transform.
299 gfxMatrix snappedMatrixInverse = snappedMatrix;
300 snappedMatrixInverse.Invert();
301 *aResidualTransform = matrix2D * snappedMatrixInverse;
303 } else {
304 result = aTransform;
306 return result;
309 const gfx3DMatrix&
310 Layer::GetLocalTransform()
312 #ifdef MOZ_IPC
313 if (ShadowLayer* shadow = AsShadowLayer())
314 return shadow->GetShadowTransform();
315 #endif
316 return mTransform;
319 float
320 Layer::GetEffectiveOpacity()
322 float opacity = GetOpacity();
323 for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface();
324 c = c->GetParent()) {
325 opacity *= c->GetOpacity();
327 return opacity;
330 PRBool
331 ContainerLayer::HasMultipleChildren()
333 PRUint32 count = 0;
334 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
335 const nsIntRect *clipRect = child->GetEffectiveClipRect();
336 if (clipRect && clipRect->IsEmpty())
337 continue;
338 if (child->GetVisibleRegion().IsEmpty())
339 continue;
340 ++count;
341 if (count > 1)
342 return PR_TRUE;
345 return PR_FALSE;
348 void
349 ContainerLayer::DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
351 gfxMatrix residual;
352 gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
353 mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), &residual);
355 PRBool useIntermediateSurface;
356 float opacity = GetEffectiveOpacity();
357 if (opacity != 1.0f && HasMultipleChildren()) {
358 useIntermediateSurface = PR_TRUE;
359 } else {
360 useIntermediateSurface = PR_FALSE;
361 gfxMatrix contTransform;
362 if (!mEffectiveTransform.Is2D(&contTransform) ||
363 !contTransform.PreservesAxisAlignedRectangles()) {
364 for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
365 const nsIntRect *clipRect = child->GetEffectiveClipRect();
366 /* We can't (easily) forward our transform to children with a non-empty clip
367 * rect since it would need to be adjusted for the transform.
368 * TODO: This is easily solvable for translation/scaling transforms.
370 if (clipRect && !clipRect->IsEmpty() && !child->GetVisibleRegion().IsEmpty()) {
371 useIntermediateSurface = PR_TRUE;
372 break;
378 mUseIntermediateSurface = useIntermediateSurface;
379 if (useIntermediateSurface) {
380 ComputeEffectiveTransformsForChildren(gfx3DMatrix::From2D(residual));
381 } else {
382 ComputeEffectiveTransformsForChildren(idealTransform);
386 void
387 ContainerLayer::ComputeEffectiveTransformsForChildren(const gfx3DMatrix& aTransformToSurface)
389 for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
390 l->ComputeEffectiveTransforms(aTransformToSurface);
394 #ifdef MOZ_LAYERS_HAVE_LOG
396 static nsACString& PrintInfo(nsACString& aTo, ShadowLayer* aShadowLayer);
398 void
399 Layer::Dump(FILE* aFile, const char* aPrefix)
401 DumpSelf(aFile, aPrefix);
403 if (Layer* kid = GetFirstChild()) {
404 nsCAutoString pfx(aPrefix);
405 pfx += " ";
406 kid->Dump(aFile, pfx.get());
409 if (Layer* next = GetNextSibling())
410 next->Dump(aFile, aPrefix);
413 void
414 Layer::DumpSelf(FILE* aFile, const char* aPrefix)
416 nsCAutoString str;
417 PrintInfo(str, aPrefix);
418 fprintf(FILEOrDefault(aFile), "%s\n", str.get());
421 void
422 Layer::Log(const char* aPrefix)
424 if (!IsLogEnabled())
425 return;
427 LogSelf(aPrefix);
429 if (Layer* kid = GetFirstChild()) {
430 nsCAutoString pfx(aPrefix);
431 pfx += " ";
432 kid->Log(pfx.get());
435 if (Layer* next = GetNextSibling())
436 next->Log(aPrefix);
439 void
440 Layer::LogSelf(const char* aPrefix)
442 if (!IsLogEnabled())
443 return;
445 nsCAutoString str;
446 PrintInfo(str, aPrefix);
447 MOZ_LAYERS_LOG(("%s", str.get()));
450 nsACString&
451 Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
453 aTo += aPrefix;
454 aTo += nsPrintfCString(64, "%s%s (0x%p)", mManager->Name(), Name(), this);
456 ::PrintInfo(aTo, AsShadowLayer());
458 if (mUseClipRect) {
459 AppendToString(aTo, mClipRect, " [clip=", "]");
461 if (!mTransform.IsIdentity()) {
462 AppendToString(aTo, mTransform, " [transform=", "]");
464 if (!mVisibleRegion.IsEmpty()) {
465 AppendToString(aTo, mVisibleRegion, " [visible=", "]");
467 if (1.0 != mOpacity) {
468 aTo.AppendPrintf(" [opacity=%g]", mOpacity);
470 if (const nsIntRect* tileSourceRect = GetTileSourceRect()) {
471 AppendToString(aTo, *tileSourceRect, " [tileSrc=", "]");
473 if (GetContentFlags() & CONTENT_OPAQUE) {
474 aTo += " [opaqueContent]";
476 if (GetContentFlags() & CONTENT_COMPONENT_ALPHA) {
477 aTo += " [componentAlpha]";
480 return aTo;
483 nsACString&
484 ThebesLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
486 Layer::PrintInfo(aTo, aPrefix);
487 if (!mValidRegion.IsEmpty()) {
488 AppendToString(aTo, mValidRegion, " [valid=", "]");
490 if (mXResolution != 1.0 || mYResolution != 1.0) {
491 aTo.AppendPrintf(" [xres=%g yres=%g]", mXResolution, mYResolution);
493 return aTo;
496 nsACString&
497 ContainerLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
499 Layer::PrintInfo(aTo, aPrefix);
500 if (!mFrameMetrics.IsDefault()) {
501 AppendToString(aTo, mFrameMetrics, " [metrics=", "]");
503 if (UseIntermediateSurface()) {
504 aTo += " [usesTmpSurf]";
506 return aTo;
509 nsACString&
510 ColorLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
512 Layer::PrintInfo(aTo, aPrefix);
513 AppendToString(aTo, mColor, " [color=", "]");
514 return aTo;
517 nsACString&
518 CanvasLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
520 Layer::PrintInfo(aTo, aPrefix);
521 if (mFilter != gfxPattern::FILTER_GOOD) {
522 AppendToString(aTo, mFilter, " [filter=", "]");
524 return aTo;
527 nsACString&
528 ImageLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
530 Layer::PrintInfo(aTo, aPrefix);
531 if (mFilter != gfxPattern::FILTER_GOOD) {
532 AppendToString(aTo, mFilter, " [filter=", "]");
534 return aTo;
537 //--------------------------------------------------
538 // LayerManager
540 void
541 LayerManager::Dump(FILE* aFile, const char* aPrefix)
543 FILE* file = FILEOrDefault(aFile);
545 DumpSelf(file, aPrefix);
547 nsCAutoString pfx(aPrefix);
548 pfx += " ";
549 if (!GetRoot()) {
550 fprintf(file, "%s(null)", pfx.get());
551 return;
554 GetRoot()->Dump(file, pfx.get());
557 void
558 LayerManager::DumpSelf(FILE* aFile, const char* aPrefix)
560 nsCAutoString str;
561 PrintInfo(str, aPrefix);
562 fprintf(FILEOrDefault(aFile), "%s\n", str.get());
565 void
566 LayerManager::Log(const char* aPrefix)
568 if (!IsLogEnabled())
569 return;
571 LogSelf(aPrefix);
573 nsCAutoString pfx(aPrefix);
574 pfx += " ";
575 if (!GetRoot()) {
576 MOZ_LAYERS_LOG(("%s(null)", pfx.get()));
577 return;
580 GetRoot()->Log(pfx.get());
583 void
584 LayerManager::LogSelf(const char* aPrefix)
586 nsCAutoString str;
587 PrintInfo(str, aPrefix);
588 MOZ_LAYERS_LOG(("%s", str.get()));
591 nsACString&
592 LayerManager::PrintInfo(nsACString& aTo, const char* aPrefix)
594 aTo += aPrefix;
595 return aTo += nsPrintfCString(64, "%sLayerManager (0x%p)", Name(), this);
598 /*static*/ void
599 LayerManager::InitLog()
601 if (!sLog)
602 sLog = PR_NewLogModule("Layers");
605 /*static*/ bool
606 LayerManager::IsLogEnabled()
608 NS_ABORT_IF_FALSE(!!sLog,
609 "layer manager must be created before logging is allowed");
610 return PR_LOG_TEST(sLog, PR_LOG_DEBUG);
613 # ifdef MOZ_IPC
614 static nsACString&
615 PrintInfo(nsACString& aTo, ShadowLayer* aShadowLayer)
617 if (!aShadowLayer) {
618 return aTo;
620 if (const nsIntRect* clipRect = aShadowLayer->GetShadowClipRect()) {
621 AppendToString(aTo, *clipRect, " [shadow-clip=", "]");
623 if (!aShadowLayer->GetShadowTransform().IsIdentity()) {
624 AppendToString(aTo, aShadowLayer->GetShadowTransform(), " [shadow-transform=", "]");
626 if (!aShadowLayer->GetShadowVisibleRegion().IsEmpty()) {
627 AppendToString(aTo, aShadowLayer->GetShadowVisibleRegion(), " [shadow-visible=", "]");
629 return aTo;
631 # else
632 static nsACString& PrintInfo(nsACString& aTo, ShadowLayer* aShadowLayer)
634 return aTo;
636 # endif // MOZ_IPC
638 #else // !MOZ_LAYERS_HAVE_LOG
640 void Layer::Dump(FILE* aFile, const char* aPrefix) {}
641 void Layer::DumpSelf(FILE* aFile, const char* aPrefix) {}
642 void Layer::Log(const char* aPrefix) {}
643 void Layer::LogSelf(const char* aPrefix) {}
644 nsACString&
645 Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
646 { return aTo; }
648 nsACString&
649 ThebesLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
650 { return aTo; }
652 nsACString&
653 ContainerLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
654 { return aTo; }
656 nsACString&
657 ColorLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
658 { return aTo; }
660 nsACString&
661 CanvasLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
662 { return aTo; }
664 nsACString&
665 ImageLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
666 { return aTo; }
668 void LayerManager::Dump(FILE* aFile, const char* aPrefix) {}
669 void LayerManager::DumpSelf(FILE* aFile, const char* aPrefix) {}
670 void LayerManager::Log(const char* aPrefix) {}
671 void LayerManager::LogSelf(const char* aPrefix) {}
673 nsACString&
674 LayerManager::PrintInfo(nsACString& aTo, const char* aPrefix)
675 { return aTo; }
677 /*static*/ void LayerManager::InitLog() {}
678 /*static*/ bool LayerManager::IsLogEnabled() { return false; }
680 #endif // MOZ_LAYERS_HAVE_LOG
682 PRLogModuleInfo* LayerManager::sLog;
684 } // namespace layers
685 } // namespace mozilla