michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/layers/Compositor.h" michael@0: #include "base/message_loop.h" // for MessageLoop michael@0: #include "mozilla/layers/CompositorParent.h" // for CompositorParent michael@0: #include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc michael@0: #include "mozilla/mozalloc.h" // for operator delete, etc michael@0: #include "gfx2DGlue.h" michael@0: michael@0: namespace mozilla { michael@0: namespace gfx { michael@0: class Matrix4x4; michael@0: } michael@0: michael@0: namespace layers { michael@0: michael@0: /* static */ LayersBackend Compositor::sBackend = LayersBackend::LAYERS_NONE; michael@0: /* static */ LayersBackend michael@0: Compositor::GetBackend() michael@0: { michael@0: AssertOnCompositorThread(); michael@0: return sBackend; michael@0: } michael@0: michael@0: /* static */ void michael@0: Compositor::SetBackend(LayersBackend backend) michael@0: { michael@0: if (sBackend != LayersBackend::LAYERS_NONE && sBackend != backend) { michael@0: // Assert this once we figure out bug 972891. michael@0: //MOZ_CRASH("Trying to use more than one OMTC compositor."); michael@0: michael@0: #ifdef XP_MACOSX michael@0: printf("ERROR: Changing compositor from %u to %u.\n", michael@0: unsigned(sBackend), unsigned(backend)); michael@0: #endif michael@0: } michael@0: sBackend = backend; michael@0: } michael@0: michael@0: /* static */ void michael@0: Compositor::AssertOnCompositorThread() michael@0: { michael@0: MOZ_ASSERT(CompositorParent::CompositorLoop() == michael@0: MessageLoop::current(), michael@0: "Can only call this from the compositor thread!"); michael@0: } michael@0: michael@0: bool michael@0: Compositor::ShouldDrawDiagnostics(DiagnosticFlags aFlags) michael@0: { michael@0: if ((aFlags & DIAGNOSTIC_TILE) && !(mDiagnosticTypes & DIAGNOSTIC_TILE_BORDERS)) { michael@0: return false; michael@0: } michael@0: if ((aFlags & DIAGNOSTIC_BIGIMAGE) && michael@0: !(mDiagnosticTypes & DIAGNOSTIC_BIGIMAGE_BORDERS)) { michael@0: return false; michael@0: } michael@0: if (!mDiagnosticTypes) { michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: Compositor::DrawDiagnostics(DiagnosticFlags aFlags, michael@0: const nsIntRegion& aVisibleRegion, michael@0: const gfx::Rect& aClipRect, michael@0: const gfx::Matrix4x4& aTransform, michael@0: uint32_t aFlashCounter) michael@0: { michael@0: if (!ShouldDrawDiagnostics(aFlags)) { michael@0: return; michael@0: } michael@0: michael@0: if (aVisibleRegion.GetNumRects() > 1) { michael@0: nsIntRegionRectIterator screenIter(aVisibleRegion); michael@0: michael@0: while (const nsIntRect* rect = screenIter.Next()) michael@0: { michael@0: DrawDiagnostics(aFlags | DIAGNOSTIC_REGION_RECT, michael@0: ToRect(*rect), aClipRect, aTransform, aFlashCounter); michael@0: } michael@0: } michael@0: michael@0: DrawDiagnostics(aFlags, ToRect(aVisibleRegion.GetBounds()), michael@0: aClipRect, aTransform, aFlashCounter); michael@0: } michael@0: michael@0: void michael@0: Compositor::DrawDiagnostics(DiagnosticFlags aFlags, michael@0: const gfx::Rect& aVisibleRect, michael@0: const gfx::Rect& aClipRect, michael@0: const gfx::Matrix4x4& aTransform, michael@0: uint32_t aFlashCounter) michael@0: { michael@0: if (!ShouldDrawDiagnostics(aFlags)) { michael@0: return; michael@0: } michael@0: michael@0: DrawDiagnosticsInternal(aFlags, aVisibleRect, aClipRect, aTransform, michael@0: aFlashCounter); michael@0: } michael@0: michael@0: gfx::Rect michael@0: Compositor::ClipRectInLayersCoordinates(gfx::Rect aClip) const { michael@0: gfx::Rect result; michael@0: aClip = aClip + GetCurrentRenderTarget()->GetOrigin(); michael@0: gfx::IntSize destSize = GetWidgetSize(); michael@0: michael@0: switch (mScreenRotation) { michael@0: case ROTATION_0: michael@0: result = aClip; michael@0: break; michael@0: case ROTATION_90: michael@0: result = gfx::Rect(aClip.y, michael@0: destSize.width - aClip.x - aClip.width, michael@0: aClip.height, aClip.width); michael@0: break; michael@0: case ROTATION_270: michael@0: result = gfx::Rect(destSize.height - aClip.y - aClip.height, michael@0: aClip.x, michael@0: aClip.height, aClip.width); michael@0: break; michael@0: case ROTATION_180: michael@0: result = gfx::Rect(destSize.width - aClip.x - aClip.width, michael@0: destSize.height - aClip.y - aClip.height, michael@0: aClip.width, aClip.height); michael@0: break; michael@0: // ScreenRotation has a sentinel value, need to catch it in the switch michael@0: // statement otherwise the build fails (-WError) michael@0: default: {} michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: Compositor::DrawDiagnosticsInternal(DiagnosticFlags aFlags, michael@0: const gfx::Rect& aVisibleRect, michael@0: const gfx::Rect& aClipRect, michael@0: const gfx::Matrix4x4& aTransform, michael@0: uint32_t aFlashCounter) michael@0: { michael@0: #ifdef MOZ_B2G michael@0: int lWidth = 4; michael@0: #elif defined(ANDROID) michael@0: int lWidth = 10; michael@0: #else michael@0: int lWidth = 2; michael@0: #endif michael@0: float opacity = 0.7f; michael@0: michael@0: gfx::Color color; michael@0: if (aFlags & DIAGNOSTIC_CONTENT) { michael@0: color = gfx::Color(0.0f, 1.0f, 0.0f, 1.0f); // green michael@0: if (aFlags & DIAGNOSTIC_COMPONENT_ALPHA) { michael@0: color = gfx::Color(0.0f, 1.0f, 1.0f, 1.0f); // greenish blue michael@0: } michael@0: } else if (aFlags & DIAGNOSTIC_IMAGE) { michael@0: color = gfx::Color(1.0f, 0.0f, 0.0f, 1.0f); // red michael@0: } else if (aFlags & DIAGNOSTIC_COLOR) { michael@0: color = gfx::Color(0.0f, 0.0f, 1.0f, 1.0f); // blue michael@0: } else if (aFlags & DIAGNOSTIC_CONTAINER) { michael@0: color = gfx::Color(0.8f, 0.0f, 0.8f, 1.0f); // purple michael@0: } michael@0: michael@0: // make tile borders a bit more transparent to keep layer borders readable. michael@0: if (aFlags & DIAGNOSTIC_TILE || michael@0: aFlags & DIAGNOSTIC_BIGIMAGE || michael@0: aFlags & DIAGNOSTIC_REGION_RECT) { michael@0: lWidth = 1; michael@0: opacity = 0.5f; michael@0: color.r *= 0.7f; michael@0: color.g *= 0.7f; michael@0: color.b *= 0.7f; michael@0: } michael@0: michael@0: if (mDiagnosticTypes & DIAGNOSTIC_FLASH_BORDERS) { michael@0: float flash = (float)aFlashCounter / (float)DIAGNOSTIC_FLASH_COUNTER_MAX; michael@0: color.r *= flash; michael@0: color.g *= flash; michael@0: color.b *= flash; michael@0: } michael@0: michael@0: EffectChain effects; michael@0: michael@0: effects.mPrimaryEffect = new EffectSolidColor(color); michael@0: // left michael@0: this->DrawQuad(gfx::Rect(aVisibleRect.x, aVisibleRect.y, michael@0: lWidth, aVisibleRect.height), michael@0: aClipRect, effects, opacity, michael@0: aTransform); michael@0: // top michael@0: this->DrawQuad(gfx::Rect(aVisibleRect.x + lWidth, aVisibleRect.y, michael@0: aVisibleRect.width - 2 * lWidth, lWidth), michael@0: aClipRect, effects, opacity, michael@0: aTransform); michael@0: // right michael@0: this->DrawQuad(gfx::Rect(aVisibleRect.x + aVisibleRect.width - lWidth, aVisibleRect.y, michael@0: lWidth, aVisibleRect.height), michael@0: aClipRect, effects, opacity, michael@0: aTransform); michael@0: // bottom michael@0: this->DrawQuad(gfx::Rect(aVisibleRect.x + lWidth, aVisibleRect.y + aVisibleRect.height-lWidth, michael@0: aVisibleRect.width - 2 * lWidth, lWidth), michael@0: aClipRect, effects, opacity, michael@0: aTransform); michael@0: } michael@0: michael@0: } // namespace michael@0: } // namespace