gfx/layers/composite/ContentHost.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "mozilla/layers/ContentHost.h"
michael@0 7 #include "LayersLogging.h" // for AppendToString
michael@0 8 #include "gfx2DGlue.h" // for ContentForFormat
michael@0 9 #include "mozilla/gfx/Point.h" // for IntSize
michael@0 10 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
michael@0 11 #include "mozilla/gfx/BaseRect.h" // for BaseRect
michael@0 12 #include "mozilla/layers/Compositor.h" // for Compositor
michael@0 13 #include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
michael@0 14 #include "mozilla/layers/LayersMessages.h" // for ThebesBufferData
michael@0 15 #include "nsAString.h"
michael@0 16 #include "nsPrintfCString.h" // for nsPrintfCString
michael@0 17 #include "nsString.h" // for nsAutoCString
michael@0 18 #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
michael@0 19
michael@0 20 namespace mozilla {
michael@0 21 namespace gfx {
michael@0 22 class Matrix4x4;
michael@0 23 }
michael@0 24 using namespace gfx;
michael@0 25
michael@0 26 namespace layers {
michael@0 27
michael@0 28 ContentHostBase::ContentHostBase(const TextureInfo& aTextureInfo)
michael@0 29 : ContentHost(aTextureInfo)
michael@0 30 , mPaintWillResample(false)
michael@0 31 , mInitialised(false)
michael@0 32 {}
michael@0 33
michael@0 34 ContentHostBase::~ContentHostBase()
michael@0 35 {
michael@0 36 }
michael@0 37
michael@0 38 struct AutoLockContentHost
michael@0 39 {
michael@0 40 AutoLockContentHost(ContentHostBase* aHost)
michael@0 41 : mHost(aHost)
michael@0 42 {
michael@0 43 mSucceeded = mHost->Lock();
michael@0 44 }
michael@0 45
michael@0 46 ~AutoLockContentHost()
michael@0 47 {
michael@0 48 if (mSucceeded) {
michael@0 49 mHost->Unlock();
michael@0 50 }
michael@0 51 }
michael@0 52
michael@0 53 bool Failed() { return !mSucceeded; }
michael@0 54
michael@0 55 ContentHostBase* mHost;
michael@0 56 bool mSucceeded;
michael@0 57 };
michael@0 58
michael@0 59 void
michael@0 60 ContentHostBase::Composite(EffectChain& aEffectChain,
michael@0 61 float aOpacity,
michael@0 62 const gfx::Matrix4x4& aTransform,
michael@0 63 const Filter& aFilter,
michael@0 64 const Rect& aClipRect,
michael@0 65 const nsIntRegion* aVisibleRegion,
michael@0 66 TiledLayerProperties* aLayerProperties)
michael@0 67 {
michael@0 68 NS_ASSERTION(aVisibleRegion, "Requires a visible region");
michael@0 69
michael@0 70 AutoLockContentHost lock(this);
michael@0 71 if (lock.Failed()) {
michael@0 72 return;
michael@0 73 }
michael@0 74
michael@0 75 RefPtr<NewTextureSource> source = GetTextureSource();
michael@0 76 RefPtr<NewTextureSource> sourceOnWhite = GetTextureSourceOnWhite();
michael@0 77
michael@0 78 if (!source) {
michael@0 79 return;
michael@0 80 }
michael@0 81 RefPtr<TexturedEffect> effect =
michael@0 82 CreateTexturedEffect(source, sourceOnWhite, aFilter);
michael@0 83
michael@0 84 if (!effect) {
michael@0 85 return;
michael@0 86 }
michael@0 87
michael@0 88 aEffectChain.mPrimaryEffect = effect;
michael@0 89
michael@0 90 nsIntRegion tmpRegion;
michael@0 91 const nsIntRegion* renderRegion;
michael@0 92 if (PaintWillResample()) {
michael@0 93 // If we're resampling, then the texture image will contain exactly the
michael@0 94 // entire visible region's bounds, and we should draw it all in one quad
michael@0 95 // to avoid unexpected aliasing.
michael@0 96 tmpRegion = aVisibleRegion->GetBounds();
michael@0 97 renderRegion = &tmpRegion;
michael@0 98 } else {
michael@0 99 renderRegion = aVisibleRegion;
michael@0 100 }
michael@0 101
michael@0 102 nsIntRegion region(*renderRegion);
michael@0 103 nsIntPoint origin = GetOriginOffset();
michael@0 104 // translate into TexImage space, buffer origin might not be at texture (0,0)
michael@0 105 region.MoveBy(-origin);
michael@0 106
michael@0 107 // Figure out the intersecting draw region
michael@0 108 gfx::IntSize texSize = source->GetSize();
michael@0 109 nsIntRect textureRect = nsIntRect(0, 0, texSize.width, texSize.height);
michael@0 110 textureRect.MoveBy(region.GetBounds().TopLeft());
michael@0 111 nsIntRegion subregion;
michael@0 112 subregion.And(region, textureRect);
michael@0 113 if (subregion.IsEmpty()) {
michael@0 114 // Region is empty, nothing to draw
michael@0 115 return;
michael@0 116 }
michael@0 117
michael@0 118 nsIntRegion screenRects;
michael@0 119 nsIntRegion regionRects;
michael@0 120
michael@0 121 // Collect texture/screen coordinates for drawing
michael@0 122 nsIntRegionRectIterator iter(subregion);
michael@0 123 while (const nsIntRect* iterRect = iter.Next()) {
michael@0 124 nsIntRect regionRect = *iterRect;
michael@0 125 nsIntRect screenRect = regionRect;
michael@0 126 screenRect.MoveBy(origin);
michael@0 127
michael@0 128 screenRects.Or(screenRects, screenRect);
michael@0 129 regionRects.Or(regionRects, regionRect);
michael@0 130 }
michael@0 131
michael@0 132 TileIterator* tileIter = source->AsTileIterator();
michael@0 133 TileIterator* iterOnWhite = nullptr;
michael@0 134 if (tileIter) {
michael@0 135 tileIter->BeginTileIteration();
michael@0 136 }
michael@0 137
michael@0 138 if (sourceOnWhite) {
michael@0 139 iterOnWhite = sourceOnWhite->AsTileIterator();
michael@0 140 MOZ_ASSERT(!tileIter || tileIter->GetTileCount() == iterOnWhite->GetTileCount(),
michael@0 141 "Tile count mismatch on component alpha texture");
michael@0 142 if (iterOnWhite) {
michael@0 143 iterOnWhite->BeginTileIteration();
michael@0 144 }
michael@0 145 }
michael@0 146
michael@0 147 bool usingTiles = (tileIter && tileIter->GetTileCount() > 1);
michael@0 148 do {
michael@0 149 if (iterOnWhite) {
michael@0 150 MOZ_ASSERT(iterOnWhite->GetTileRect() == tileIter->GetTileRect(),
michael@0 151 "component alpha textures should be the same size.");
michael@0 152 }
michael@0 153
michael@0 154 nsIntRect texRect = tileIter ? tileIter->GetTileRect()
michael@0 155 : nsIntRect(0, 0,
michael@0 156 texSize.width,
michael@0 157 texSize.height);
michael@0 158
michael@0 159 // Draw texture. If we're using tiles, we do repeating manually, as texture
michael@0 160 // repeat would cause each individual tile to repeat instead of the
michael@0 161 // compound texture as a whole. This involves drawing at most 4 sections,
michael@0 162 // 2 for each axis that has texture repeat.
michael@0 163 for (int y = 0; y < (usingTiles ? 2 : 1); y++) {
michael@0 164 for (int x = 0; x < (usingTiles ? 2 : 1); x++) {
michael@0 165 nsIntRect currentTileRect(texRect);
michael@0 166 currentTileRect.MoveBy(x * texSize.width, y * texSize.height);
michael@0 167
michael@0 168 nsIntRegionRectIterator screenIter(screenRects);
michael@0 169 nsIntRegionRectIterator regionIter(regionRects);
michael@0 170
michael@0 171 const nsIntRect* screenRect;
michael@0 172 const nsIntRect* regionRect;
michael@0 173 while ((screenRect = screenIter.Next()) &&
michael@0 174 (regionRect = regionIter.Next())) {
michael@0 175 nsIntRect tileScreenRect(*screenRect);
michael@0 176 nsIntRect tileRegionRect(*regionRect);
michael@0 177
michael@0 178 // When we're using tiles, find the intersection between the tile
michael@0 179 // rect and this region rect. Tiling is then handled by the
michael@0 180 // outer for-loops and modifying the tile rect.
michael@0 181 if (usingTiles) {
michael@0 182 tileScreenRect.MoveBy(-origin);
michael@0 183 tileScreenRect = tileScreenRect.Intersect(currentTileRect);
michael@0 184 tileScreenRect.MoveBy(origin);
michael@0 185
michael@0 186 if (tileScreenRect.IsEmpty())
michael@0 187 continue;
michael@0 188
michael@0 189 tileRegionRect = regionRect->Intersect(currentTileRect);
michael@0 190 tileRegionRect.MoveBy(-currentTileRect.TopLeft());
michael@0 191 }
michael@0 192 gfx::Rect rect(tileScreenRect.x, tileScreenRect.y,
michael@0 193 tileScreenRect.width, tileScreenRect.height);
michael@0 194
michael@0 195 effect->mTextureCoords = Rect(Float(tileRegionRect.x) / texRect.width,
michael@0 196 Float(tileRegionRect.y) / texRect.height,
michael@0 197 Float(tileRegionRect.width) / texRect.width,
michael@0 198 Float(tileRegionRect.height) / texRect.height);
michael@0 199 GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, aOpacity, aTransform);
michael@0 200 if (usingTiles) {
michael@0 201 DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT | DIAGNOSTIC_BIGIMAGE;
michael@0 202 diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0;
michael@0 203 GetCompositor()->DrawDiagnostics(diagnostics, rect, aClipRect,
michael@0 204 aTransform, mFlashCounter);
michael@0 205 }
michael@0 206 }
michael@0 207 }
michael@0 208 }
michael@0 209
michael@0 210 if (iterOnWhite) {
michael@0 211 iterOnWhite->NextTile();
michael@0 212 }
michael@0 213 } while (usingTiles && tileIter->NextTile());
michael@0 214
michael@0 215 if (tileIter) {
michael@0 216 tileIter->EndTileIteration();
michael@0 217 }
michael@0 218 if (iterOnWhite) {
michael@0 219 iterOnWhite->EndTileIteration();
michael@0 220 }
michael@0 221
michael@0 222 DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT;
michael@0 223 diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0;
michael@0 224 GetCompositor()->DrawDiagnostics(diagnostics, *aVisibleRegion, aClipRect,
michael@0 225 aTransform, mFlashCounter);
michael@0 226 }
michael@0 227
michael@0 228
michael@0 229 void
michael@0 230 ContentHostTexture::UseTextureHost(TextureHost* aTexture)
michael@0 231 {
michael@0 232 ContentHostBase::UseTextureHost(aTexture);
michael@0 233 mTextureHost = aTexture;
michael@0 234 mTextureHostOnWhite = nullptr;
michael@0 235 }
michael@0 236
michael@0 237 void
michael@0 238 ContentHostTexture::UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
michael@0 239 TextureHost* aTextureOnWhite)
michael@0 240 {
michael@0 241 ContentHostBase::UseComponentAlphaTextures(aTextureOnBlack, aTextureOnWhite);
michael@0 242 mTextureHost = aTextureOnBlack;
michael@0 243 mTextureHostOnWhite = aTextureOnWhite;
michael@0 244 }
michael@0 245
michael@0 246 void
michael@0 247 ContentHostTexture::SetCompositor(Compositor* aCompositor)
michael@0 248 {
michael@0 249 ContentHostBase::SetCompositor(aCompositor);
michael@0 250 if (mTextureHost) {
michael@0 251 mTextureHost->SetCompositor(aCompositor);
michael@0 252 }
michael@0 253 if (mTextureHostOnWhite) {
michael@0 254 mTextureHostOnWhite->SetCompositor(aCompositor);
michael@0 255 }
michael@0 256 }
michael@0 257
michael@0 258 #ifdef MOZ_DUMP_PAINTING
michael@0 259 void
michael@0 260 ContentHostTexture::Dump(FILE* aFile,
michael@0 261 const char* aPrefix,
michael@0 262 bool aDumpHtml)
michael@0 263 {
michael@0 264 if (!aDumpHtml) {
michael@0 265 return;
michael@0 266 }
michael@0 267 if (!aFile) {
michael@0 268 aFile = stderr;
michael@0 269 }
michael@0 270 fprintf(aFile, "<ul>");
michael@0 271 if (mTextureHost) {
michael@0 272 fprintf(aFile, "%s", aPrefix);
michael@0 273 fprintf(aFile, "<li> <a href=");
michael@0 274 DumpTextureHost(aFile, mTextureHost);
michael@0 275 fprintf(aFile, "> Front buffer </a></li> ");
michael@0 276 }
michael@0 277 if (mTextureHostOnWhite) {
michael@0 278 fprintf(aFile, "%s", aPrefix);
michael@0 279 fprintf(aFile, "<li> <a href=");
michael@0 280 DumpTextureHost(aFile, mTextureHostOnWhite);
michael@0 281 fprintf(aFile, "> Front buffer on white </a> </li> ");
michael@0 282 }
michael@0 283 fprintf(aFile, "</ul>");
michael@0 284 }
michael@0 285 #endif
michael@0 286
michael@0 287 static inline void
michael@0 288 AddWrappedRegion(const nsIntRegion& aInput, nsIntRegion& aOutput,
michael@0 289 const nsIntSize& aSize, const nsIntPoint& aShift)
michael@0 290 {
michael@0 291 nsIntRegion tempRegion;
michael@0 292 tempRegion.And(nsIntRect(aShift, aSize), aInput);
michael@0 293 tempRegion.MoveBy(-aShift);
michael@0 294 aOutput.Or(aOutput, tempRegion);
michael@0 295 }
michael@0 296
michael@0 297 bool
michael@0 298 ContentHostSingleBuffered::UpdateThebes(const ThebesBufferData& aData,
michael@0 299 const nsIntRegion& aUpdated,
michael@0 300 const nsIntRegion& aOldValidRegionBack,
michael@0 301 nsIntRegion* aUpdatedRegionBack)
michael@0 302 {
michael@0 303 aUpdatedRegionBack->SetEmpty();
michael@0 304
michael@0 305 if (!mTextureHost) {
michael@0 306 mInitialised = false;
michael@0 307 return true; // FIXME should we return false? Returning true for now
michael@0 308 } // to preserve existing behavior of NOT causing IPC errors.
michael@0 309
michael@0 310 // updated is in screen coordinates. Convert it to buffer coordinates.
michael@0 311 nsIntRegion destRegion(aUpdated);
michael@0 312 destRegion.MoveBy(-aData.rect().TopLeft());
michael@0 313
michael@0 314 if (!aData.rect().Contains(aUpdated.GetBounds()) ||
michael@0 315 aData.rotation().x > aData.rect().width ||
michael@0 316 aData.rotation().y > aData.rect().height) {
michael@0 317 NS_ERROR("Invalid update data");
michael@0 318 return false;
michael@0 319 }
michael@0 320
michael@0 321 // destRegion is now in logical coordinates relative to the buffer, but we
michael@0 322 // need to account for rotation. We do that by moving the region to the
michael@0 323 // rotation offset and then wrapping any pixels that extend off the
michael@0 324 // bottom/right edges.
michael@0 325
michael@0 326 // Shift to the rotation point
michael@0 327 destRegion.MoveBy(aData.rotation());
michael@0 328
michael@0 329 nsIntSize bufferSize = aData.rect().Size();
michael@0 330
michael@0 331 // Select only the pixels that are still within the buffer.
michael@0 332 nsIntRegion finalRegion;
michael@0 333 finalRegion.And(nsIntRect(nsIntPoint(), bufferSize), destRegion);
michael@0 334
michael@0 335 // For each of the overlap areas (right, bottom-right, bottom), select those
michael@0 336 // pixels and wrap them around to the opposite edge of the buffer rect.
michael@0 337 AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().width, 0));
michael@0 338 AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().width, aData.rect().height));
michael@0 339 AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(0, aData.rect().height));
michael@0 340
michael@0 341 MOZ_ASSERT(nsIntRect(0, 0, aData.rect().width, aData.rect().height).Contains(finalRegion.GetBounds()));
michael@0 342
michael@0 343 mTextureHost->Updated(&finalRegion);
michael@0 344 if (mTextureHostOnWhite) {
michael@0 345 mTextureHostOnWhite->Updated(&finalRegion);
michael@0 346 }
michael@0 347 mInitialised = true;
michael@0 348
michael@0 349 mBufferRect = aData.rect();
michael@0 350 mBufferRotation = aData.rotation();
michael@0 351
michael@0 352 return true;
michael@0 353 }
michael@0 354
michael@0 355 bool
michael@0 356 ContentHostDoubleBuffered::UpdateThebes(const ThebesBufferData& aData,
michael@0 357 const nsIntRegion& aUpdated,
michael@0 358 const nsIntRegion& aOldValidRegionBack,
michael@0 359 nsIntRegion* aUpdatedRegionBack)
michael@0 360 {
michael@0 361 if (!mTextureHost) {
michael@0 362 mInitialised = false;
michael@0 363
michael@0 364 *aUpdatedRegionBack = aUpdated;
michael@0 365 return true;
michael@0 366 }
michael@0 367
michael@0 368 // We don't need to calculate an update region because we assume that if we
michael@0 369 // are using double buffering then we have render-to-texture and thus no
michael@0 370 // upload to do.
michael@0 371 mTextureHost->Updated();
michael@0 372 if (mTextureHostOnWhite) {
michael@0 373 mTextureHostOnWhite->Updated();
michael@0 374 }
michael@0 375 mInitialised = true;
michael@0 376
michael@0 377 mBufferRect = aData.rect();
michael@0 378 mBufferRotation = aData.rotation();
michael@0 379
michael@0 380 *aUpdatedRegionBack = aUpdated;
michael@0 381
michael@0 382 // Save the current valid region of our front buffer, because if
michael@0 383 // we're double buffering, it's going to be the valid region for the
michael@0 384 // next back buffer sent back to the renderer.
michael@0 385 //
michael@0 386 // NB: we rely here on the fact that mValidRegion is initialized to
michael@0 387 // empty, and that the first time Swap() is called we don't have a
michael@0 388 // valid front buffer that we're going to return to content.
michael@0 389 mValidRegionForNextBackBuffer = aOldValidRegionBack;
michael@0 390
michael@0 391 return true;
michael@0 392 }
michael@0 393
michael@0 394 ContentHostIncremental::ContentHostIncremental(const TextureInfo& aTextureInfo)
michael@0 395 : ContentHostBase(aTextureInfo)
michael@0 396 , mDeAllocator(nullptr)
michael@0 397 , mLocked(false)
michael@0 398 {
michael@0 399 }
michael@0 400
michael@0 401 ContentHostIncremental::~ContentHostIncremental()
michael@0 402 {
michael@0 403 }
michael@0 404
michael@0 405 bool
michael@0 406 ContentHostIncremental::CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
michael@0 407 const TextureInfo& aTextureInfo,
michael@0 408 const nsIntRect& aBufferRect)
michael@0 409 {
michael@0 410 mUpdateList.AppendElement(new TextureCreationRequest(aTextureInfo,
michael@0 411 aBufferRect));
michael@0 412 mDeAllocator = aAllocator;
michael@0 413 FlushUpdateQueue();
michael@0 414 return true;
michael@0 415 }
michael@0 416
michael@0 417 void
michael@0 418 ContentHostIncremental::UpdateIncremental(TextureIdentifier aTextureId,
michael@0 419 SurfaceDescriptor& aSurface,
michael@0 420 const nsIntRegion& aUpdated,
michael@0 421 const nsIntRect& aBufferRect,
michael@0 422 const nsIntPoint& aBufferRotation)
michael@0 423 {
michael@0 424 mUpdateList.AppendElement(new TextureUpdateRequest(mDeAllocator,
michael@0 425 aTextureId,
michael@0 426 aSurface,
michael@0 427 aUpdated,
michael@0 428 aBufferRect,
michael@0 429 aBufferRotation));
michael@0 430 FlushUpdateQueue();
michael@0 431 }
michael@0 432
michael@0 433 void
michael@0 434 ContentHostIncremental::FlushUpdateQueue()
michael@0 435 {
michael@0 436 // If we're not compositing for some reason (the window being minimized
michael@0 437 // is one example), then we never process these updates and it can consume
michael@0 438 // huge amounts of memory. Instead we forcibly process the updates (during the
michael@0 439 // transaction) if the list gets too long.
michael@0 440 static const uint32_t kMaxUpdateCount = 6;
michael@0 441 if (mUpdateList.Length() >= kMaxUpdateCount) {
michael@0 442 ProcessTextureUpdates();
michael@0 443 }
michael@0 444 }
michael@0 445
michael@0 446 void
michael@0 447 ContentHostIncremental::ProcessTextureUpdates()
michael@0 448 {
michael@0 449 for (uint32_t i = 0; i < mUpdateList.Length(); i++) {
michael@0 450 mUpdateList[i]->Execute(this);
michael@0 451 }
michael@0 452 mUpdateList.Clear();
michael@0 453 }
michael@0 454
michael@0 455 NewTextureSource*
michael@0 456 ContentHostIncremental::GetTextureSource()
michael@0 457 {
michael@0 458 MOZ_ASSERT(mLocked);
michael@0 459 return mSource;
michael@0 460 }
michael@0 461
michael@0 462 NewTextureSource*
michael@0 463 ContentHostIncremental::GetTextureSourceOnWhite()
michael@0 464 {
michael@0 465 MOZ_ASSERT(mLocked);
michael@0 466 return mSourceOnWhite;
michael@0 467 }
michael@0 468
michael@0 469 void
michael@0 470 ContentHostIncremental::TextureCreationRequest::Execute(ContentHostIncremental* aHost)
michael@0 471 {
michael@0 472 Compositor* compositor = aHost->GetCompositor();
michael@0 473 MOZ_ASSERT(compositor);
michael@0 474
michael@0 475 RefPtr<DataTextureSource> temp =
michael@0 476 compositor->CreateDataTextureSource(mTextureInfo.mTextureFlags);
michael@0 477 MOZ_ASSERT(temp->AsSourceOGL() &&
michael@0 478 temp->AsSourceOGL()->AsTextureImageTextureSource());
michael@0 479 RefPtr<TextureImageTextureSourceOGL> newSource =
michael@0 480 temp->AsSourceOGL()->AsTextureImageTextureSource();
michael@0 481
michael@0 482 RefPtr<TextureImageTextureSourceOGL> newSourceOnWhite;
michael@0 483 if (mTextureInfo.mTextureFlags & TEXTURE_COMPONENT_ALPHA) {
michael@0 484 temp =
michael@0 485 compositor->CreateDataTextureSource(mTextureInfo.mTextureFlags);
michael@0 486 MOZ_ASSERT(temp->AsSourceOGL() &&
michael@0 487 temp->AsSourceOGL()->AsTextureImageTextureSource());
michael@0 488 newSourceOnWhite = temp->AsSourceOGL()->AsTextureImageTextureSource();
michael@0 489 }
michael@0 490
michael@0 491 if (mTextureInfo.mDeprecatedTextureHostFlags & TEXTURE_HOST_COPY_PREVIOUS) {
michael@0 492 MOZ_ASSERT(aHost->mSource);
michael@0 493 MOZ_ASSERT(aHost->mSource->IsValid());
michael@0 494 nsIntRect bufferRect = aHost->mBufferRect;
michael@0 495 nsIntPoint bufferRotation = aHost->mBufferRotation;
michael@0 496 nsIntRect overlap;
michael@0 497
michael@0 498 // The buffer looks like:
michael@0 499 // ______
michael@0 500 // |1 |2 | Where the center point is offset by mBufferRotation from the top-left corner.
michael@0 501 // |___|__|
michael@0 502 // |3 |4 |
michael@0 503 // |___|__|
michael@0 504 //
michael@0 505 // This is drawn to the screen as:
michael@0 506 // ______
michael@0 507 // |4 |3 | Where the center point is { width - mBufferRotation.x, height - mBufferRotation.y } from
michael@0 508 // |___|__| from the top left corner - rotationPoint.
michael@0 509 // |2 |1 |
michael@0 510 // |___|__|
michael@0 511 //
michael@0 512
michael@0 513 // The basic idea below is to take all quadrant rectangles from the src and transform them into rectangles
michael@0 514 // in the destination. Unfortunately, it seems it is overly complex and could perhaps be simplified.
michael@0 515
michael@0 516 nsIntRect srcBufferSpaceBottomRight(bufferRotation.x, bufferRotation.y, bufferRect.width - bufferRotation.x, bufferRect.height - bufferRotation.y);
michael@0 517 nsIntRect srcBufferSpaceTopRight(bufferRotation.x, 0, bufferRect.width - bufferRotation.x, bufferRotation.y);
michael@0 518 nsIntRect srcBufferSpaceTopLeft(0, 0, bufferRotation.x, bufferRotation.y);
michael@0 519 nsIntRect srcBufferSpaceBottomLeft(0, bufferRotation.y, bufferRotation.x, bufferRect.height - bufferRotation.y);
michael@0 520
michael@0 521 overlap.IntersectRect(bufferRect, mBufferRect);
michael@0 522
michael@0 523 nsIntRect srcRect(overlap), dstRect(overlap);
michael@0 524 srcRect.MoveBy(- bufferRect.TopLeft() + bufferRotation);
michael@0 525
michael@0 526 nsIntRect srcRectDrawTopRight(srcRect);
michael@0 527 nsIntRect srcRectDrawTopLeft(srcRect);
michael@0 528 nsIntRect srcRectDrawBottomLeft(srcRect);
michael@0 529 // transform into the different quadrants
michael@0 530 srcRectDrawTopRight .MoveBy(-nsIntPoint(0, bufferRect.height));
michael@0 531 srcRectDrawTopLeft .MoveBy(-nsIntPoint(bufferRect.width, bufferRect.height));
michael@0 532 srcRectDrawBottomLeft.MoveBy(-nsIntPoint(bufferRect.width, 0));
michael@0 533
michael@0 534 // Intersect with the quadrant
michael@0 535 srcRect = srcRect .Intersect(srcBufferSpaceBottomRight);
michael@0 536 srcRectDrawTopRight = srcRectDrawTopRight .Intersect(srcBufferSpaceTopRight);
michael@0 537 srcRectDrawTopLeft = srcRectDrawTopLeft .Intersect(srcBufferSpaceTopLeft);
michael@0 538 srcRectDrawBottomLeft = srcRectDrawBottomLeft.Intersect(srcBufferSpaceBottomLeft);
michael@0 539
michael@0 540 dstRect = srcRect;
michael@0 541 nsIntRect dstRectDrawTopRight(srcRectDrawTopRight);
michael@0 542 nsIntRect dstRectDrawTopLeft(srcRectDrawTopLeft);
michael@0 543 nsIntRect dstRectDrawBottomLeft(srcRectDrawBottomLeft);
michael@0 544
michael@0 545 // transform back to src buffer space
michael@0 546 dstRect .MoveBy(-bufferRotation);
michael@0 547 dstRectDrawTopRight .MoveBy(-bufferRotation + nsIntPoint(0, bufferRect.height));
michael@0 548 dstRectDrawTopLeft .MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, bufferRect.height));
michael@0 549 dstRectDrawBottomLeft.MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, 0));
michael@0 550
michael@0 551 // transform back to draw coordinates
michael@0 552 dstRect .MoveBy(bufferRect.TopLeft());
michael@0 553 dstRectDrawTopRight .MoveBy(bufferRect.TopLeft());
michael@0 554 dstRectDrawTopLeft .MoveBy(bufferRect.TopLeft());
michael@0 555 dstRectDrawBottomLeft.MoveBy(bufferRect.TopLeft());
michael@0 556
michael@0 557 // transform to destBuffer space
michael@0 558 dstRect .MoveBy(-mBufferRect.TopLeft());
michael@0 559 dstRectDrawTopRight .MoveBy(-mBufferRect.TopLeft());
michael@0 560 dstRectDrawTopLeft .MoveBy(-mBufferRect.TopLeft());
michael@0 561 dstRectDrawBottomLeft.MoveBy(-mBufferRect.TopLeft());
michael@0 562
michael@0 563 newSource->EnsureBuffer(mBufferRect.Size(),
michael@0 564 ContentForFormat(aHost->mSource->GetFormat()));
michael@0 565
michael@0 566 aHost->mSource->CopyTo(srcRect, newSource, dstRect);
michael@0 567 if (bufferRotation != nsIntPoint(0, 0)) {
michael@0 568 // Draw the remaining quadrants. We call BlitTextureImage 3 extra
michael@0 569 // times instead of doing a single draw call because supporting that
michael@0 570 // with a tiled source is quite tricky.
michael@0 571
michael@0 572 if (!srcRectDrawTopRight.IsEmpty())
michael@0 573 aHost->mSource->CopyTo(srcRectDrawTopRight,
michael@0 574 newSource, dstRectDrawTopRight);
michael@0 575 if (!srcRectDrawTopLeft.IsEmpty())
michael@0 576 aHost->mSource->CopyTo(srcRectDrawTopLeft,
michael@0 577 newSource, dstRectDrawTopLeft);
michael@0 578 if (!srcRectDrawBottomLeft.IsEmpty())
michael@0 579 aHost->mSource->CopyTo(srcRectDrawBottomLeft,
michael@0 580 newSource, dstRectDrawBottomLeft);
michael@0 581 }
michael@0 582
michael@0 583 if (newSourceOnWhite) {
michael@0 584 newSourceOnWhite->EnsureBuffer(mBufferRect.Size(),
michael@0 585 ContentForFormat(aHost->mSourceOnWhite->GetFormat()));
michael@0 586 aHost->mSourceOnWhite->CopyTo(srcRect, newSourceOnWhite, dstRect);
michael@0 587 if (bufferRotation != nsIntPoint(0, 0)) {
michael@0 588 // draw the remaining quadrants
michael@0 589 if (!srcRectDrawTopRight.IsEmpty())
michael@0 590 aHost->mSourceOnWhite->CopyTo(srcRectDrawTopRight,
michael@0 591 newSourceOnWhite, dstRectDrawTopRight);
michael@0 592 if (!srcRectDrawTopLeft.IsEmpty())
michael@0 593 aHost->mSourceOnWhite->CopyTo(srcRectDrawTopLeft,
michael@0 594 newSourceOnWhite, dstRectDrawTopLeft);
michael@0 595 if (!srcRectDrawBottomLeft.IsEmpty())
michael@0 596 aHost->mSourceOnWhite->CopyTo(srcRectDrawBottomLeft,
michael@0 597 newSourceOnWhite, dstRectDrawBottomLeft);
michael@0 598 }
michael@0 599 }
michael@0 600 }
michael@0 601
michael@0 602 aHost->mSource = newSource;
michael@0 603 aHost->mSourceOnWhite = newSourceOnWhite;
michael@0 604
michael@0 605 aHost->mBufferRect = mBufferRect;
michael@0 606 aHost->mBufferRotation = nsIntPoint();
michael@0 607 }
michael@0 608
michael@0 609 nsIntRect
michael@0 610 ContentHostIncremental::TextureUpdateRequest::GetQuadrantRectangle(XSide aXSide,
michael@0 611 YSide aYSide) const
michael@0 612 {
michael@0 613 // quadrantTranslation is the amount we translate the top-left
michael@0 614 // of the quadrant by to get coordinates relative to the layer
michael@0 615 nsIntPoint quadrantTranslation = -mBufferRotation;
michael@0 616 quadrantTranslation.x += aXSide == LEFT ? mBufferRect.width : 0;
michael@0 617 quadrantTranslation.y += aYSide == TOP ? mBufferRect.height : 0;
michael@0 618 return mBufferRect + quadrantTranslation;
michael@0 619 }
michael@0 620
michael@0 621 void
michael@0 622 ContentHostIncremental::TextureUpdateRequest::Execute(ContentHostIncremental* aHost)
michael@0 623 {
michael@0 624 nsIntRect drawBounds = mUpdated.GetBounds();
michael@0 625
michael@0 626 aHost->mBufferRect = mBufferRect;
michael@0 627 aHost->mBufferRotation = mBufferRotation;
michael@0 628
michael@0 629 // Figure out which quadrant to draw in
michael@0 630 int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x;
michael@0 631 int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y;
michael@0 632 XSide sideX = drawBounds.XMost() <= xBoundary ? RIGHT : LEFT;
michael@0 633 YSide sideY = drawBounds.YMost() <= yBoundary ? BOTTOM : TOP;
michael@0 634 nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
michael@0 635 NS_ASSERTION(quadrantRect.Contains(drawBounds), "Messed up quadrants");
michael@0 636
michael@0 637 mUpdated.MoveBy(-nsIntPoint(quadrantRect.x, quadrantRect.y));
michael@0 638
michael@0 639 IntPoint offset = ToIntPoint(-mUpdated.GetBounds().TopLeft());
michael@0 640
michael@0 641 RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(mDescriptor);
michael@0 642
michael@0 643 if (mTextureId == TextureFront) {
michael@0 644 aHost->mSource->Update(surf, &mUpdated, &offset);
michael@0 645 } else {
michael@0 646 aHost->mSourceOnWhite->Update(surf, &mUpdated, &offset);
michael@0 647 }
michael@0 648 }
michael@0 649
michael@0 650 void
michael@0 651 ContentHostTexture::PrintInfo(nsACString& aTo, const char* aPrefix)
michael@0 652 {
michael@0 653 aTo += aPrefix;
michael@0 654 aTo += nsPrintfCString("ContentHost (0x%p)", this);
michael@0 655
michael@0 656 AppendToString(aTo, mBufferRect, " [buffer-rect=", "]");
michael@0 657 AppendToString(aTo, mBufferRotation, " [buffer-rotation=", "]");
michael@0 658 if (PaintWillResample()) {
michael@0 659 aTo += " [paint-will-resample]";
michael@0 660 }
michael@0 661
michael@0 662 nsAutoCString pfx(aPrefix);
michael@0 663 pfx += " ";
michael@0 664
michael@0 665 if (mTextureHost) {
michael@0 666 aTo += "\n";
michael@0 667 mTextureHost->PrintInfo(aTo, pfx.get());
michael@0 668 }
michael@0 669 }
michael@0 670
michael@0 671
michael@0 672 LayerRenderState
michael@0 673 ContentHostTexture::GetRenderState()
michael@0 674 {
michael@0 675 if (!mTextureHost) {
michael@0 676 return LayerRenderState();
michael@0 677 }
michael@0 678
michael@0 679 LayerRenderState result = mTextureHost->GetRenderState();
michael@0 680
michael@0 681 if (mBufferRotation != nsIntPoint()) {
michael@0 682 result.mFlags |= LAYER_RENDER_STATE_BUFFER_ROTATION;
michael@0 683 }
michael@0 684 result.SetOffset(GetOriginOffset());
michael@0 685 return result;
michael@0 686 }
michael@0 687
michael@0 688 #ifdef MOZ_DUMP_PAINTING
michael@0 689 TemporaryRef<gfx::DataSourceSurface>
michael@0 690 ContentHostTexture::GetAsSurface()
michael@0 691 {
michael@0 692 if (!mTextureHost) {
michael@0 693 return nullptr;
michael@0 694 }
michael@0 695
michael@0 696 return mTextureHost->GetAsSurface();
michael@0 697 }
michael@0 698
michael@0 699 #endif
michael@0 700
michael@0 701
michael@0 702 } // namespace
michael@0 703 } // namespace

mercurial