Example #1
0
void
ThebesLayerD3D9::SetVisibleRegion(const nsIntRegion &aRegion)
{
  if (aRegion.IsEqual(mVisibleRegion)) {
    return;
  }

  nsIntRegion oldVisibleRegion = mVisibleRegion;
  ThebesLayer::SetVisibleRegion(aRegion);

  if (!mTexture) {
    // If we don't need to retain content initialize lazily. This is good also
    // because we might get mIsOpaqueSurface set later than the first call to
    // SetVisibleRegion.
    return;
  }

  D3DFORMAT fmt = (UseOpaqueSurface(this) && !mD2DSurface) ?
                    D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8;

  D3DSURFACE_DESC desc;
  mTexture->GetLevelDesc(0, &desc);

  if (fmt != desc.Format) {
    // The new format isn't compatible with the old texture, toss out the old
    // texture.
    mTexture = nsnull;
  }

  nsRefPtr<IDirect3DTexture9> oldTexture = mTexture;

  nsIntRect oldBounds = oldVisibleRegion.GetBounds();
  nsIntRect newBounds = mVisibleRegion.GetBounds();

  CreateNewTexture(gfxIntSize(newBounds.width, newBounds.height));

  // Old visible region will become the region that is covered by both the
  // old and the new visible region.
  oldVisibleRegion.And(oldVisibleRegion, mVisibleRegion);
  // No point in retaining parts which were not valid.
  oldVisibleRegion.And(oldVisibleRegion, mValidRegion);

  nsIntRect largeRect = oldVisibleRegion.GetLargestRectangle();

  // If we had no hardware texture before or have no retained area larger than
  // the retention threshold, we're not retaining and are done here. If our
  // texture creation failed this can mean a device reset is pending and we
  // should silently ignore the failure. In the future when device failures
  // are properly handled we should test for the type of failure and gracefully
  // handle different failures. See bug 569081.
  if (!oldTexture || !mTexture ||
      largeRect.width * largeRect.height < RETENTION_THRESHOLD) {
    mValidRegion.SetEmpty();
    return;
  }

  nsRefPtr<IDirect3DSurface9> srcSurface, dstSurface;
  oldTexture->GetSurfaceLevel(0, getter_AddRefs(srcSurface));
  mTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));

  nsIntRegion retainedRegion;
  nsIntRegionRectIterator iter(oldVisibleRegion);
  const nsIntRect *r;
  while ((r = iter.Next())) {
    if (r->width * r->height > RETENTION_THRESHOLD) {
      RECT oldRect, newRect;

      // Calculate the retained rectangle's position on the old and the new
      // surface.
      oldRect.left = r->x - oldBounds.x;
      oldRect.top = r->y - oldBounds.y;
      oldRect.right = oldRect.left + r->width;
      oldRect.bottom = oldRect.top + r->height;

      newRect.left = r->x - newBounds.x;
      newRect.top = r->y - newBounds.y;
      newRect.right = newRect.left + r->width;
      newRect.bottom = newRect.top + r->height;

      // Copy data from our old texture to the new one
      HRESULT hr = device()->
        StretchRect(srcSurface, &oldRect, dstSurface, &newRect, D3DTEXF_NONE);

      if (SUCCEEDED(hr)) {
        retainedRegion.Or(retainedRegion, *r);
      }
    }
  }

  // Areas which were valid and were retained are still valid
  mValidRegion.And(mValidRegion, retainedRegion);  
}