void ContentHostBase::Composite(EffectChain& aEffectChain, float aOpacity, const gfx::Matrix4x4& aTransform, const Filter& aFilter, const Rect& aClipRect, const nsIntRegion* aVisibleRegion, TiledLayerProperties* aLayerProperties) { NS_ASSERTION(aVisibleRegion, "Requires a visible region"); AutoLockTextureHost lock(mTextureHost); AutoLockTextureHost lockOnWhite(mTextureHostOnWhite); if (!mTextureHost || !lock.IsValid() || !lockOnWhite.IsValid()) { return; } RefPtr<NewTextureSource> source = mTextureHost->GetTextureSources(); RefPtr<NewTextureSource> sourceOnWhite = mTextureHostOnWhite ? mTextureHostOnWhite->GetTextureSources() : nullptr; if (!source) { return; } RefPtr<TexturedEffect> effect = CreateTexturedEffect(source, sourceOnWhite, aFilter); aEffectChain.mPrimaryEffect = effect; nsIntRegion tmpRegion; const nsIntRegion* renderRegion; if (PaintWillResample()) { // If we're resampling, then the texture image will contain exactly the // entire visible region's bounds, and we should draw it all in one quad // to avoid unexpected aliasing. tmpRegion = aVisibleRegion->GetBounds(); renderRegion = &tmpRegion; } else { renderRegion = aVisibleRegion; } nsIntRegion region(*renderRegion); nsIntPoint origin = GetOriginOffset(); // translate into TexImage space, buffer origin might not be at texture (0,0) region.MoveBy(-origin); // Figure out the intersecting draw region gfx::IntSize texSize = source->GetSize(); nsIntRect textureRect = nsIntRect(0, 0, texSize.width, texSize.height); textureRect.MoveBy(region.GetBounds().TopLeft()); nsIntRegion subregion; subregion.And(region, textureRect); if (subregion.IsEmpty()) { // Region is empty, nothing to draw return; } nsIntRegion screenRects; nsIntRegion regionRects; // Collect texture/screen coordinates for drawing nsIntRegionRectIterator iter(subregion); while (const nsIntRect* iterRect = iter.Next()) { nsIntRect regionRect = *iterRect; nsIntRect screenRect = regionRect; screenRect.MoveBy(origin); screenRects.Or(screenRects, screenRect); regionRects.Or(regionRects, regionRect); } TileIterator* tileIter = source->AsTileIterator(); TileIterator* iterOnWhite = nullptr; if (tileIter) { tileIter->BeginTileIteration(); } if (mTextureHostOnWhite) { iterOnWhite = sourceOnWhite->AsTileIterator(); MOZ_ASSERT(!tileIter || tileIter->GetTileCount() == iterOnWhite->GetTileCount(), "Tile count mismatch on component alpha texture"); if (iterOnWhite) { iterOnWhite->BeginTileIteration(); } } bool usingTiles = (tileIter && tileIter->GetTileCount() > 1); do { if (iterOnWhite) { MOZ_ASSERT(iterOnWhite->GetTileRect() == tileIter->GetTileRect(), "component alpha textures should be the same size."); } nsIntRect texRect = tileIter ? tileIter->GetTileRect() : nsIntRect(0, 0, texSize.width, texSize.height); // Draw texture. If we're using tiles, we do repeating manually, as texture // repeat would cause each individual tile to repeat instead of the // compound texture as a whole. This involves drawing at most 4 sections, // 2 for each axis that has texture repeat. for (int y = 0; y < (usingTiles ? 2 : 1); y++) { for (int x = 0; x < (usingTiles ? 2 : 1); x++) { nsIntRect currentTileRect(texRect); currentTileRect.MoveBy(x * texSize.width, y * texSize.height); nsIntRegionRectIterator screenIter(screenRects); nsIntRegionRectIterator regionIter(regionRects); const nsIntRect* screenRect; const nsIntRect* regionRect; while ((screenRect = screenIter.Next()) && (regionRect = regionIter.Next())) { nsIntRect tileScreenRect(*screenRect); nsIntRect tileRegionRect(*regionRect); // When we're using tiles, find the intersection between the tile // rect and this region rect. Tiling is then handled by the // outer for-loops and modifying the tile rect. if (usingTiles) { tileScreenRect.MoveBy(-origin); tileScreenRect = tileScreenRect.Intersect(currentTileRect); tileScreenRect.MoveBy(origin); if (tileScreenRect.IsEmpty()) continue; tileRegionRect = regionRect->Intersect(currentTileRect); tileRegionRect.MoveBy(-currentTileRect.TopLeft()); } gfx::Rect rect(tileScreenRect.x, tileScreenRect.y, tileScreenRect.width, tileScreenRect.height); effect->mTextureCoords = Rect(Float(tileRegionRect.x) / texRect.width, Float(tileRegionRect.y) / texRect.height, Float(tileRegionRect.width) / texRect.width, Float(tileRegionRect.height) / texRect.height); GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, aOpacity, aTransform); if (usingTiles) { DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT | DIAGNOSTIC_BIGIMAGE; diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0; GetCompositor()->DrawDiagnostics(diagnostics, rect, aClipRect, aTransform); } } } } if (iterOnWhite) { iterOnWhite->NextTile(); } } while (usingTiles && tileIter->NextTile()); if (tileIter) { tileIter->EndTileIteration(); } if (iterOnWhite) { iterOnWhite->EndTileIteration(); } DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT; diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0; GetCompositor()->DrawDiagnostics(diagnostics, *aVisibleRegion, aClipRect, aTransform); }
void ContentHostTexture::Composite(LayerComposite* aLayer, EffectChain& aEffectChain, float aOpacity, const gfx::Matrix4x4& aTransform, const Filter& aFilter, const Rect& aClipRect, const nsIntRegion* aVisibleRegion) { NS_ASSERTION(aVisibleRegion, "Requires a visible region"); AutoLockCompositableHost lock(this); if (lock.Failed()) { return; } if (!mTextureHost->BindTextureSource(mTextureSource)) { return; } MOZ_ASSERT(mTextureSource.get()); if (!mTextureHostOnWhite) { mTextureSourceOnWhite = nullptr; } if (mTextureHostOnWhite && !mTextureHostOnWhite->BindTextureSource(mTextureSourceOnWhite)) { return; } RefPtr<TexturedEffect> effect = CreateTexturedEffect(mTextureSource.get(), mTextureSourceOnWhite.get(), aFilter, true, GetRenderState()); if (!effect) { return; } aEffectChain.mPrimaryEffect = effect; nsIntRegion tmpRegion; const nsIntRegion* renderRegion; #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE if (PaintWillResample()) { // If we're resampling, then the texture image will contain exactly the // entire visible region's bounds, and we should draw it all in one quad // to avoid unexpected aliasing. tmpRegion = aVisibleRegion->GetBounds(); renderRegion = &tmpRegion; } else { renderRegion = aVisibleRegion; } #else renderRegion = aVisibleRegion; #endif nsIntRegion region(*renderRegion); nsIntPoint origin = GetOriginOffset(); // translate into TexImage space, buffer origin might not be at texture (0,0) region.MoveBy(-origin); // Figure out the intersecting draw region gfx::IntSize texSize = mTextureSource->GetSize(); IntRect textureRect = IntRect(0, 0, texSize.width, texSize.height); textureRect.MoveBy(region.GetBounds().TopLeft()); nsIntRegion subregion; subregion.And(region, textureRect); if (subregion.IsEmpty()) { // Region is empty, nothing to draw return; } nsIntRegion screenRects; nsIntRegion regionRects; // Collect texture/screen coordinates for drawing nsIntRegionRectIterator iter(subregion); while (const IntRect* iterRect = iter.Next()) { IntRect regionRect = *iterRect; IntRect screenRect = regionRect; screenRect.MoveBy(origin); screenRects.Or(screenRects, screenRect); regionRects.Or(regionRects, regionRect); } BigImageIterator* bigImgIter = mTextureSource->AsBigImageIterator(); BigImageIterator* iterOnWhite = nullptr; if (bigImgIter) { bigImgIter->BeginBigImageIteration(); } if (mTextureSourceOnWhite) { iterOnWhite = mTextureSourceOnWhite->AsBigImageIterator(); MOZ_ASSERT(!bigImgIter || bigImgIter->GetTileCount() == iterOnWhite->GetTileCount(), "Tile count mismatch on component alpha texture"); if (iterOnWhite) { iterOnWhite->BeginBigImageIteration(); } } bool usingTiles = (bigImgIter && bigImgIter->GetTileCount() > 1); do { if (iterOnWhite && bigImgIter) { MOZ_ASSERT(iterOnWhite->GetTileRect() == bigImgIter->GetTileRect(), "component alpha textures should be the same size."); } IntRect texRect = bigImgIter ? bigImgIter->GetTileRect() : IntRect(0, 0, texSize.width, texSize.height); // Draw texture. If we're using tiles, we do repeating manually, as texture // repeat would cause each individual tile to repeat instead of the // compound texture as a whole. This involves drawing at most 4 sections, // 2 for each axis that has texture repeat. for (int y = 0; y < (usingTiles ? 2 : 1); y++) { for (int x = 0; x < (usingTiles ? 2 : 1); x++) { IntRect currentTileRect(texRect); currentTileRect.MoveBy(x * texSize.width, y * texSize.height); nsIntRegionRectIterator screenIter(screenRects); nsIntRegionRectIterator regionIter(regionRects); const IntRect* screenRect; const IntRect* regionRect; while ((screenRect = screenIter.Next()) && (regionRect = regionIter.Next())) { IntRect tileScreenRect(*screenRect); IntRect tileRegionRect(*regionRect); // When we're using tiles, find the intersection between the tile // rect and this region rect. Tiling is then handled by the // outer for-loops and modifying the tile rect. if (usingTiles) { tileScreenRect.MoveBy(-origin); tileScreenRect = tileScreenRect.Intersect(currentTileRect); tileScreenRect.MoveBy(origin); if (tileScreenRect.IsEmpty()) continue; tileRegionRect = regionRect->Intersect(currentTileRect); tileRegionRect.MoveBy(-currentTileRect.TopLeft()); } gfx::Rect rect(tileScreenRect.x, tileScreenRect.y, tileScreenRect.width, tileScreenRect.height); effect->mTextureCoords = Rect(Float(tileRegionRect.x) / texRect.width, Float(tileRegionRect.y) / texRect.height, Float(tileRegionRect.width) / texRect.width, Float(tileRegionRect.height) / texRect.height); GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, aOpacity, aTransform); if (usingTiles) { DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT | DiagnosticFlags::BIGIMAGE; if (iterOnWhite) { diagnostics |= DiagnosticFlags::COMPONENT_ALPHA; } GetCompositor()->DrawDiagnostics(diagnostics, rect, aClipRect, aTransform, mFlashCounter); } } } } if (iterOnWhite) { iterOnWhite->NextTile(); } } while (usingTiles && bigImgIter->NextTile()); if (bigImgIter) { bigImgIter->EndBigImageIteration(); } if (iterOnWhite) { iterOnWhite->EndBigImageIteration(); } DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT; if (iterOnWhite) { diagnostics |= DiagnosticFlags::COMPONENT_ALPHA; } GetCompositor()->DrawDiagnostics(diagnostics, nsIntRegion(mBufferRect), aClipRect, aTransform, mFlashCounter); }