diff --git a/Frameworks/CoreGraphics/CGContext.mm b/Frameworks/CoreGraphics/CGContext.mm index e8d604b6cd..c7ce7a5928 100644 --- a/Frameworks/CoreGraphics/CGContext.mm +++ b/Frameworks/CoreGraphics/CGContext.mm @@ -840,7 +840,7 @@ CGRect CGContextGetClipBoundingBox(CGContextRef context) { auto& state = context->CurrentGState(); if (!state.clippingGeometry) { D2D1_SIZE_F targetSize = context->RenderTarget()->GetSize(); - return CGContextConvertRectToUserSpace(context, CGRect{ CGPointZero, { targetSize.width, targetSize.height }}); + return CGContextConvertRectToUserSpace(context, CGRect{ CGPointZero, { targetSize.width, targetSize.height } }); } D2D1_RECT_F bounds; @@ -1393,39 +1393,6 @@ void CGContextShowGlyphsWithAdvances(CGContextRef context, const CGGlyph* glyphs } #pragma endregion -#pragma region Drawing Operations - CGImage -/// TODO(DH): GH#1078 Image Drawing -/** - @Status Interoperable -*/ -void CGContextDrawImage(CGContextRef context, CGRect rect, CGImageRef image) { - NOISY_RETURN_IF_NULL(context); - if (!image) { - TraceWarning(TAG, L"Img == nullptr!"); - return; - } - if (!context) { - TraceWarning(TAG, L"CGContextDrawImage: context == nullptr!"); - return; - } - - UNIMPLEMENTED(); -} - -void CGContextDrawImageRect(CGContextRef context, CGImageRef image, CGRect src, CGRect dst) { - NOISY_RETURN_IF_NULL(context); - UNIMPLEMENTED(); -} - -/** - @Status Interoperable -*/ -void CGContextDrawTiledImage(CGContextRef context, CGRect rect, CGImageRef image) { - NOISY_RETURN_IF_NULL(context); - UNIMPLEMENTED(); -} -#pragma endregion - #pragma region Drawing Operations - Basic Shapes /** @Status Interoperable @@ -1803,10 +1770,94 @@ void CGContextEOFillPath(CGContextRef context) { } #pragma endregion -#pragma region Drawing Operations - Gradient + Shading +#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); + + // Obtain the pixel format for the image + WICPixelFormatGUID imagePixelFormat = _CGImageGetWICPixelFormat(image); + + CFRetain(image); + woc::unique_cf refImage; + refImage.reset(image); + + if (!_CGIsValidRenderTargetPixelFormat(imagePixelFormat)) { + // convert it to a valid pixelformat + refImage.reset(_CGImageCreateCopyWithPixelFormat(image, GUID_WICPixelFormat32bppPRGBA)); + } + + ComPtr bmap; + FAIL_FAST_IF_FAILED(_CGImageGetWICImageSource(refImage.get(), &bmap)); + + ComPtr d2dBitmap; + FAIL_FAST_IF_FAILED(context->RenderTarget()->CreateBitmapFromWicBitmap(bmap.Get(), nullptr, &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)); + flipImage = CGAffineTransformScale(flipImage, 1.0, -1.0); + flipImage = CGAffineTransformTranslate(flipImage, -rect.origin.x, -(rect.origin.y + (rect.size.height / 2.0))); + + ComPtr commandList; + HRESULT hr = __CGContextRenderToCommandList(context, + _kCGCoordinateModeUserSpace, + &flipImage, + &commandList, + [&](CGContextRef context, ID2D1DeviceContext* deviceContext) { + deviceContext->DrawBitmap(d2dBitmap.Get(), __CGRectToD2D_F(rect)); + return S_OK; + }); + FAIL_FAST_IF_FAILED(hr); + FAIL_FAST_IF_FAILED(__CGContextRenderImage(context, commandList.Get())); +} + +void _CGContextDrawImageRect(CGContextRef context, CGImageRef image, CGRect src, CGRect dst) { + NOISY_RETURN_IF_NULL(context); + NOISY_RETURN_IF_NULL(image); + + if (CGRectEqualToRect(src, dst)) { + CGContextDrawImage(context, dst, image); + return; + } + + RETURN_IF(CGRectGetHeight(src) == 0); + RETURN_IF(CGRectGetWidth(src) == 0); + + // we want the source region to be drawn into the dest region (scaled) + // The image needs to be scaled and translated for the destination. + CGRect drawRect = CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)); + // scale factor of the image + float scaleX = CGRectGetWidth(dst) / CGRectGetWidth(src); + float scaleY = CGRectGetHeight(dst) / CGRectGetHeight(src); + // calculate he translation offset + float deltaX = CGRectGetMinX(dst) - (CGRectGetMinX(src) * scaleX); + float deltaY = CGRectGetMinY(dst) - (CGRectGetMinY(src) * scaleY); + drawRect = CGRectMake(deltaX, deltaY, (float)CGImageGetWidth(image) * scaleX, (float)CGImageGetHeight(image) * scaleY); + + CGContextSaveGState(context); + CGContextClipToRect(context, dst); + CGContextDrawImage(context, drawRect, image); + CGContextRestoreGState(context); +} + +/** + @Status Stub +*/ +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(); +} +#pragma endregion + +#pragma region Drawing Operations - Gradient + Shading +/** + @Status Stub +*/ void CGContextDrawLinearGradient( CGContextRef context, CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint, CGGradientDrawingOptions options) { NOISY_RETURN_IF_NULL(context); @@ -1816,7 +1867,7 @@ void CGContextDrawLinearGradient( } /** - @Status Interoperable + @Status Stub */ void CGContextDrawRadialGradient(CGContextRef context, CGGradientRef gradient, diff --git a/Frameworks/CoreGraphics/CGImage.mm b/Frameworks/CoreGraphics/CGImage.mm index 7c6c861ece..26af98c541 100644 --- a/Frameworks/CoreGraphics/CGImage.mm +++ b/Frameworks/CoreGraphics/CGImage.mm @@ -555,6 +555,11 @@ CGImageRef CGImageCreateWithMaskingColors(CGImageRef image, const CGFloat* compo #pragma region WIC_HELPERS +WICPixelFormatGUID _CGImageGetWICPixelFormat(CGImageRef image) { + RETURN_RESULT_IF_NULL(image, GUID_WICPixelFormatUndefined); + return image->PixelFormat(); +} + bool _CGIsValidRenderTargetPixelFormat(WICPixelFormatGUID pixelFormat) { auto iterator = s_ValidRenderTargetPixelFormat.find(pixelFormat); return iterator != s_ValidRenderTargetPixelFormat.end(); @@ -569,9 +574,11 @@ bool _CGIsValidRenderTargetPixelFormat(WICPixelFormatGUID pixelFormat) { return &iterator->second; } -IWICBitmap* _CGImageGetImageSource(CGImageRef image) { - RETURN_NULL_IF(!image); - return image->ImageSource().Get(); +HRESULT _CGImageGetWICImageSource(CGImageRef image, IWICBitmap** source) { + RETURN_HR_IF_NULL(E_INVALIDARG, image); + RETURN_HR_IF_NULL(E_POINTER, source); + *source = image->ImageSource().Get(); + return S_OK; } DisplayTexture* _CGImageGetDisplayTexture(CGImageRef image) { diff --git a/Frameworks/QuartzCore/CALayer.mm b/Frameworks/QuartzCore/CALayer.mm index 6fd53b459e..5b808007e9 100644 --- a/Frameworks/QuartzCore/CALayer.mm +++ b/Frameworks/QuartzCore/CALayer.mm @@ -375,8 +375,8 @@ CGContextRef CreateLayerContentsBitmapContext32(int width, int height, float sca releaseWritetableBitmapTexture.Dismiss(); Microsoft::WRL::ComPtr customWICBtmap = - Microsoft::WRL::Make(displayTexture.get(), GUID_WICPixelFormat32bppPBGRA, height, width); - // We want to convert it to GUID_WICPixelFormat32bppPBGRA for D2D Render Target compatibility. + Microsoft::WRL::Make(displayTexture.get(), GUID_WICPixelFormat32bppPRGBA, height, width); + // We want to convert it to GUID_WICPixelFormat32bppPRGBA for D2D Render Target compatibility. woc::unique_cf image(_CGImageCreateWithWICBitmap(customWICBtmap.Get())); Microsoft::WRL::ComPtr factory; @@ -481,7 +481,7 @@ - (void)renderInContext:(CGContextRef)ctx { rect.size.width = priv->bounds.size.width * priv->contentsScale; rect.size.height = -priv->bounds.size.height * priv->contentsScale; - CGContextDrawImageRect(ctx, priv->contents, rect, destRect); + _CGContextDrawImageRect(ctx, priv->contents, rect, destRect); } // Draw sublayers diff --git a/Frameworks/UIKit/StarboardXaml/CompositorInterface.mm b/Frameworks/UIKit/StarboardXaml/CompositorInterface.mm index 3341dc548c..85bcdd0a66 100644 --- a/Frameworks/UIKit/StarboardXaml/CompositorInterface.mm +++ b/Frameworks/UIKit/StarboardXaml/CompositorInterface.mm @@ -163,7 +163,7 @@ void SetNodeContent(DisplayNode* node, float width, float height, float scale) { public: DisplayTextureContent(CGImageRef img) : name("TextureBitmap") { - woc::unique_cf image(_CGImageCreateCopyWithPixelFormat(img, GUID_WICPixelFormat32bppPBGRA)); + woc::unique_cf image(_CGImageCreateCopyWithPixelFormat(img, GUID_WICPixelFormat32bppPRGBA)); _xamlImage = CreateBitmapFromBits(_CGImageGetRawBytes(image.get()), CGImageGetWidth(image.get()), CGImageGetHeight(image.get()), diff --git a/Frameworks/UIKit/UIImage.mm b/Frameworks/UIKit/UIImage.mm index 0c675f7929..2a8af666f6 100644 --- a/Frameworks/UIKit/UIImage.mm +++ b/Frameworks/UIKit/UIImage.mm @@ -449,7 +449,7 @@ - (void)draw1PartImageInRect:(CGRect)pos { srcRect.size.width = pos.size.width; srcRect.size.height = -pos.size.height; - CGContextDrawImageRect(cur, getImage(self), srcRect, pos); + _CGContextDrawImageRect(cur, getImage(self), srcRect, pos); } /** @@ -488,7 +488,7 @@ - (void)drawAtPoint:(CGPoint)point blendMode:(CGBlendMode)mode alpha:(float)alph srcRect.size.width = img_width; srcRect.size.height = -img_height; - CGContextDrawImageRect(cur, img, srcRect, pos); + _CGContextDrawImageRect(cur, img, srcRect, pos); CGContextRestoreGState(cur); } @@ -541,24 +541,24 @@ static inline void drawPatches(CGContextRef context, UIImage* img, CGRect* dst) if (dstHeight - dstTopCap - dstBotCap > 0) { if (dstLeftCap) { // MidHeightLeft - CGContextDrawImageRect(context, - cgImg, - CGRectMake(0, srcHeight - srcBotCap, srcLeftCap, -(srcHeight - srcTopCap - srcBotCap)), - CGRectMake(dstX, (dstY + dstBotCap), dstLeftCap, (dstHeight - dstTopCap - dstBotCap))); + _CGContextDrawImageRect(context, + cgImg, + CGRectMake(0, srcHeight - srcBotCap, srcLeftCap, -(srcHeight - srcTopCap - srcBotCap)), + CGRectMake(dstX, (dstY + dstBotCap), dstLeftCap, (dstHeight - dstTopCap - dstBotCap))); } if (dstWidth - dstLeftCap - dstRightCap > 0) { // MidHeightMidWidth - CGContextDrawImageRect(context, - cgImg, - CGRectMake(srcLeftCap, - srcHeight - srcBotCap, - (srcWidth - srcLeftCap - srcRightCap), - -(srcHeight - srcTopCap - srcBotCap)), - CGRectMake((dstX + dstLeftCap), - (dstY + dstBotCap), - (dstWidth - dstLeftCap - dstRightCap), - (dstHeight - dstTopCap - dstBotCap))); + _CGContextDrawImageRect(context, + cgImg, + CGRectMake(srcLeftCap, + srcHeight - srcBotCap, + (srcWidth - srcLeftCap - srcRightCap), + -(srcHeight - srcTopCap - srcBotCap)), + CGRectMake((dstX + dstLeftCap), + (dstY + dstBotCap), + (dstWidth - dstLeftCap - dstRightCap), + (dstHeight - dstTopCap - dstBotCap))); } else { UNIMPLEMENTED_WITH_MSG( "Patched draws only supported when sum of " @@ -568,7 +568,7 @@ static inline void drawPatches(CGContextRef context, UIImage* img, CGRect* dst) if (dstRightCap) { // MidHeightRight - CGContextDrawImageRect( + _CGContextDrawImageRect( context, cgImg, CGRectMake((srcWidth - srcRightCap), srcHeight - srcBotCap, srcRightCap, -(srcHeight - srcTopCap - srcBotCap)), @@ -584,54 +584,54 @@ static inline void drawPatches(CGContextRef context, UIImage* img, CGRect* dst) if (dstTopCap) { if (dstLeftCap) { // TL corner - CGContextDrawImageRect(context, - cgImg, - CGRectMake(0, srcTopCap, srcLeftCap, -srcTopCap), - CGRectMake(dstX, (dstY + dstHeight - dstTopCap), dstLeftCap, dstTopCap)); + _CGContextDrawImageRect(context, + cgImg, + CGRectMake(0, srcTopCap, srcLeftCap, -srcTopCap), + CGRectMake(dstX, (dstY + dstHeight - dstTopCap), dstLeftCap, dstTopCap)); } if (dstWidth - dstLeftCap - dstRightCap > 0) { // TCenter - CGContextDrawImageRect(context, - cgImg, - CGRectMake(srcLeftCap, srcTopCap, (srcWidth - srcLeftCap - srcRightCap), -srcTopCap), - CGRectMake((dstX + dstLeftCap), - (dstY + dstHeight - dstTopCap), - (dstWidth - dstLeftCap - dstRightCap), - dstTopCap)); + _CGContextDrawImageRect(context, + cgImg, + CGRectMake(srcLeftCap, srcTopCap, (srcWidth - srcLeftCap - srcRightCap), -srcTopCap), + CGRectMake((dstX + dstLeftCap), + (dstY + dstHeight - dstTopCap), + (dstWidth - dstLeftCap - dstRightCap), + dstTopCap)); } if (dstRightCap) { // TR corner - CGContextDrawImageRect(context, - cgImg, - CGRectMake((srcWidth - srcRightCap), srcTopCap, srcRightCap, -srcTopCap), - CGRectMake((dstX + dstWidth - dstRightCap), (dstY + dstHeight - dstTopCap), dstRightCap, dstTopCap)); + _CGContextDrawImageRect(context, + cgImg, + CGRectMake((srcWidth - srcRightCap), srcTopCap, srcRightCap, -srcTopCap), + CGRectMake((dstX + dstWidth - dstRightCap), (dstY + dstHeight - dstTopCap), dstRightCap, dstTopCap)); } } if (dstBotCap) { if (dstLeftCap) { // BL Corner - CGContextDrawImageRect(context, - cgImg, - CGRectMake(0, srcHeight, srcLeftCap, -srcBotCap), - CGRectMake(dstX, dstY, dstLeftCap, dstBotCap)); + _CGContextDrawImageRect(context, + cgImg, + CGRectMake(0, srcHeight, srcLeftCap, -srcBotCap), + CGRectMake(dstX, dstY, dstLeftCap, dstBotCap)); } if (dstWidth - dstLeftCap - dstRightCap > 0) { // bottomMidWidth - CGContextDrawImageRect(context, - cgImg, - CGRectMake(srcLeftCap, srcHeight, (srcWidth - srcLeftCap - srcRightCap), -srcBotCap), - CGRectMake((dstX + dstLeftCap), dstY, (dstWidth - dstLeftCap - dstRightCap), dstBotCap)); + _CGContextDrawImageRect(context, + cgImg, + CGRectMake(srcLeftCap, srcHeight, (srcWidth - srcLeftCap - srcRightCap), -srcBotCap), + CGRectMake((dstX + dstLeftCap), dstY, (dstWidth - dstLeftCap - dstRightCap), dstBotCap)); } if (dstRightCap) { - CGContextDrawImageRect(context, - cgImg, - CGRectMake((srcWidth - srcRightCap), srcHeight, srcRightCap, -srcBotCap), - CGRectMake((dstX + dstWidth - dstRightCap), dstY, dstRightCap, dstBotCap)); + _CGContextDrawImageRect(context, + cgImg, + CGRectMake((srcWidth - srcRightCap), srcHeight, srcRightCap, -srcBotCap), + CGRectMake((dstX + dstWidth - dstRightCap), dstY, dstRightCap, dstBotCap)); } } } diff --git a/Frameworks/UIKit/UIPasteboard.mm b/Frameworks/UIKit/UIPasteboard.mm index 6051cbbb97..586a3cc5b7 100644 --- a/Frameworks/UIKit/UIPasteboard.mm +++ b/Frameworks/UIKit/UIPasteboard.mm @@ -282,7 +282,7 @@ + (WSSInMemoryRandomAccessStream*)_grabStreamFromUIImage:(UIImage*)image { CGImageRef img = [image CGImage]; // TODO #1338 - Support via encoded data from IWIC - woc::unique_cf imgRef(_CGImageCreateCopyWithPixelFormat(img, GUID_WICPixelFormat32bppPBGRA)); + woc::unique_cf imgRef(_CGImageCreateCopyWithPixelFormat(img, GUID_WICPixelFormat32bppPRGBA)); NSData* data = static_cast(CGImageGetDataProvider(imgRef.get())); WSSInMemoryRandomAccessStream* stream = [[WSSInMemoryRandomAccessStream make] autorelease]; diff --git a/Frameworks/include/CGContextImpl.h b/Frameworks/include/CGContextImpl.h index 206a70b475..747c964ddf 100644 --- a/Frameworks/include/CGContextImpl.h +++ b/Frameworks/include/CGContextImpl.h @@ -105,7 +105,7 @@ class CGContextImpl { virtual CGAffineTransform CGContextGetCTM(); virtual void CGContextSetCTM(CGAffineTransform transform); virtual void CGContextDrawImage(CGRect rct, CGImageRef img); - virtual void CGContextDrawImageRect(CGImageRef img, CGRect src, CGRect dst); + virtual void _CGContextDrawImageRect(CGImageRef img, CGRect src, CGRect dst); virtual void CGContextDrawTiledImage(CGRect rct, CGImageRef img); virtual void CGContextClipToMask(CGRect dest, CGImageRef img); virtual void CGContextSaveGState(); diff --git a/Frameworks/include/CGContextInternal.h b/Frameworks/include/CGContextInternal.h index d8b4466972..8ae11089e0 100644 --- a/Frameworks/include/CGContextInternal.h +++ b/Frameworks/include/CGContextInternal.h @@ -32,7 +32,7 @@ COREGRAPHICS_EXPORT CGContextRef _CGBitmapContextCreateWithRenderTarget(ID2D1RenderTarget* renderTarget, CGImageRef img = nullptr); COREGRAPHICS_EXPORT CGContextRef _CGBitmapContextCreateWithFormat(int width, int height, __CGSurfaceFormat fmt); COREGRAPHICS_EXPORT CGImageRef CGBitmapContextGetImage(CGContextRef ctx); -COREGRAPHICS_EXPORT void CGContextDrawImageRect(CGContextRef ctx, CGImageRef img, CGRect src, CGRect dst); +COREGRAPHICS_EXPORT void _CGContextDrawImageRect(CGContextRef ctx, CGImageRef img, CGRect src, CGRect dst); COREGRAPHICS_EXPORT void CGContextClearToColor(CGContextRef ctx, float r, float g, float b, float a); COREGRAPHICS_EXPORT bool CGContextIsDirty(CGContextRef ctx); COREGRAPHICS_EXPORT void CGContextSetDirty(CGContextRef ctx, bool dirty); diff --git a/Frameworks/include/CGImageInternal.h b/Frameworks/include/CGImageInternal.h index b4372e655d..d8cee2d965 100644 --- a/Frameworks/include/CGImageInternal.h +++ b/Frameworks/include/CGImageInternal.h @@ -95,6 +95,8 @@ static const std::map s_PixelForm bool _CGIsValidRenderTargetPixelFormat(WICPixelFormatGUID pixelFormat); const __CGImagePixelProperties* _CGGetPixelFormatProperties(WICPixelFormatGUID pixelFormat); +WICPixelFormatGUID _CGImageGetWICPixelFormat(CGImageRef image); + COREGRAPHICS_EXPORT CGImageRef _CGImageLoadGIF(void* bytes, int length); COREGRAPHICS_EXPORT CGImageRef _CGImageLoadBMP(void* bytes, size_t length); @@ -115,7 +117,7 @@ COREGRAPHICS_EXPORT NSData* _CGImageRepresentation(CGImageRef image, REFGUID gui COREGRAPHICS_EXPORT CGImageRef _CGImageCreateWithWICBitmap(IWICBitmap* bitmap); -COREGRAPHICS_EXPORT IWICBitmap* _CGImageGetImageSource(CGImageRef image); +COREGRAPHICS_EXPORT HRESULT _CGImageGetWICImageSource(CGImageRef image, IWICBitmap** source); // Obtain a direct pointer to the data. COREGRAPHICS_EXPORT void* _CGImageGetRawBytes(CGImageRef image); diff --git a/build/CoreGraphics/dll/CoreGraphics.def b/build/CoreGraphics/dll/CoreGraphics.def index a073dd622d..a01c8d0af3 100644 --- a/build/CoreGraphics/dll/CoreGraphics.def +++ b/build/CoreGraphics/dll/CoreGraphics.def @@ -226,7 +226,7 @@ LIBRARY CoreGraphics ; private exports below CGContextClearToColor - CGContextDrawImageRect + _CGContextDrawImageRect CGContextGetBlendMode CGContextIsDirty CGContextReleaseLock @@ -360,7 +360,7 @@ LIBRARY CoreGraphics _CGImageCreateCopyWithPixelFormat _CGImageGetRawBytes _CGImageGetDisplayTexture - _CGImageGetImageSource + _CGImageGetWICImageSource ; private exports below CGImageAddDestructionListener diff --git a/build/Tests/UnitTests/CoreGraphics.Drawing/CoreGraphics.Drawing.UnitTests.vcxproj b/build/Tests/UnitTests/CoreGraphics.Drawing/CoreGraphics.Drawing.UnitTests.vcxproj index 9fae829e48..c2bee28476 100644 --- a/build/Tests/UnitTests/CoreGraphics.Drawing/CoreGraphics.Drawing.UnitTests.vcxproj +++ b/build/Tests/UnitTests/CoreGraphics.Drawing/CoreGraphics.Drawing.UnitTests.vcxproj @@ -250,8 +250,7 @@ - + diff --git a/tests/UnitTests/CoreGraphics.drawing/CGContextDrawingTests.cpp b/tests/UnitTests/CoreGraphics.drawing/CGContextDrawingTests.cpp index 90a9ee4ce2..33855ca229 100644 --- a/tests/UnitTests/CoreGraphics.drawing/CGContextDrawingTests.cpp +++ b/tests/UnitTests/CoreGraphics.drawing/CGContextDrawingTests.cpp @@ -14,7 +14,68 @@ // //****************************************************************************** -#include "DrawingTest.h" +#import "DrawingTest.h" +#import +#import "CGContextInternal.h" + +// TODO:#1448 Remove the use of OBJC code +#ifdef WINOBJC + +static NSString* getModulePath() { + char fullPath[_MAX_PATH]; + GetModuleFileNameA(NULL, fullPath, _MAX_PATH); + return [@(fullPath) stringByDeletingLastPathComponent]; +} + +static NSString* getPathToFile(NSString* fileName) { + static StrongId refPath = getModulePath(); + return [refPath stringByAppendingPathComponent:fileName]; +} + +DISABLED_DRAW_TEST_F(CGContext, DrawIntoRect, UIKitMimicTest) { + // Draw a portion of an image into a different region. + CFDataRef data = (CFDataRef)[NSData dataWithContentsOfFile:getPathToFile(@"png3.9.png")]; + woc::unique_cf dataProvider(CGDataProviderCreateWithCFData(data)); + + woc::unique_cf image(CGImageCreateWithPNGDataProvider(dataProvider.get(), NULL, NO, kCGRenderingIntentDefault)); + ASSERT_NE(image, nullptr); + + CGContextRef context = GetDrawingContext(); + CGRect bounds = GetDrawingBounds(); + + CGAffineTransform flip = CGAffineTransformMakeScale(1, -1); + CGAffineTransform shift = CGAffineTransformTranslate(flip, 0, bounds.size.height * -1); + CGContextConcatCTM(context, shift); + + _CGContextDrawImageRect(context, + image.get(), + { 0, 0, bounds.size.width / 4, bounds.size.height / 4 }, + { 0, 0, bounds.size.width, bounds.size.height }); +} + +DISABLED_DRAW_TEST_F(CGContext, DrawAnImage, UIKitMimicTest) { + // Load an Image and draw it into the canvas context + CFDataRef data = (CFDataRef)[NSData dataWithContentsOfFile:getPathToFile(@"jpg1.jpg")]; + woc::unique_cf dataProvider(CGDataProviderCreateWithCFData(data)); + + woc::unique_cf cgImage(CGImageCreateWithJPEGDataProvider(dataProvider.get(), + + NULL, + NO, + kCGRenderingIntentDefault)); + ASSERT_NE(cgImage, nullptr); + + CGContextRef context = GetDrawingContext(); + CGRect bounds = GetDrawingBounds(); + + CGAffineTransform flip = CGAffineTransformMakeScale(1, -1); + CGAffineTransform shift = CGAffineTransformTranslate(flip, 0, bounds.size.height * -1); + CGContextConcatCTM(context, shift); + + CGContextDrawImage(context, bounds, cgImage.get()); +} + +#endif DISABLED_DRAW_TEST_F(CGContext, RedBox, UIKitMimicTest) { CGContextRef context = GetDrawingContext(); @@ -24,6 +85,35 @@ DISABLED_DRAW_TEST_F(CGContext, RedBox, UIKitMimicTest) { CGContextFillRect(context, CGRectInset(bounds, 10, 10)); } +DISABLED_DRAW_TEST_F(CGContext, DrawAContextIntoAnImage, UIKitMimicTest) { + // This test will create a bitmap context, draw some entity into the context, then create a image out of the bitmap context. + // Thereafter it will draw the image into the Canvas context + + static woc::unique_cf rgbColorSpace(CGColorSpaceCreateDeviceRGB()); + // Create a bitmap context to draw the Image into + woc::unique_cf contextImage(CGBitmapContextCreate( + nullptr, 10, 10, 8, 4 * 10 /* bytesPerRow = bytesPerPixel*width*/, rgbColorSpace.get(), kCGImageAlphaPremultipliedFirst)); + ASSERT_NE(contextImage, nullptr); + + CGContextSetRGBFillColor(contextImage.get(), 1.0, 0.0, 0.0, 1.0); + CGContextFillRect(contextImage.get(), { 0, 0, 10, 10 }); + + // Create the image out of the bitmap context + woc::unique_cf image(CGBitmapContextCreateImage(contextImage.get())); + ASSERT_NE(image, nullptr); + + CGContextRef context = GetDrawingContext(); + CGRect bounds = GetDrawingBounds(); + + CGAffineTransform flip = CGAffineTransformMakeScale(1, -1); + CGAffineTransform shift = CGAffineTransformTranslate(flip, 0, bounds.size.height * -1); + CGContextConcatCTM(context, shift); + + // draw the image + CGContextDrawImage(context, bounds, image.get()); +} + + DISABLED_DRAW_TEST_F(CGContext, FillThenStrokeIsSameAsDrawFillStroke, WhiteBackgroundTest) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); diff --git a/tests/unittests/CoreGraphics.drawing/data/jpg1.jpg b/tests/unittests/CoreGraphics.drawing/data/jpg1.jpg new file mode 100644 index 0000000000..2d3e3acf8f --- /dev/null +++ b/tests/unittests/CoreGraphics.drawing/data/jpg1.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4acbfed702e7facfa6fcd9dd96d1a54fc32ad87fb1d8d897c25ff19ae724271a +size 58514 diff --git a/tests/unittests/CoreGraphics.drawing/data/png3.9.png b/tests/unittests/CoreGraphics.drawing/data/png3.9.png new file mode 100644 index 0000000000..3100561dcb --- /dev/null +++ b/tests/unittests/CoreGraphics.drawing/data/png3.9.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e912f441be54a82cd9d37b3240f659acb259250b702a4ee2f5f5fc3c0efd3e01 +size 3803366 diff --git a/tests/unittests/CoreGraphics/CGContextTests.mm b/tests/unittests/CoreGraphics/CGContextTests.mm index d7bc5eb4b4..1b58b3b347 100644 --- a/tests/unittests/CoreGraphics/CGContextTests.mm +++ b/tests/unittests/CoreGraphics/CGContextTests.mm @@ -30,6 +30,7 @@ #include #import "CGContextInternal.h" +#import "TestUtils.h" using namespace Microsoft::WRL; #endif @@ -419,3 +420,76 @@ virtual void SetUp() { INSTANTIATE_TEST_CASE_P(CGContextCoordinateSpace, ContextCoordinateTest, ::testing::ValuesIn(coordinateTestTuples)); #endif + +TEST(CGContext, DrawAnImageIntoContext) { + woc::unique_cf rgbColorSpace(CGColorSpaceCreateDeviceRGB()); + + // Create a canvas context + woc::unique_cf context(CGBitmapContextCreate( + nullptr, 512, 256, 8, 4 * 512 /* bytesPerRow = bytesPerPixel*width*/, rgbColorSpace.get(), kCGImageAlphaPremultipliedFirst)); + + // Load an image from file + CFDataRef data = (CFDataRef)[NSData dataWithContentsOfFile:getPathToFile(@"jpg1.jpg")]; + woc::unique_cf dataProvider(CGDataProviderCreateWithCFData(data)); + + woc::unique_cf cgImage(CGImageCreateWithJPEGDataProvider(dataProvider.get(), NULL, NO, kCGRenderingIntentDefault)); + ASSERT_NE(cgImage, nullptr); + + CGRect bounds = { 0, 0, 512, 256 }; + CGAffineTransform flip = CGAffineTransformMakeScale(1, -1); + CGAffineTransform shift = CGAffineTransformTranslate(flip, 0, bounds.size.height * -1); + CGContextConcatCTM(context.get(), shift); + + // Check the canvas context pixel before drawing + BYTE* dataPtr = static_cast(CGBitmapContextGetData(context.get())); + ASSERT_NE(dataPtr, nullptr); + EXPECT_EQ(dataPtr[0], 0xcd); + + // Draw the image into the canvas context + CGContextDrawImage(context.get(), bounds, cgImage.get()); + + // Check the canvas context pixel after drawing + dataPtr = static_cast(CGBitmapContextGetData(context.get())); + ASSERT_NE(dataPtr, nullptr); + EXPECT_EQ(dataPtr[0], 0x97); +} + +TEST(CGContext, DrawAContextImageIntoAContext) { + woc::unique_cf rgbColorSpace(CGColorSpaceCreateDeviceRGB()); + + // Create a bitmap context to draw into + woc::unique_cf contextImage(CGBitmapContextCreate( + nullptr, 10, 10, 8, 4 * 10 /* bytesPerRow = bytesPerPixel*width*/, rgbColorSpace.get(), kCGImageAlphaPremultipliedFirst)); + ASSERT_NE(contextImage, nullptr); + + // flood the bitmap context with a pretty color. + CGContextSetRGBFillColor(contextImage.get(), 1.0, 0.0, 0.0, 1.0); + CGContextFillRect(contextImage.get(), { 0, 0, 10, 10 }); + + // Create a image out of the bitmap context + woc::unique_cf image(CGBitmapContextCreateImage(contextImage.get())); + ASSERT_NE(image, nullptr); + + // This will be the pseudo canvas context which we will draw into + woc::unique_cf context(CGBitmapContextCreate( + nullptr, 512, 256, 8, 4 * 512 /* bytesPerRow = bytesPerPixel*width*/, rgbColorSpace.get(), kCGImageAlphaPremultipliedFirst)); + + CGRect bounds = { 0, 0, 512, 256 }; + + CGAffineTransform flip = CGAffineTransformMakeScale(1, -1); + CGAffineTransform shift = CGAffineTransformTranslate(flip, 0, bounds.size.height * -1); + CGContextConcatCTM(context.get(), shift); + + // Check the canvas context pixel before drawing + BYTE* dataPtr = static_cast(CGBitmapContextGetData(context.get())); + ASSERT_NE(dataPtr, nullptr); + EXPECT_EQ(dataPtr[0], 0xcd); + + // Draw the image into the canvas context + CGContextDrawImage(context.get(), bounds, image.get()); + + // Check the canvas context pixel after drawing + dataPtr = static_cast(CGBitmapContextGetData(context.get())); + ASSERT_NE(dataPtr, nullptr); + EXPECT_EQ(dataPtr[0], 0xff); +}