in winrt/lib/drawing/CanvasDrawingSession.cpp [1279:1331]
static bool TryGetFillOpacityMaskParameters(ID2D1Brush* opacityBrush, ID2D1DeviceContext1* deviceContext, D2D1_RECT_F const& destRect, ID2D1Bitmap** opacityBitmap, D2D1_RECT_F* opacitySourceRect)
{
// Is this a bitmap brush?
auto bitmapBrush = MaybeAs<ID2D1BitmapBrush1>(opacityBrush);
if (!bitmapBrush)
return false;
bitmapBrush->GetBitmap(opacityBitmap);
if (!*opacityBitmap)
return false;
// Make sure the brush transform contains only positive scaling and translation, as other
// transforms cannot be represented in FillOpacityMask sourceRect/destRect format.
D2D1::Matrix3x2F brushTransform;
bitmapBrush->GetTransform(&brushTransform);
if (brushTransform._11 <= 0 ||
brushTransform._22 <= 0 ||
brushTransform._12 != 0 ||
brushTransform._21 != 0)
{
return false;
}
// Transform the dest rect by the inverse of the brush transform, yielding a FillOpacityMask source rect.
if (!D2D1InvertMatrix(&brushTransform))
return false;
auto tl = D2D1_POINT_2F{ destRect.left, destRect.top } * brushTransform;
auto br = D2D1_POINT_2F{ destRect.right, destRect.bottom } * brushTransform;
// Can't use FillOpacityMask if the source rect goes outside the bounds of the bitmap.
if (!ArePointsInsideBitmap(*opacityBitmap, tl, br, deviceContext->GetUnitMode()))
return false;
// FillOpacityMask always uses default alpha and interpolation mode.
if (bitmapBrush->GetOpacity() != 1.0f)
return false;
if (bitmapBrush->GetInterpolationMode1() != D2D1_BITMAP_INTERPOLATION_MODE_LINEAR)
return false;
// FillOpacityMask requires that antialiasing be disabled.
if (deviceContext->GetAntialiasMode() != D2D1_ANTIALIAS_MODE_ALIASED)
return false;
// Ok then! FillOpacityMask is a go.
*opacitySourceRect = D2D1_RECT_F{ tl.x, tl.y, br.x, br.y };
return true;
}