-
Notifications
You must be signed in to change notification settings - Fork 806
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1950,30 +1950,43 @@ void CGContextEOFillPath(CGContextRef context) { | |
|
||
#pragma region Drawing Operations - CGImage | ||
|
||
/** | ||
@Status Interoperable | ||
*/ | ||
void CGContextDrawImage(CGContextRef context, CGRect rect, CGImageRef image) { | ||
NOISY_RETURN_IF_NULL(context); | ||
NOISY_RETURN_IF_NULL(image); | ||
static HRESULT __CreateD2DBitmapFromCGImage(CGContextRef context, CGImageRef image, ID2D1Bitmap** bitmap) { | ||
RETURN_HR_IF_NULL(E_INVALIDARG, context); | ||
RETURN_HR_IF_NULL(E_INVALIDARG, image); | ||
RETURN_HR_IF_NULL(E_POINTER, bitmap); | ||
|
||
// Obtain the pixel format for the image | ||
WICPixelFormatGUID imagePixelFormat = _CGImageGetWICPixelFormat(image); | ||
ComPtr<IWICBitmap> bmap; | ||
RETURN_IF_FAILED(_CGImageGetWICImageSource(image, &bmap)); | ||
|
||
CFRetain(image); | ||
woc::unique_cf<CGImageRef> refImage; | ||
refImage.reset(image); | ||
ComPtr<ID2D1Bitmap> d2dBitmap; | ||
RETURN_IF_FAILED(context->DeviceContext()->CreateBitmapFromWicBitmap(bmap.Get(), nullptr, &d2dBitmap)); | ||
*bitmap = d2dBitmap.Detach(); | ||
return S_OK; | ||
} | ||
|
||
static CGImageRef __CGContextCreateRenderableImage(CGImageRef image) { | ||
RETURN_NULL_IF(!image); | ||
WICPixelFormatGUID imagePixelFormat = _CGImageGetWICPixelFormat(image); | ||
if (!_CGIsValidRenderTargetPixelFormat(imagePixelFormat)) { | ||
// convert it to a valid pixelformat | ||
refImage.reset(_CGImageCreateCopyWithPixelFormat(image, GUID_WICPixelFormat32bppPBGRA)); | ||
return _CGImageCreateCopyWithPixelFormat(image, GUID_WICPixelFormat32bppPBGRA); | ||
} | ||
|
||
ComPtr<IWICBitmap> bmap; | ||
FAIL_FAST_IF_FAILED(_CGImageGetWICImageSource(refImage.get(), &bmap)); | ||
CGImageRetain(image); | ||
return image; | ||
} | ||
|
||
/** | ||
@Status Interoperable | ||
*/ | ||
void CGContextDrawImage(CGContextRef context, CGRect rect, CGImageRef image) { | ||
NOISY_RETURN_IF_NULL(context); | ||
NOISY_RETURN_IF_NULL(image); | ||
|
||
woc::unique_cf<CGImageRef> refImage{ __CGContextCreateRenderableImage(image) }; | ||
|
||
ComPtr<ID2D1Bitmap> d2dBitmap; | ||
FAIL_FAST_IF_FAILED(context->DeviceContext()->CreateBitmapFromWicBitmap(bmap.Get(), nullptr, &d2dBitmap)); | ||
FAIL_FAST_IF_FAILED(__CreateD2DBitmapFromCGImage(context, refImage.get(), &d2dBitmap)); | ||
|
||
// Flip the image to account for change in coordinate system origin. | ||
CGAffineTransform flipImage = CGAffineTransformMakeTranslation(rect.origin.x, rect.origin.y + (rect.size.height / 2.0)); | ||
|
@@ -2022,13 +2035,58 @@ void _CGContextDrawImageRect(CGContextRef context, CGImageRef image, CGRect src, | |
} | ||
|
||
/** | ||
@Status Stub | ||
@Status Interoperable | ||
*/ | ||
void CGContextDrawTiledImage(CGContextRef context, CGRect rect, CGImageRef image) { | ||
// TODO #1417: This can be combined with brushes (brush + tiled fill); | ||
NOISY_RETURN_IF_NULL(context); | ||
UNIMPLEMENTED(); | ||
NOISY_RETURN_IF_NULL(image); | ||
|
||
woc::unique_cf<CGImageRef> refImage{ __CGContextCreateRenderableImage(image) }; | ||
|
||
ComPtr<ID2D1Bitmap> d2dBitmap; | ||
FAIL_FAST_IF_FAILED(__CreateD2DBitmapFromCGImage(context, refImage.get(), &d2dBitmap)); | ||
|
||
ComPtr<ID2D1BitmapBrush> bitmapBrush; | ||
ComPtr<ID2D1DeviceContext> deviceContext = context->DeviceContext(); | ||
FAIL_FAST_IF_FAILED(deviceContext->CreateBitmapBrush(d2dBitmap.Get(), &bitmapBrush)); | ||
|
||
// set the bitmap properties for the brush to be repeated | ||
bitmapBrush->SetExtendModeX(D2D1_EXTEND_MODE_WRAP); | ||
bitmapBrush->SetExtendModeY(D2D1_EXTEND_MODE_WRAP); | ||
|
||
// |1 0 0| is the transformation matrix for flipping a rect about its Y midpoint m. (m = (y + h/2)) | ||
// |0 -1 0| | ||
// |0 2m 1| | ||
// | ||
// Combined with [scale sx * sy] * [translate X, Y], that becomes: | ||
// |sx 0 0| | ||
// | 0 -sy 0| | ||
// | x -y+2m 0| | ||
// Or, the transformation matrix for drawing a flipped rect at a scale and offset. | ||
D2D1_SIZE_U bitmapSize = d2dBitmap->GetPixelSize(); | ||
CGFloat sx = rect.size.width / bitmapSize.width; | ||
CGFloat sy = rect.size.height / bitmapSize.height; | ||
CGFloat m = rect.origin.y + (rect.size.height / 2.f); | ||
|
||
CGAffineTransform transform{ sx, 0, 0, -sy, rect.origin.x, (2 * m) - rect.origin.y }; | ||
transform = CGAffineTransformConcat(transform, CGContextGetUserSpaceToDeviceSpaceTransform(context)); | ||
This comment has been minimized.
Sorry, something went wrong. |
||
|
||
// set the transform for the brush and alpha | ||
bitmapBrush->SetTransform(__CGAffineTransformToD2D_F(transform)); | ||
bitmapBrush->SetOpacity(context->CurrentGState().alpha); | ||
|
||
// set the interpolationMode | ||
bitmapBrush->SetInterpolationMode(D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR); | ||
This comment has been minimized.
Sorry, something went wrong.
DHowett-MSFT
|
||
|
||
// Area to fill | ||
D2D1_SIZE_F targetSize = deviceContext->GetSize(); | ||
D2D1_RECT_F region = D2D1::RectF(0, 0, targetSize.width, targetSize.height); | ||
|
||
deviceContext->BeginDraw(); | ||
This comment has been minimized.
Sorry, something went wrong.
DHowett-MSFT
|
||
deviceContext->FillRectangle(®ion, bitmapBrush.Get()); | ||
FAIL_FAST_IF_FAILED(deviceContext->EndDraw()); | ||
} | ||
|
||
#pragma endregion | ||
|
||
#pragma region Drawing Operations - Gradient + Shading | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,146 @@ DISABLED_DRAW_TEST_F(CGContext, DrawIntoRect, UIKitMimicTest) { | |
} | ||
#endif | ||
|
||
static void _drawTiledImage(CGContextRef context, CGRect rect, const std::string& name) { | ||
auto drawingConfig = DrawingTestConfig::Get(); | ||
woc::unique_cf<CFStringRef> testFilename{ _CFStringCreateWithStdString(drawingConfig->GetResourcePath(name)) }; | ||
woc::unique_cf<CGImageRef> image{ _CGImageCreateFromPNGFile(testFilename.get()) }; | ||
ASSERT_NE(image, nullptr); | ||
CGContextDrawTiledImage(context, rect, image.get()); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageHeart, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 128, 128 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageHeart.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageHeartScaledUp, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 250, 250 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageHeart.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageHeartScaledTiny, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 1, 1 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageHeart.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageHeartScaledAlpha1, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 100, 100 } }; | ||
CGContextSetAlpha(GetDrawingContext(), 0.8); | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageHeart.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageHeartScaledAlpha2, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 256, 256 } }; | ||
CGContextSetAlpha(GetDrawingContext(), 0.24); | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageHeart.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageHeartScaledAlpha3, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 300, 513 } }; | ||
CGContextSetAlpha(GetDrawingContext(), 0.66); | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageHeart.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageHeartScaledDown, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 50, 50 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageHeart.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageHeartScaled, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 250, 128 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageHeart.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageDog, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 256, 256 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageDog.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageDogScaledDown, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 50, 50 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageDog.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageDogScaledUp, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 512, 512 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageDog.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageDogScaled, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 350, 500 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageDog.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageDogScaled2, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 128, 240 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageDog.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageDogScaledAspectRatioWrong, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 1024, 25 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageDog.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageDogScaledAspectRatio, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 1024, 1024 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageDog.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageDogScaledAlpha, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 100, 100 } }; | ||
CGContextSetAlpha(GetDrawingContext(), 0.8); | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageDog.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageDogScaledAlpha2, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 256, 256 } }; | ||
CGContextSetAlpha(GetDrawingContext(), 0.24); | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageDog.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageDogScaledAlpha3, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 300, 513 } }; | ||
CGContextSetAlpha(GetDrawingContext(), 0.66); | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageDog.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageCustom, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 562, 469 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageCircleMe.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageCustomScaledUp, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 2050, 2050 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageCircleMe.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageCustomScaledDown, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 20, 20 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageCircleMe.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageCustomScaledDownReallyLow, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 1, 1 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageCircleMe.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageCustomScaled, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 10, 250 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageCircleMe.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageCustomScaledObscure, UIKitMimicTest) { | ||
CGRect rect = { { 0, 0 }, { 253, 13 } }; | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageCircleMe.png"); | ||
} | ||
|
||
DRAW_TEST_F(CGContext, TiledImageCustomScaledAlpha, UIKitMimicTest) { | ||
This comment has been minimized.
Sorry, something went wrong.
DHowett-MSFT
|
||
CGRect rect = { { 0, 0 }, { 128, 128 } }; | ||
CGContextSetAlpha(GetDrawingContext(), 0.88); | ||
_drawTiledImage(GetDrawingContext(), rect, "tiledImageCircleMe.png"); | ||
} | ||
|
||
DISABLED_DRAW_TEST_F(CGContext, DrawAnImage, UIKitMimicTest) { | ||
// Load an Image and draw it into the canvas context | ||
auto drawingConfig = DrawingTestConfig::Get(); | ||
|
@@ -98,7 +238,6 @@ DISABLED_DRAW_TEST_F(CGContext, DrawAContextIntoAnImage, UIKitMimicTest) { | |
CGContextDrawImage(context, bounds, image.get()); | ||
} | ||
|
||
|
||
DISABLED_DRAW_TEST_F(CGContext, FillThenStrokeIsSameAsDrawFillStroke, WhiteBackgroundTest) { | ||
CGContextRef context = GetDrawingContext(); | ||
CGRect bounds = GetDrawingBounds(); | ||
|
Whichever of us merges second will be tasked with lifting this out into a common function ;)