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 "ImageHost.h" michael@0: #include "LayersLogging.h" // for AppendToString michael@0: #include "composite/CompositableHost.h" // for CompositableHost, etc michael@0: #include "ipc/IPCMessageUtils.h" // for null_t michael@0: #include "mozilla/layers/Compositor.h" // for Compositor michael@0: #include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc michael@0: #include "nsAString.h" michael@0: #include "nsDebug.h" // for NS_WARNING, NS_ASSERTION michael@0: #include "nsPrintfCString.h" // for nsPrintfCString michael@0: #include "nsString.h" // for nsAutoCString michael@0: michael@0: class nsIntRegion; michael@0: michael@0: namespace mozilla { michael@0: namespace gfx { michael@0: class Matrix4x4; michael@0: } michael@0: michael@0: using namespace gfx; michael@0: michael@0: namespace layers { michael@0: michael@0: class ISurfaceAllocator; michael@0: michael@0: ImageHost::ImageHost(const TextureInfo& aTextureInfo) michael@0: : CompositableHost(aTextureInfo) michael@0: , mFrontBuffer(nullptr) michael@0: , mHasPictureRect(false) michael@0: {} michael@0: michael@0: ImageHost::~ImageHost() {} michael@0: michael@0: void michael@0: ImageHost::UseTextureHost(TextureHost* aTexture) michael@0: { michael@0: CompositableHost::UseTextureHost(aTexture); michael@0: mFrontBuffer = aTexture; michael@0: } michael@0: michael@0: void michael@0: ImageHost::RemoveTextureHost(TextureHost* aTexture) michael@0: { michael@0: CompositableHost::RemoveTextureHost(aTexture); michael@0: if (aTexture && mFrontBuffer == aTexture) { michael@0: aTexture->SetCompositableBackendSpecificData(nullptr); michael@0: mFrontBuffer = nullptr; michael@0: } michael@0: } michael@0: michael@0: TextureHost* michael@0: ImageHost::GetAsTextureHost() michael@0: { michael@0: return mFrontBuffer; michael@0: } michael@0: michael@0: void michael@0: ImageHost::Composite(EffectChain& aEffectChain, michael@0: float aOpacity, michael@0: const gfx::Matrix4x4& aTransform, michael@0: const gfx::Filter& aFilter, michael@0: const gfx::Rect& aClipRect, michael@0: const nsIntRegion* aVisibleRegion, michael@0: TiledLayerProperties* aLayerProperties) michael@0: { michael@0: if (!GetCompositor()) { michael@0: // should only happen when a tab is dragged to another window and michael@0: // async-video is still sending frames but we haven't attached the michael@0: // set the new compositor yet. michael@0: return; michael@0: } michael@0: if (!mFrontBuffer) { michael@0: return; michael@0: } michael@0: michael@0: // Make sure the front buffer has a compositor michael@0: mFrontBuffer->SetCompositor(GetCompositor()); michael@0: mFrontBuffer->SetCompositableBackendSpecificData(GetCompositableBackendSpecificData()); michael@0: michael@0: AutoLockTextureHost autoLock(mFrontBuffer); michael@0: if (autoLock.Failed()) { michael@0: NS_WARNING("failed to lock front buffer"); michael@0: return; michael@0: } michael@0: RefPtr source = mFrontBuffer->GetTextureSources(); michael@0: if (!source) { michael@0: return; michael@0: } michael@0: RefPtr effect = CreateTexturedEffect(mFrontBuffer->GetFormat(), michael@0: source, michael@0: aFilter); michael@0: if (!effect) { michael@0: return; michael@0: } michael@0: michael@0: aEffectChain.mPrimaryEffect = effect; michael@0: IntSize textureSize = source->GetSize(); michael@0: gfx::Rect gfxPictureRect michael@0: = mHasPictureRect ? gfx::Rect(0, 0, mPictureRect.width, mPictureRect.height) michael@0: : gfx::Rect(0, 0, textureSize.width, textureSize.height); michael@0: michael@0: gfx::Rect pictureRect(0, 0, michael@0: mPictureRect.width, michael@0: mPictureRect.height); michael@0: //XXX: We might have multiple texture sources here (e.g. 3 YCbCr textures), and we're michael@0: // only iterating over the tiles of the first one. Are we assuming that the tiling michael@0: // will be identical? Can we ensure that somehow? michael@0: TileIterator* it = source->AsTileIterator(); michael@0: if (it) { michael@0: it->BeginTileIteration(); michael@0: do { michael@0: nsIntRect tileRect = it->GetTileRect(); michael@0: gfx::Rect rect(tileRect.x, tileRect.y, tileRect.width, tileRect.height); michael@0: if (mHasPictureRect) { michael@0: rect = rect.Intersect(pictureRect); michael@0: effect->mTextureCoords = Rect(Float(rect.x - tileRect.x)/ tileRect.width, michael@0: Float(rect.y - tileRect.y) / tileRect.height, michael@0: Float(rect.width) / tileRect.width, michael@0: Float(rect.height) / tileRect.height); michael@0: } else { michael@0: effect->mTextureCoords = Rect(0, 0, 1, 1); michael@0: } michael@0: GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, michael@0: aOpacity, aTransform); michael@0: GetCompositor()->DrawDiagnostics(DIAGNOSTIC_IMAGE|DIAGNOSTIC_BIGIMAGE, michael@0: rect, aClipRect, aTransform, mFlashCounter); michael@0: } while (it->NextTile()); michael@0: it->EndTileIteration(); michael@0: // layer border michael@0: GetCompositor()->DrawDiagnostics(DIAGNOSTIC_IMAGE, michael@0: gfxPictureRect, aClipRect, michael@0: aTransform, mFlashCounter); michael@0: } else { michael@0: IntSize textureSize = source->GetSize(); michael@0: gfx::Rect rect; michael@0: if (mHasPictureRect) { michael@0: effect->mTextureCoords = Rect(Float(mPictureRect.x) / textureSize.width, michael@0: Float(mPictureRect.y) / textureSize.height, michael@0: Float(mPictureRect.width) / textureSize.width, michael@0: Float(mPictureRect.height) / textureSize.height); michael@0: rect = pictureRect; michael@0: } else { michael@0: effect->mTextureCoords = Rect(0, 0, 1, 1); michael@0: rect = gfx::Rect(0, 0, textureSize.width, textureSize.height); michael@0: } michael@0: michael@0: if (mFrontBuffer->GetFlags() & TEXTURE_NEEDS_Y_FLIP) { michael@0: effect->mTextureCoords.y = effect->mTextureCoords.YMost(); michael@0: effect->mTextureCoords.height = -effect->mTextureCoords.height; michael@0: } michael@0: michael@0: GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, michael@0: aOpacity, aTransform); michael@0: GetCompositor()->DrawDiagnostics(DIAGNOSTIC_IMAGE, michael@0: rect, aClipRect, michael@0: aTransform, mFlashCounter); michael@0: } michael@0: } michael@0: michael@0: void michael@0: ImageHost::SetCompositor(Compositor* aCompositor) michael@0: { michael@0: if (mFrontBuffer && mCompositor != aCompositor) { michael@0: mFrontBuffer->SetCompositor(aCompositor); michael@0: } michael@0: CompositableHost::SetCompositor(aCompositor); michael@0: } michael@0: michael@0: void michael@0: ImageHost::PrintInfo(nsACString& aTo, const char* aPrefix) michael@0: { michael@0: aTo += aPrefix; michael@0: aTo += nsPrintfCString("ImageHost (0x%p)", this); michael@0: michael@0: AppendToString(aTo, mPictureRect, " [picture-rect=", "]"); michael@0: michael@0: if (mFrontBuffer) { michael@0: nsAutoCString pfx(aPrefix); michael@0: pfx += " "; michael@0: aTo += "\n"; michael@0: mFrontBuffer->PrintInfo(aTo, pfx.get()); michael@0: } michael@0: } michael@0: michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: void michael@0: ImageHost::Dump(FILE* aFile, michael@0: const char* aPrefix, michael@0: bool aDumpHtml) michael@0: { michael@0: if (!aFile) { michael@0: aFile = stderr; michael@0: } michael@0: if (mFrontBuffer) { michael@0: fprintf_stderr(aFile, "%s", aPrefix); michael@0: fprintf_stderr(aFile, aDumpHtml ? " " : " "); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: LayerRenderState michael@0: ImageHost::GetRenderState() michael@0: { michael@0: if (mFrontBuffer) { michael@0: return mFrontBuffer->GetRenderState(); michael@0: } michael@0: return LayerRenderState(); michael@0: } michael@0: michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: TemporaryRef michael@0: ImageHost::GetAsSurface() michael@0: { michael@0: return mFrontBuffer->GetAsSurface(); michael@0: } michael@0: #endif michael@0: michael@0: } michael@0: }