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); }