Bug 1791686 - For COLRv1 glyphs that use PaintComposite, render the composited sub-graph to a temporary Skia surface. r=gfx-reviewers,lsalzman

This avoids calling PushLayerWithBlend on the eventual DrawTarget, because
not all DrawTarget implementations support it; instead we perform the blend
operation to a Skia surface and then copy the result to the real target.

Checked that the results are as expected with Dominik's test page at
https://roettsch.es/var_colrv1.html, where many of the glyphs (not just the
explicit composite-mode tests, but also a bunch of the transform tests etc)
involve PaintComposite layers.

Differential Revision: https://phabricator.services.mozilla.com/D158197
This commit is contained in:
Jonathan Kew 2022-09-29 15:07:41 +00:00
parent bf8918c2e9
commit e8fe128740

View file

@ -1615,16 +1615,37 @@ struct PaintComposite {
if (compositeMode == COMPOSITE_DEST) {
return DispatchPaint(aState, aOffset + backdropPaintOffset);
}
aState.mDrawTarget->PushLayer(true, 1.0, nullptr, Matrix());
bool ok = DispatchPaint(aState, aOffset + backdropPaintOffset);
if (ok) {
aState.mDrawTarget->PushLayerWithBlend(true, 1.0, nullptr, Matrix(),
IntRect(), false,
mapCompositionMode(compositeMode));
ok = DispatchPaint(aState, aOffset + sourcePaintOffset);
aState.mDrawTarget->PopLayer();
Rect r = GetBoundingRect(aState, aOffset);
if (r.IsEmpty()) {
return true;
}
r.RoundOut();
// Because not all backends support PushLayerWithBlend (looking at you,
// DrawTargetD2D1), we paint this sub-graph of the glyph to a temporary
// Skia surface where we know we *can* use PushLayerWithBlend, and then
// copy it to the final destination.
RefPtr dt = Factory::CreateDrawTarget(BackendType::SKIA,
IntSize(int(r.width), int(r.height)),
SurfaceFormat::B8G8R8A8);
if (!dt) {
// If this failed, we'll just bail out, leaving this glyph (partially)
// unpainted, but allow other rendering to continue.
return true;
}
dt->SetTransform(Matrix::Translation(-r.TopLeft()));
PaintState state = aState;
state.mDrawTarget = dt;
bool ok = DispatchPaint(state, aOffset + backdropPaintOffset);
if (ok) {
dt->PushLayerWithBlend(true, 1.0, nullptr, Matrix(), IntRect(), false,
mapCompositionMode(compositeMode));
ok = DispatchPaint(state, aOffset + sourcePaintOffset);
dt->PopLayer();
}
if (ok) {
RefPtr snapshot = dt->Snapshot();
aState.mDrawTarget->DrawSurface(snapshot, r, Rect(Point(), r.Size()));
}
aState.mDrawTarget->PopLayer();
return ok;
}