1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/composite/ContentHost.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,703 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/layers/ContentHost.h" 1.10 +#include "LayersLogging.h" // for AppendToString 1.11 +#include "gfx2DGlue.h" // for ContentForFormat 1.12 +#include "mozilla/gfx/Point.h" // for IntSize 1.13 +#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc 1.14 +#include "mozilla/gfx/BaseRect.h" // for BaseRect 1.15 +#include "mozilla/layers/Compositor.h" // for Compositor 1.16 +#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc 1.17 +#include "mozilla/layers/LayersMessages.h" // for ThebesBufferData 1.18 +#include "nsAString.h" 1.19 +#include "nsPrintfCString.h" // for nsPrintfCString 1.20 +#include "nsString.h" // for nsAutoCString 1.21 +#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL 1.22 + 1.23 +namespace mozilla { 1.24 +namespace gfx { 1.25 +class Matrix4x4; 1.26 +} 1.27 +using namespace gfx; 1.28 + 1.29 +namespace layers { 1.30 + 1.31 +ContentHostBase::ContentHostBase(const TextureInfo& aTextureInfo) 1.32 + : ContentHost(aTextureInfo) 1.33 + , mPaintWillResample(false) 1.34 + , mInitialised(false) 1.35 +{} 1.36 + 1.37 +ContentHostBase::~ContentHostBase() 1.38 +{ 1.39 +} 1.40 + 1.41 +struct AutoLockContentHost 1.42 +{ 1.43 + AutoLockContentHost(ContentHostBase* aHost) 1.44 + : mHost(aHost) 1.45 + { 1.46 + mSucceeded = mHost->Lock(); 1.47 + } 1.48 + 1.49 + ~AutoLockContentHost() 1.50 + { 1.51 + if (mSucceeded) { 1.52 + mHost->Unlock(); 1.53 + } 1.54 + } 1.55 + 1.56 + bool Failed() { return !mSucceeded; } 1.57 + 1.58 + ContentHostBase* mHost; 1.59 + bool mSucceeded; 1.60 +}; 1.61 + 1.62 +void 1.63 +ContentHostBase::Composite(EffectChain& aEffectChain, 1.64 + float aOpacity, 1.65 + const gfx::Matrix4x4& aTransform, 1.66 + const Filter& aFilter, 1.67 + const Rect& aClipRect, 1.68 + const nsIntRegion* aVisibleRegion, 1.69 + TiledLayerProperties* aLayerProperties) 1.70 +{ 1.71 + NS_ASSERTION(aVisibleRegion, "Requires a visible region"); 1.72 + 1.73 + AutoLockContentHost lock(this); 1.74 + if (lock.Failed()) { 1.75 + return; 1.76 + } 1.77 + 1.78 + RefPtr<NewTextureSource> source = GetTextureSource(); 1.79 + RefPtr<NewTextureSource> sourceOnWhite = GetTextureSourceOnWhite(); 1.80 + 1.81 + if (!source) { 1.82 + return; 1.83 + } 1.84 + RefPtr<TexturedEffect> effect = 1.85 + CreateTexturedEffect(source, sourceOnWhite, aFilter); 1.86 + 1.87 + if (!effect) { 1.88 + return; 1.89 + } 1.90 + 1.91 + aEffectChain.mPrimaryEffect = effect; 1.92 + 1.93 + nsIntRegion tmpRegion; 1.94 + const nsIntRegion* renderRegion; 1.95 + if (PaintWillResample()) { 1.96 + // If we're resampling, then the texture image will contain exactly the 1.97 + // entire visible region's bounds, and we should draw it all in one quad 1.98 + // to avoid unexpected aliasing. 1.99 + tmpRegion = aVisibleRegion->GetBounds(); 1.100 + renderRegion = &tmpRegion; 1.101 + } else { 1.102 + renderRegion = aVisibleRegion; 1.103 + } 1.104 + 1.105 + nsIntRegion region(*renderRegion); 1.106 + nsIntPoint origin = GetOriginOffset(); 1.107 + // translate into TexImage space, buffer origin might not be at texture (0,0) 1.108 + region.MoveBy(-origin); 1.109 + 1.110 + // Figure out the intersecting draw region 1.111 + gfx::IntSize texSize = source->GetSize(); 1.112 + nsIntRect textureRect = nsIntRect(0, 0, texSize.width, texSize.height); 1.113 + textureRect.MoveBy(region.GetBounds().TopLeft()); 1.114 + nsIntRegion subregion; 1.115 + subregion.And(region, textureRect); 1.116 + if (subregion.IsEmpty()) { 1.117 + // Region is empty, nothing to draw 1.118 + return; 1.119 + } 1.120 + 1.121 + nsIntRegion screenRects; 1.122 + nsIntRegion regionRects; 1.123 + 1.124 + // Collect texture/screen coordinates for drawing 1.125 + nsIntRegionRectIterator iter(subregion); 1.126 + while (const nsIntRect* iterRect = iter.Next()) { 1.127 + nsIntRect regionRect = *iterRect; 1.128 + nsIntRect screenRect = regionRect; 1.129 + screenRect.MoveBy(origin); 1.130 + 1.131 + screenRects.Or(screenRects, screenRect); 1.132 + regionRects.Or(regionRects, regionRect); 1.133 + } 1.134 + 1.135 + TileIterator* tileIter = source->AsTileIterator(); 1.136 + TileIterator* iterOnWhite = nullptr; 1.137 + if (tileIter) { 1.138 + tileIter->BeginTileIteration(); 1.139 + } 1.140 + 1.141 + if (sourceOnWhite) { 1.142 + iterOnWhite = sourceOnWhite->AsTileIterator(); 1.143 + MOZ_ASSERT(!tileIter || tileIter->GetTileCount() == iterOnWhite->GetTileCount(), 1.144 + "Tile count mismatch on component alpha texture"); 1.145 + if (iterOnWhite) { 1.146 + iterOnWhite->BeginTileIteration(); 1.147 + } 1.148 + } 1.149 + 1.150 + bool usingTiles = (tileIter && tileIter->GetTileCount() > 1); 1.151 + do { 1.152 + if (iterOnWhite) { 1.153 + MOZ_ASSERT(iterOnWhite->GetTileRect() == tileIter->GetTileRect(), 1.154 + "component alpha textures should be the same size."); 1.155 + } 1.156 + 1.157 + nsIntRect texRect = tileIter ? tileIter->GetTileRect() 1.158 + : nsIntRect(0, 0, 1.159 + texSize.width, 1.160 + texSize.height); 1.161 + 1.162 + // Draw texture. If we're using tiles, we do repeating manually, as texture 1.163 + // repeat would cause each individual tile to repeat instead of the 1.164 + // compound texture as a whole. This involves drawing at most 4 sections, 1.165 + // 2 for each axis that has texture repeat. 1.166 + for (int y = 0; y < (usingTiles ? 2 : 1); y++) { 1.167 + for (int x = 0; x < (usingTiles ? 2 : 1); x++) { 1.168 + nsIntRect currentTileRect(texRect); 1.169 + currentTileRect.MoveBy(x * texSize.width, y * texSize.height); 1.170 + 1.171 + nsIntRegionRectIterator screenIter(screenRects); 1.172 + nsIntRegionRectIterator regionIter(regionRects); 1.173 + 1.174 + const nsIntRect* screenRect; 1.175 + const nsIntRect* regionRect; 1.176 + while ((screenRect = screenIter.Next()) && 1.177 + (regionRect = regionIter.Next())) { 1.178 + nsIntRect tileScreenRect(*screenRect); 1.179 + nsIntRect tileRegionRect(*regionRect); 1.180 + 1.181 + // When we're using tiles, find the intersection between the tile 1.182 + // rect and this region rect. Tiling is then handled by the 1.183 + // outer for-loops and modifying the tile rect. 1.184 + if (usingTiles) { 1.185 + tileScreenRect.MoveBy(-origin); 1.186 + tileScreenRect = tileScreenRect.Intersect(currentTileRect); 1.187 + tileScreenRect.MoveBy(origin); 1.188 + 1.189 + if (tileScreenRect.IsEmpty()) 1.190 + continue; 1.191 + 1.192 + tileRegionRect = regionRect->Intersect(currentTileRect); 1.193 + tileRegionRect.MoveBy(-currentTileRect.TopLeft()); 1.194 + } 1.195 + gfx::Rect rect(tileScreenRect.x, tileScreenRect.y, 1.196 + tileScreenRect.width, tileScreenRect.height); 1.197 + 1.198 + effect->mTextureCoords = Rect(Float(tileRegionRect.x) / texRect.width, 1.199 + Float(tileRegionRect.y) / texRect.height, 1.200 + Float(tileRegionRect.width) / texRect.width, 1.201 + Float(tileRegionRect.height) / texRect.height); 1.202 + GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, aOpacity, aTransform); 1.203 + if (usingTiles) { 1.204 + DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT | DIAGNOSTIC_BIGIMAGE; 1.205 + diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0; 1.206 + GetCompositor()->DrawDiagnostics(diagnostics, rect, aClipRect, 1.207 + aTransform, mFlashCounter); 1.208 + } 1.209 + } 1.210 + } 1.211 + } 1.212 + 1.213 + if (iterOnWhite) { 1.214 + iterOnWhite->NextTile(); 1.215 + } 1.216 + } while (usingTiles && tileIter->NextTile()); 1.217 + 1.218 + if (tileIter) { 1.219 + tileIter->EndTileIteration(); 1.220 + } 1.221 + if (iterOnWhite) { 1.222 + iterOnWhite->EndTileIteration(); 1.223 + } 1.224 + 1.225 + DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT; 1.226 + diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0; 1.227 + GetCompositor()->DrawDiagnostics(diagnostics, *aVisibleRegion, aClipRect, 1.228 + aTransform, mFlashCounter); 1.229 +} 1.230 + 1.231 + 1.232 +void 1.233 +ContentHostTexture::UseTextureHost(TextureHost* aTexture) 1.234 +{ 1.235 + ContentHostBase::UseTextureHost(aTexture); 1.236 + mTextureHost = aTexture; 1.237 + mTextureHostOnWhite = nullptr; 1.238 +} 1.239 + 1.240 +void 1.241 +ContentHostTexture::UseComponentAlphaTextures(TextureHost* aTextureOnBlack, 1.242 + TextureHost* aTextureOnWhite) 1.243 +{ 1.244 + ContentHostBase::UseComponentAlphaTextures(aTextureOnBlack, aTextureOnWhite); 1.245 + mTextureHost = aTextureOnBlack; 1.246 + mTextureHostOnWhite = aTextureOnWhite; 1.247 +} 1.248 + 1.249 +void 1.250 +ContentHostTexture::SetCompositor(Compositor* aCompositor) 1.251 +{ 1.252 + ContentHostBase::SetCompositor(aCompositor); 1.253 + if (mTextureHost) { 1.254 + mTextureHost->SetCompositor(aCompositor); 1.255 + } 1.256 + if (mTextureHostOnWhite) { 1.257 + mTextureHostOnWhite->SetCompositor(aCompositor); 1.258 + } 1.259 +} 1.260 + 1.261 +#ifdef MOZ_DUMP_PAINTING 1.262 +void 1.263 +ContentHostTexture::Dump(FILE* aFile, 1.264 + const char* aPrefix, 1.265 + bool aDumpHtml) 1.266 +{ 1.267 + if (!aDumpHtml) { 1.268 + return; 1.269 + } 1.270 + if (!aFile) { 1.271 + aFile = stderr; 1.272 + } 1.273 + fprintf(aFile, "<ul>"); 1.274 + if (mTextureHost) { 1.275 + fprintf(aFile, "%s", aPrefix); 1.276 + fprintf(aFile, "<li> <a href="); 1.277 + DumpTextureHost(aFile, mTextureHost); 1.278 + fprintf(aFile, "> Front buffer </a></li> "); 1.279 + } 1.280 + if (mTextureHostOnWhite) { 1.281 + fprintf(aFile, "%s", aPrefix); 1.282 + fprintf(aFile, "<li> <a href="); 1.283 + DumpTextureHost(aFile, mTextureHostOnWhite); 1.284 + fprintf(aFile, "> Front buffer on white </a> </li> "); 1.285 + } 1.286 + fprintf(aFile, "</ul>"); 1.287 +} 1.288 +#endif 1.289 + 1.290 +static inline void 1.291 +AddWrappedRegion(const nsIntRegion& aInput, nsIntRegion& aOutput, 1.292 + const nsIntSize& aSize, const nsIntPoint& aShift) 1.293 +{ 1.294 + nsIntRegion tempRegion; 1.295 + tempRegion.And(nsIntRect(aShift, aSize), aInput); 1.296 + tempRegion.MoveBy(-aShift); 1.297 + aOutput.Or(aOutput, tempRegion); 1.298 +} 1.299 + 1.300 +bool 1.301 +ContentHostSingleBuffered::UpdateThebes(const ThebesBufferData& aData, 1.302 + const nsIntRegion& aUpdated, 1.303 + const nsIntRegion& aOldValidRegionBack, 1.304 + nsIntRegion* aUpdatedRegionBack) 1.305 +{ 1.306 + aUpdatedRegionBack->SetEmpty(); 1.307 + 1.308 + if (!mTextureHost) { 1.309 + mInitialised = false; 1.310 + return true; // FIXME should we return false? Returning true for now 1.311 + } // to preserve existing behavior of NOT causing IPC errors. 1.312 + 1.313 + // updated is in screen coordinates. Convert it to buffer coordinates. 1.314 + nsIntRegion destRegion(aUpdated); 1.315 + destRegion.MoveBy(-aData.rect().TopLeft()); 1.316 + 1.317 + if (!aData.rect().Contains(aUpdated.GetBounds()) || 1.318 + aData.rotation().x > aData.rect().width || 1.319 + aData.rotation().y > aData.rect().height) { 1.320 + NS_ERROR("Invalid update data"); 1.321 + return false; 1.322 + } 1.323 + 1.324 + // destRegion is now in logical coordinates relative to the buffer, but we 1.325 + // need to account for rotation. We do that by moving the region to the 1.326 + // rotation offset and then wrapping any pixels that extend off the 1.327 + // bottom/right edges. 1.328 + 1.329 + // Shift to the rotation point 1.330 + destRegion.MoveBy(aData.rotation()); 1.331 + 1.332 + nsIntSize bufferSize = aData.rect().Size(); 1.333 + 1.334 + // Select only the pixels that are still within the buffer. 1.335 + nsIntRegion finalRegion; 1.336 + finalRegion.And(nsIntRect(nsIntPoint(), bufferSize), destRegion); 1.337 + 1.338 + // For each of the overlap areas (right, bottom-right, bottom), select those 1.339 + // pixels and wrap them around to the opposite edge of the buffer rect. 1.340 + AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().width, 0)); 1.341 + AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().width, aData.rect().height)); 1.342 + AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(0, aData.rect().height)); 1.343 + 1.344 + MOZ_ASSERT(nsIntRect(0, 0, aData.rect().width, aData.rect().height).Contains(finalRegion.GetBounds())); 1.345 + 1.346 + mTextureHost->Updated(&finalRegion); 1.347 + if (mTextureHostOnWhite) { 1.348 + mTextureHostOnWhite->Updated(&finalRegion); 1.349 + } 1.350 + mInitialised = true; 1.351 + 1.352 + mBufferRect = aData.rect(); 1.353 + mBufferRotation = aData.rotation(); 1.354 + 1.355 + return true; 1.356 +} 1.357 + 1.358 +bool 1.359 +ContentHostDoubleBuffered::UpdateThebes(const ThebesBufferData& aData, 1.360 + const nsIntRegion& aUpdated, 1.361 + const nsIntRegion& aOldValidRegionBack, 1.362 + nsIntRegion* aUpdatedRegionBack) 1.363 +{ 1.364 + if (!mTextureHost) { 1.365 + mInitialised = false; 1.366 + 1.367 + *aUpdatedRegionBack = aUpdated; 1.368 + return true; 1.369 + } 1.370 + 1.371 + // We don't need to calculate an update region because we assume that if we 1.372 + // are using double buffering then we have render-to-texture and thus no 1.373 + // upload to do. 1.374 + mTextureHost->Updated(); 1.375 + if (mTextureHostOnWhite) { 1.376 + mTextureHostOnWhite->Updated(); 1.377 + } 1.378 + mInitialised = true; 1.379 + 1.380 + mBufferRect = aData.rect(); 1.381 + mBufferRotation = aData.rotation(); 1.382 + 1.383 + *aUpdatedRegionBack = aUpdated; 1.384 + 1.385 + // Save the current valid region of our front buffer, because if 1.386 + // we're double buffering, it's going to be the valid region for the 1.387 + // next back buffer sent back to the renderer. 1.388 + // 1.389 + // NB: we rely here on the fact that mValidRegion is initialized to 1.390 + // empty, and that the first time Swap() is called we don't have a 1.391 + // valid front buffer that we're going to return to content. 1.392 + mValidRegionForNextBackBuffer = aOldValidRegionBack; 1.393 + 1.394 + return true; 1.395 +} 1.396 + 1.397 +ContentHostIncremental::ContentHostIncremental(const TextureInfo& aTextureInfo) 1.398 + : ContentHostBase(aTextureInfo) 1.399 + , mDeAllocator(nullptr) 1.400 + , mLocked(false) 1.401 +{ 1.402 +} 1.403 + 1.404 +ContentHostIncremental::~ContentHostIncremental() 1.405 +{ 1.406 +} 1.407 + 1.408 +bool 1.409 +ContentHostIncremental::CreatedIncrementalTexture(ISurfaceAllocator* aAllocator, 1.410 + const TextureInfo& aTextureInfo, 1.411 + const nsIntRect& aBufferRect) 1.412 +{ 1.413 + mUpdateList.AppendElement(new TextureCreationRequest(aTextureInfo, 1.414 + aBufferRect)); 1.415 + mDeAllocator = aAllocator; 1.416 + FlushUpdateQueue(); 1.417 + return true; 1.418 +} 1.419 + 1.420 +void 1.421 +ContentHostIncremental::UpdateIncremental(TextureIdentifier aTextureId, 1.422 + SurfaceDescriptor& aSurface, 1.423 + const nsIntRegion& aUpdated, 1.424 + const nsIntRect& aBufferRect, 1.425 + const nsIntPoint& aBufferRotation) 1.426 +{ 1.427 + mUpdateList.AppendElement(new TextureUpdateRequest(mDeAllocator, 1.428 + aTextureId, 1.429 + aSurface, 1.430 + aUpdated, 1.431 + aBufferRect, 1.432 + aBufferRotation)); 1.433 + FlushUpdateQueue(); 1.434 +} 1.435 + 1.436 +void 1.437 +ContentHostIncremental::FlushUpdateQueue() 1.438 +{ 1.439 + // If we're not compositing for some reason (the window being minimized 1.440 + // is one example), then we never process these updates and it can consume 1.441 + // huge amounts of memory. Instead we forcibly process the updates (during the 1.442 + // transaction) if the list gets too long. 1.443 + static const uint32_t kMaxUpdateCount = 6; 1.444 + if (mUpdateList.Length() >= kMaxUpdateCount) { 1.445 + ProcessTextureUpdates(); 1.446 + } 1.447 +} 1.448 + 1.449 +void 1.450 +ContentHostIncremental::ProcessTextureUpdates() 1.451 +{ 1.452 + for (uint32_t i = 0; i < mUpdateList.Length(); i++) { 1.453 + mUpdateList[i]->Execute(this); 1.454 + } 1.455 + mUpdateList.Clear(); 1.456 +} 1.457 + 1.458 +NewTextureSource* 1.459 +ContentHostIncremental::GetTextureSource() 1.460 +{ 1.461 + MOZ_ASSERT(mLocked); 1.462 + return mSource; 1.463 +} 1.464 + 1.465 +NewTextureSource* 1.466 +ContentHostIncremental::GetTextureSourceOnWhite() 1.467 +{ 1.468 + MOZ_ASSERT(mLocked); 1.469 + return mSourceOnWhite; 1.470 +} 1.471 + 1.472 +void 1.473 +ContentHostIncremental::TextureCreationRequest::Execute(ContentHostIncremental* aHost) 1.474 +{ 1.475 + Compositor* compositor = aHost->GetCompositor(); 1.476 + MOZ_ASSERT(compositor); 1.477 + 1.478 + RefPtr<DataTextureSource> temp = 1.479 + compositor->CreateDataTextureSource(mTextureInfo.mTextureFlags); 1.480 + MOZ_ASSERT(temp->AsSourceOGL() && 1.481 + temp->AsSourceOGL()->AsTextureImageTextureSource()); 1.482 + RefPtr<TextureImageTextureSourceOGL> newSource = 1.483 + temp->AsSourceOGL()->AsTextureImageTextureSource(); 1.484 + 1.485 + RefPtr<TextureImageTextureSourceOGL> newSourceOnWhite; 1.486 + if (mTextureInfo.mTextureFlags & TEXTURE_COMPONENT_ALPHA) { 1.487 + temp = 1.488 + compositor->CreateDataTextureSource(mTextureInfo.mTextureFlags); 1.489 + MOZ_ASSERT(temp->AsSourceOGL() && 1.490 + temp->AsSourceOGL()->AsTextureImageTextureSource()); 1.491 + newSourceOnWhite = temp->AsSourceOGL()->AsTextureImageTextureSource(); 1.492 + } 1.493 + 1.494 + if (mTextureInfo.mDeprecatedTextureHostFlags & TEXTURE_HOST_COPY_PREVIOUS) { 1.495 + MOZ_ASSERT(aHost->mSource); 1.496 + MOZ_ASSERT(aHost->mSource->IsValid()); 1.497 + nsIntRect bufferRect = aHost->mBufferRect; 1.498 + nsIntPoint bufferRotation = aHost->mBufferRotation; 1.499 + nsIntRect overlap; 1.500 + 1.501 + // The buffer looks like: 1.502 + // ______ 1.503 + // |1 |2 | Where the center point is offset by mBufferRotation from the top-left corner. 1.504 + // |___|__| 1.505 + // |3 |4 | 1.506 + // |___|__| 1.507 + // 1.508 + // This is drawn to the screen as: 1.509 + // ______ 1.510 + // |4 |3 | Where the center point is { width - mBufferRotation.x, height - mBufferRotation.y } from 1.511 + // |___|__| from the top left corner - rotationPoint. 1.512 + // |2 |1 | 1.513 + // |___|__| 1.514 + // 1.515 + 1.516 + // The basic idea below is to take all quadrant rectangles from the src and transform them into rectangles 1.517 + // in the destination. Unfortunately, it seems it is overly complex and could perhaps be simplified. 1.518 + 1.519 + nsIntRect srcBufferSpaceBottomRight(bufferRotation.x, bufferRotation.y, bufferRect.width - bufferRotation.x, bufferRect.height - bufferRotation.y); 1.520 + nsIntRect srcBufferSpaceTopRight(bufferRotation.x, 0, bufferRect.width - bufferRotation.x, bufferRotation.y); 1.521 + nsIntRect srcBufferSpaceTopLeft(0, 0, bufferRotation.x, bufferRotation.y); 1.522 + nsIntRect srcBufferSpaceBottomLeft(0, bufferRotation.y, bufferRotation.x, bufferRect.height - bufferRotation.y); 1.523 + 1.524 + overlap.IntersectRect(bufferRect, mBufferRect); 1.525 + 1.526 + nsIntRect srcRect(overlap), dstRect(overlap); 1.527 + srcRect.MoveBy(- bufferRect.TopLeft() + bufferRotation); 1.528 + 1.529 + nsIntRect srcRectDrawTopRight(srcRect); 1.530 + nsIntRect srcRectDrawTopLeft(srcRect); 1.531 + nsIntRect srcRectDrawBottomLeft(srcRect); 1.532 + // transform into the different quadrants 1.533 + srcRectDrawTopRight .MoveBy(-nsIntPoint(0, bufferRect.height)); 1.534 + srcRectDrawTopLeft .MoveBy(-nsIntPoint(bufferRect.width, bufferRect.height)); 1.535 + srcRectDrawBottomLeft.MoveBy(-nsIntPoint(bufferRect.width, 0)); 1.536 + 1.537 + // Intersect with the quadrant 1.538 + srcRect = srcRect .Intersect(srcBufferSpaceBottomRight); 1.539 + srcRectDrawTopRight = srcRectDrawTopRight .Intersect(srcBufferSpaceTopRight); 1.540 + srcRectDrawTopLeft = srcRectDrawTopLeft .Intersect(srcBufferSpaceTopLeft); 1.541 + srcRectDrawBottomLeft = srcRectDrawBottomLeft.Intersect(srcBufferSpaceBottomLeft); 1.542 + 1.543 + dstRect = srcRect; 1.544 + nsIntRect dstRectDrawTopRight(srcRectDrawTopRight); 1.545 + nsIntRect dstRectDrawTopLeft(srcRectDrawTopLeft); 1.546 + nsIntRect dstRectDrawBottomLeft(srcRectDrawBottomLeft); 1.547 + 1.548 + // transform back to src buffer space 1.549 + dstRect .MoveBy(-bufferRotation); 1.550 + dstRectDrawTopRight .MoveBy(-bufferRotation + nsIntPoint(0, bufferRect.height)); 1.551 + dstRectDrawTopLeft .MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, bufferRect.height)); 1.552 + dstRectDrawBottomLeft.MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, 0)); 1.553 + 1.554 + // transform back to draw coordinates 1.555 + dstRect .MoveBy(bufferRect.TopLeft()); 1.556 + dstRectDrawTopRight .MoveBy(bufferRect.TopLeft()); 1.557 + dstRectDrawTopLeft .MoveBy(bufferRect.TopLeft()); 1.558 + dstRectDrawBottomLeft.MoveBy(bufferRect.TopLeft()); 1.559 + 1.560 + // transform to destBuffer space 1.561 + dstRect .MoveBy(-mBufferRect.TopLeft()); 1.562 + dstRectDrawTopRight .MoveBy(-mBufferRect.TopLeft()); 1.563 + dstRectDrawTopLeft .MoveBy(-mBufferRect.TopLeft()); 1.564 + dstRectDrawBottomLeft.MoveBy(-mBufferRect.TopLeft()); 1.565 + 1.566 + newSource->EnsureBuffer(mBufferRect.Size(), 1.567 + ContentForFormat(aHost->mSource->GetFormat())); 1.568 + 1.569 + aHost->mSource->CopyTo(srcRect, newSource, dstRect); 1.570 + if (bufferRotation != nsIntPoint(0, 0)) { 1.571 + // Draw the remaining quadrants. We call BlitTextureImage 3 extra 1.572 + // times instead of doing a single draw call because supporting that 1.573 + // with a tiled source is quite tricky. 1.574 + 1.575 + if (!srcRectDrawTopRight.IsEmpty()) 1.576 + aHost->mSource->CopyTo(srcRectDrawTopRight, 1.577 + newSource, dstRectDrawTopRight); 1.578 + if (!srcRectDrawTopLeft.IsEmpty()) 1.579 + aHost->mSource->CopyTo(srcRectDrawTopLeft, 1.580 + newSource, dstRectDrawTopLeft); 1.581 + if (!srcRectDrawBottomLeft.IsEmpty()) 1.582 + aHost->mSource->CopyTo(srcRectDrawBottomLeft, 1.583 + newSource, dstRectDrawBottomLeft); 1.584 + } 1.585 + 1.586 + if (newSourceOnWhite) { 1.587 + newSourceOnWhite->EnsureBuffer(mBufferRect.Size(), 1.588 + ContentForFormat(aHost->mSourceOnWhite->GetFormat())); 1.589 + aHost->mSourceOnWhite->CopyTo(srcRect, newSourceOnWhite, dstRect); 1.590 + if (bufferRotation != nsIntPoint(0, 0)) { 1.591 + // draw the remaining quadrants 1.592 + if (!srcRectDrawTopRight.IsEmpty()) 1.593 + aHost->mSourceOnWhite->CopyTo(srcRectDrawTopRight, 1.594 + newSourceOnWhite, dstRectDrawTopRight); 1.595 + if (!srcRectDrawTopLeft.IsEmpty()) 1.596 + aHost->mSourceOnWhite->CopyTo(srcRectDrawTopLeft, 1.597 + newSourceOnWhite, dstRectDrawTopLeft); 1.598 + if (!srcRectDrawBottomLeft.IsEmpty()) 1.599 + aHost->mSourceOnWhite->CopyTo(srcRectDrawBottomLeft, 1.600 + newSourceOnWhite, dstRectDrawBottomLeft); 1.601 + } 1.602 + } 1.603 + } 1.604 + 1.605 + aHost->mSource = newSource; 1.606 + aHost->mSourceOnWhite = newSourceOnWhite; 1.607 + 1.608 + aHost->mBufferRect = mBufferRect; 1.609 + aHost->mBufferRotation = nsIntPoint(); 1.610 +} 1.611 + 1.612 +nsIntRect 1.613 +ContentHostIncremental::TextureUpdateRequest::GetQuadrantRectangle(XSide aXSide, 1.614 + YSide aYSide) const 1.615 +{ 1.616 + // quadrantTranslation is the amount we translate the top-left 1.617 + // of the quadrant by to get coordinates relative to the layer 1.618 + nsIntPoint quadrantTranslation = -mBufferRotation; 1.619 + quadrantTranslation.x += aXSide == LEFT ? mBufferRect.width : 0; 1.620 + quadrantTranslation.y += aYSide == TOP ? mBufferRect.height : 0; 1.621 + return mBufferRect + quadrantTranslation; 1.622 +} 1.623 + 1.624 +void 1.625 +ContentHostIncremental::TextureUpdateRequest::Execute(ContentHostIncremental* aHost) 1.626 +{ 1.627 + nsIntRect drawBounds = mUpdated.GetBounds(); 1.628 + 1.629 + aHost->mBufferRect = mBufferRect; 1.630 + aHost->mBufferRotation = mBufferRotation; 1.631 + 1.632 + // Figure out which quadrant to draw in 1.633 + int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x; 1.634 + int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y; 1.635 + XSide sideX = drawBounds.XMost() <= xBoundary ? RIGHT : LEFT; 1.636 + YSide sideY = drawBounds.YMost() <= yBoundary ? BOTTOM : TOP; 1.637 + nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY); 1.638 + NS_ASSERTION(quadrantRect.Contains(drawBounds), "Messed up quadrants"); 1.639 + 1.640 + mUpdated.MoveBy(-nsIntPoint(quadrantRect.x, quadrantRect.y)); 1.641 + 1.642 + IntPoint offset = ToIntPoint(-mUpdated.GetBounds().TopLeft()); 1.643 + 1.644 + RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(mDescriptor); 1.645 + 1.646 + if (mTextureId == TextureFront) { 1.647 + aHost->mSource->Update(surf, &mUpdated, &offset); 1.648 + } else { 1.649 + aHost->mSourceOnWhite->Update(surf, &mUpdated, &offset); 1.650 + } 1.651 +} 1.652 + 1.653 +void 1.654 +ContentHostTexture::PrintInfo(nsACString& aTo, const char* aPrefix) 1.655 +{ 1.656 + aTo += aPrefix; 1.657 + aTo += nsPrintfCString("ContentHost (0x%p)", this); 1.658 + 1.659 + AppendToString(aTo, mBufferRect, " [buffer-rect=", "]"); 1.660 + AppendToString(aTo, mBufferRotation, " [buffer-rotation=", "]"); 1.661 + if (PaintWillResample()) { 1.662 + aTo += " [paint-will-resample]"; 1.663 + } 1.664 + 1.665 + nsAutoCString pfx(aPrefix); 1.666 + pfx += " "; 1.667 + 1.668 + if (mTextureHost) { 1.669 + aTo += "\n"; 1.670 + mTextureHost->PrintInfo(aTo, pfx.get()); 1.671 + } 1.672 +} 1.673 + 1.674 + 1.675 +LayerRenderState 1.676 +ContentHostTexture::GetRenderState() 1.677 +{ 1.678 + if (!mTextureHost) { 1.679 + return LayerRenderState(); 1.680 + } 1.681 + 1.682 + LayerRenderState result = mTextureHost->GetRenderState(); 1.683 + 1.684 + if (mBufferRotation != nsIntPoint()) { 1.685 + result.mFlags |= LAYER_RENDER_STATE_BUFFER_ROTATION; 1.686 + } 1.687 + result.SetOffset(GetOriginOffset()); 1.688 + return result; 1.689 +} 1.690 + 1.691 +#ifdef MOZ_DUMP_PAINTING 1.692 +TemporaryRef<gfx::DataSourceSurface> 1.693 +ContentHostTexture::GetAsSurface() 1.694 +{ 1.695 + if (!mTextureHost) { 1.696 + return nullptr; 1.697 + } 1.698 + 1.699 + return mTextureHost->GetAsSurface(); 1.700 +} 1.701 + 1.702 +#endif 1.703 + 1.704 + 1.705 +} // namespace 1.706 +} // namespace