From ffab5cda877a927b3966bcd6738215377fc0f038 Mon Sep 17 00:00:00 2001 From: Shahmeer Esmail Date: Mon, 11 Jul 2016 15:48:00 -0700 Subject: [PATCH 1/7] Changes to resolve graphic corruption bug and optimize drawing of images with imageCaps: - drawNinePatchCallback renamed to drawPatches - Instead of creating a pattern and calling a CB function (drawNinePatchCallback) to subdivide image into patches and draw individually, the change was made to just call a function which subdivides the images into patches and draws (drawPatches) - Insets improperly scaled in many places - drawPatches optimized to subdivide the image into the smallest number of patches to reduce draw setup and state management overhead - make drawPatches and makeRect inline --- Frameworks/UIKit/UIImage.mm | 256 +++++++++++++++++------------------- 1 file changed, 120 insertions(+), 136 deletions(-) diff --git a/Frameworks/UIKit/UIImage.mm b/Frameworks/UIKit/UIImage.mm index e18bc704f6..a7d46997d5 100644 --- a/Frameworks/UIKit/UIImage.mm +++ b/Frameworks/UIKit/UIImage.mm @@ -1,5 +1,6 @@ //****************************************************************************** // +// Copyright (c) 2016 Intel Corporation. All rights reserved. // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). @@ -45,11 +46,6 @@ - (CGRect)_imageStretch; static const wchar_t* TAG = L"UIImage"; -struct insetInfo { - UIImage* img; - CGRect size; -}; - CFMutableDictionaryRef g_imageCache; pthread_mutex_t imageCacheLock = PTHREAD_MUTEX_INITIALIZER; @@ -714,102 +710,108 @@ - (void)drawAsPatternInRect:(CGRect)pos { [self drawAtPoint:pos.origin]; } -static void drawNinePatchCallBack(void* info, CGContextRef context) { - insetInfo* ii = (insetInfo*)info; - UIImage* img = ii->img; +static inline void drawPatches(CGContextRef context, UIImage* img, CGRect* src, CGRect* dst) { + // Note: Subdivides image into 1-9 patches which are drawn individually. + // Note: The number of subdivisions depends on what insets have been set. + const float topCap = img->_imageInsets.top; + const float botCap = img->_imageInsets.bottom; + const float leftCap = img->_imageInsets.left; + const float rightCap = img->_imageInsets.right; + CGImageRef cgImg = getImage(img); - if (img->_imageInsets.top) { - CGContextDrawImageRect(context, - getImage(img), - makeRect(0, - getImage(img)->Backing()->Height() - img->_imageInsets.top, - img->_imageInsets.left, - img->_imageInsets.top), - makeRect(0, ii->size.size.height - img->_imageInsets.top, img->_imageInsets.left, img->_imageInsets.top)); - if (getImage(img)->Backing()->Width() - img->_imageInsets.left - img->_imageInsets.right > 0) { + // Center strip + if (src->size.height - topCap - botCap > 0) { + if (leftCap) { + // MidHeightLeft CGContextDrawImageRect(context, - getImage(img), - makeRect(img->_imageInsets.left, - getImage(img)->Backing()->Height() - img->_imageInsets.top, - getImage(img)->Backing()->Width() - img->_imageInsets.left - img->_imageInsets.right, - img->_imageInsets.top), - makeRect(img->_imageInsets.left, - ii->size.size.height - img->_imageInsets.top, - ii->size.size.width - img->_imageInsets.left - img->_imageInsets.right, - img->_imageInsets.top)); + cgImg, + makeRect(0, botCap, leftCap, (src->size.height - topCap - botCap)), + makeRect(dst->origin.x, (dst->origin.y + botCap), leftCap, (dst->size.height - topCap - botCap))); } - CGContextDrawImageRect(context, - getImage(img), - makeRect(getImage(img)->Backing()->Width() - img->_imageInsets.right, - getImage(img)->Backing()->Height() - img->_imageInsets.top, - img->_imageInsets.right, - img->_imageInsets.top), - makeRect(ii->size.size.width - img->_imageInsets.right, - ii->size.size.height - img->_imageInsets.top, - img->_imageInsets.right, - img->_imageInsets.top)); - } - // Coordinates flipped on Y - if (getImage(img)->Backing()->Height() - img->_imageInsets.top - img->_imageInsets.bottom > 0) { - CGContextDrawImageRect(context, - getImage(img), - makeRect(0, - img->_imageInsets.bottom, - img->_imageInsets.left, - getImage(img)->Backing()->Height() - img->_imageInsets.top - img->_imageInsets.bottom), - makeRect(0, - img->_imageInsets.bottom, - img->_imageInsets.left, - ii->size.size.height - img->_imageInsets.top - img->_imageInsets.bottom)); - if (getImage(img)->Backing()->Width() - img->_imageInsets.left - img->_imageInsets.right > 0) { + if (src->size.width - leftCap - rightCap > 0) { + // MidHeightMidWidth CGContextDrawImageRect(context, - getImage(img), - makeRect(img->_imageInsets.left, - img->_imageInsets.bottom, - getImage(img)->Backing()->Width() - img->_imageInsets.left - img->_imageInsets.right, - getImage(img)->Backing()->Height() - img->_imageInsets.top - img->_imageInsets.bottom), - makeRect(img->_imageInsets.left, - img->_imageInsets.bottom, - ii->size.size.width - img->_imageInsets.left - img->_imageInsets.right, - ii->size.size.height - img->_imageInsets.top - img->_imageInsets.bottom)); + cgImg, + makeRect(leftCap, botCap, (src->size.width - leftCap - rightCap), (src->size.height - topCap - botCap)), + makeRect((dst->origin.x + leftCap), + (dst->origin.y + botCap), + (dst->size.width - leftCap - rightCap), + (dst->size.height - topCap - botCap))); } else { assert(0); } - CGContextDrawImageRect(context, - getImage(img), - makeRect(getImage(img)->Backing()->Width() - img->_imageInsets.right, - img->_imageInsets.bottom, - img->_imageInsets.right, - getImage(img)->Backing()->Height() - img->_imageInsets.top - img->_imageInsets.bottom), - makeRect(ii->size.size.width - img->_imageInsets.right, - img->_imageInsets.bottom, - img->_imageInsets.right, - ii->size.size.height - img->_imageInsets.top - img->_imageInsets.bottom)); + + if (rightCap) { + // MidHeightRight + CGContextDrawImageRect(context, + cgImg, + makeRect((src->size.width - rightCap), botCap, rightCap, (src->size.height - topCap - botCap)), + makeRect((dst->origin.x + dst->size.width - rightCap), + (dst->origin.y + botCap), + rightCap, + (dst->size.height - topCap - botCap))); + } + } else { + assert(0); + } + + if (topCap) { + if (leftCap) { + // TL corner + CGContextDrawImageRect(context, + cgImg, + makeRect(0, (src->size.height - topCap), leftCap, topCap), + makeRect(dst->origin.x, (dst->origin.y + dst->size.height - topCap), leftCap, topCap)); + } + + if (src->size.width - leftCap - rightCap > 0) { + // TCenter + CGContextDrawImageRect(context, + cgImg, + makeRect(leftCap, (src->size.height - topCap), (src->size.width - leftCap - rightCap), topCap), + makeRect((dst->origin.x + leftCap), + (dst->origin.y + dst->size.height - topCap), + (dst->size.width - leftCap - rightCap), + topCap)); + } + + if (rightCap) { + // TR corner + CGContextDrawImageRect(context, + cgImg, + makeRect((src->size.width - rightCap), (src->size.height - topCap), rightCap, topCap), + makeRect((dst->origin.x + dst->size.width - rightCap), + (dst->origin.y + dst->size.height - topCap), + rightCap, + topCap)); + } } - if (img->_imageInsets.bottom) { - CGContextDrawImageRect(context, - getImage(img), - makeRect(0, 0, img->_imageInsets.left, img->_imageInsets.bottom), - makeRect(0, 0, img->_imageInsets.left, img->_imageInsets.bottom)); - if (getImage(img)->Backing()->Width() - img->_imageInsets.left - img->_imageInsets.right > 0) { + if (botCap) { + // BL Corner + if (leftCap) { CGContextDrawImageRect(context, - getImage(img), - makeRect(img->_imageInsets.left, - 0, - getImage(img)->Backing()->Width() - img->_imageInsets.left - img->_imageInsets.right, - img->_imageInsets.bottom), - makeRect(img->_imageInsets.left, - 0, - ii->size.size.width - img->_imageInsets.left - img->_imageInsets.right, - img->_imageInsets.bottom)); + cgImg, + makeRect(0, 0, leftCap, botCap), + makeRect(dst->origin.x, dst->origin.y, leftCap, botCap)); + } + + if (src->size.width - leftCap - rightCap > 0) { + // bottomMidWidth + CGContextDrawImageRect(context, + cgImg, + makeRect(leftCap, 0, (src->size.width - leftCap - rightCap), botCap), + makeRect((dst->origin.x + leftCap), dst->origin.y, (dst->size.width - leftCap - rightCap), botCap)); + } + + if (rightCap) { + // BR corner + CGContextDrawImageRect(context, + cgImg, + makeRect((src->size.width - rightCap), 0, rightCap, botCap), + makeRect((dst->origin.x + dst->size.width - rightCap), dst->origin.y, rightCap, botCap)); } - CGContextDrawImageRect( - context, - getImage(img), - makeRect(getImage(img)->Backing()->Width() - img->_imageInsets.right, 0, img->_imageInsets.right, img->_imageInsets.bottom), - makeRect(ii->size.size.width - img->_imageInsets.right, 0, img->_imageInsets.right, img->_imageInsets.bottom)); } } @@ -831,7 +833,7 @@ static void drawLeftCap(UIImage* self, CGContextRef cur, CGRect pos) { drawRect.size.height = destRect.size.height; capRect = srcRect; - capRect.size.width = self->_imageInsets.left * self->_scale; + capRect.size.width = self->_imageInsets.left; capRect.origin.y = getImage(self)->Backing()->Height() - capRect.origin.y; capRect.size.height = -capRect.size.height; @@ -842,10 +844,10 @@ static void drawLeftCap(UIImage* self, CGContextRef cur, CGRect pos) { // Draw cap fragment drawRect.origin.x = destRect.origin.x + self->_imageInsets.left; drawRect.origin.y = destRect.origin.y; - drawRect.size.width = pos.size.width - srcRect.size.width / self->_scale; + drawRect.size.width = pos.size.width - srcRect.size.width; drawRect.size.height = destRect.size.height; - capRect.origin.x = self->_imageInsets.left * self->_scale; + capRect.origin.x = self->_imageInsets.left; capRect.origin.y = getImage(self)->Backing()->Height() - srcRect.origin.y; capRect.size.width = 1; capRect.size.height = -srcRect.size.height; @@ -854,10 +856,10 @@ static void drawLeftCap(UIImage* self, CGContextRef cur, CGRect pos) { } // Adjust the source and desination rects - srcRect.origin.x = self->_imageInsets.left * self->_scale; - srcRect.size.width = getImage(self)->Backing()->Width() - self->_imageInsets.left * self->_scale; - destRect.origin.x += pos.size.width - (srcRect.size.width / self->_scale); - destRect.size.width = srcRect.size.width / self->_scale; + srcRect.origin.x = self->_imageInsets.left; + srcRect.size.width = getImage(self)->Backing()->Width() - self->_imageInsets.left; + destRect.origin.x += pos.size.width - (srcRect.size.width); + destRect.size.width = srcRect.size.width; // Invert srcRect srcRect.origin.y = getImage(self)->Backing()->Height() - srcRect.origin.y; @@ -867,8 +869,8 @@ static void drawLeftCap(UIImage* self, CGContextRef cur, CGRect pos) { float diff = minX - destRect.origin.x; destRect.origin.x += diff; destRect.size.width -= diff; - srcRect.origin.x += diff * self->_scale; - srcRect.size.width -= diff * self->_scale; + srcRect.origin.x += diff; + srcRect.size.width -= diff; } if (destRect.size.width > 0.0f) { CGContextDrawImageRect(cur, getImage(self), srcRect, destRect); @@ -936,7 +938,7 @@ static void drawFromRect(UIImage* self, CGContextRef ctx, CGRect dest, CGRect so CGContextDrawImageRect(ctx, getImage(self), source, dest); } -static CGRect makeRect(float left, float top, float width, float height) { +static inline CGRect makeRect(float left, float top, float width, float height) { CGRect ret = { left, top, width, height }; return ret; @@ -1033,59 +1035,41 @@ - (void)drawInRect:(CGRect)pos { */ - (void)drawInRect:(CGRect)pos blendMode:(CGBlendMode)mode alpha:(float)alpha { // [BUG: Need to honor mode and alpha] - CGContextRef cur = UIGraphicsGetCurrentContext(); + CGContextRef ctx = UIGraphicsGetCurrentContext(); + CGImageRef img = getImage(self); - if (!getImage(self)) { + if (img == NULL) { TraceWarning(TAG, L"m_pImage = NULL!"); return; } - CGContextSaveGState(cur); - CGContextSetBlendMode(cur, mode); + CGContextSaveGState(ctx); + CGContextSetBlendMode(ctx, mode); - if (alpha != 1.0) { + if (alpha != 1.0f) { TraceVerbose(TAG, L"Should draw with alpha"); } - if (_scale == 0) { + if (_scale == 0.0f) { TraceWarning(TAG, L"Scale should be non-zero!"); return; } - if (_imageInsets.left == 0 && _imageInsets.top == 0 && _imageInsets.right == 0 && _imageInsets.bottom == 0) { - CGRect srcRect; - CGRect destRect = pos; + // Destination rect taken from pos with origin transformed from TL to BL + CGRect dstRect; + dstRect.origin = { pos.origin.x, (static_cast(CGBitmapContextGetHeight(ctx)) - pos.origin.y - pos.size.height) }; + dstRect.size = pos.size; - srcRect.origin.x = 0; - srcRect.origin.y = 0; - srcRect.size.width = float(getImage(self)->Backing()->Width()); - srcRect.size.height = float(getImage(self)->Backing()->Height()); + CGImageBacking* imgBacking = img->Backing(); - // Invert srcRect - srcRect.origin.y = getImage(self)->Backing()->Height() - srcRect.origin.y; - srcRect.size.height = -srcRect.size.height; - CGContextDrawImageRect(cur, getImage(self), srcRect, destRect); - } else { - static const CGPatternCallbacks patCB = { 0, drawNinePatchCallBack, NULL }; - insetInfo ii = { self, makeRect(0, 0, pos.size.width * _scale, pos.size.height * _scale) }; - - CGPatternRef pat = CGPatternCreate((void*)&ii, - makeRect(0, 0, pos.size.width * _scale, pos.size.height * _scale), - CGAffineTransformMakeScale(_scale, _scale), - 10, - 10, - kCGPatternTilingConstantSpacing, - true, - &patCB); - - CGFloat alpha = 1.0f; - CGContextSetFillPattern(cur, pat, &alpha); - CGContextFillRect(cur, pos); - - CGPatternRelease(pat); - } + CGRect srcRect; + srcRect.origin = { 0 }; + srcRect.size = { static_cast(imgBacking->Width()), static_cast(imgBacking->Height()) }; - CGContextRestoreGState(cur); + // Draw image and divide into patches if necessary + drawPatches(ctx, self, &srcRect, &dstRect); + + CGContextRestoreGState(ctx); } - (void)setOrientation:(UIImageOrientation)orientation { From be5942a5c5a7e9c3f180766a0bfdd85bcb5316d8 Mon Sep 17 00:00:00 2001 From: Shahmeer Esmail Date: Mon, 11 Jul 2016 15:49:55 -0700 Subject: [PATCH 2/7] Moved a comment inside an if statement. --- Frameworks/UIKit/UIImage.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frameworks/UIKit/UIImage.mm b/Frameworks/UIKit/UIImage.mm index a7d46997d5..b560d2fb11 100644 --- a/Frameworks/UIKit/UIImage.mm +++ b/Frameworks/UIKit/UIImage.mm @@ -789,8 +789,8 @@ static inline void drawPatches(CGContextRef context, UIImage* img, CGRect* src, } if (botCap) { - // BL Corner if (leftCap) { + // BL Corner CGContextDrawImageRect(context, cgImg, makeRect(0, 0, leftCap, botCap), From e110851f4e91b2d4bd1e318128f7ba495bf6c5d7 Mon Sep 17 00:00:00 2001 From: Shahmeer Esmail Date: Tue, 12 Jul 2016 16:30:21 -0700 Subject: [PATCH 3/7] Replace asserts with UNSUPPORTED_MSG macros. --- Frameworks/UIKit/UIImage.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Frameworks/UIKit/UIImage.mm b/Frameworks/UIKit/UIImage.mm index b560d2fb11..53f71b0aa3 100644 --- a/Frameworks/UIKit/UIImage.mm +++ b/Frameworks/UIKit/UIImage.mm @@ -739,7 +739,7 @@ static inline void drawPatches(CGContextRef context, UIImage* img, CGRect* src, (dst->size.width - leftCap - rightCap), (dst->size.height - topCap - botCap))); } else { - assert(0); + UNIMPLEMENTED_MSG("Patched draws only supported when sum of leftCap and rightCap is less than the width of the UI element."); } if (rightCap) { @@ -753,7 +753,7 @@ static inline void drawPatches(CGContextRef context, UIImage* img, CGRect* src, (dst->size.height - topCap - botCap))); } } else { - assert(0); + UNIMPLEMENTED_WITH_MSG("Patched draws only supported when sum of topCap and botCap is less than the height of the UI element."); } if (topCap) { From 799c50c382c511eaa830564c0b481deeae9ff682 Mon Sep 17 00:00:00 2001 From: Shahmeer Esmail Date: Tue, 12 Jul 2016 16:31:41 -0700 Subject: [PATCH 4/7] Minor change. --- Frameworks/UIKit/UIImage.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frameworks/UIKit/UIImage.mm b/Frameworks/UIKit/UIImage.mm index 53f71b0aa3..697e791db1 100644 --- a/Frameworks/UIKit/UIImage.mm +++ b/Frameworks/UIKit/UIImage.mm @@ -739,7 +739,7 @@ static inline void drawPatches(CGContextRef context, UIImage* img, CGRect* src, (dst->size.width - leftCap - rightCap), (dst->size.height - topCap - botCap))); } else { - UNIMPLEMENTED_MSG("Patched draws only supported when sum of leftCap and rightCap is less than the width of the UI element."); + UNIMPLEMENTED_WITH_MSG("Patched draws only supported when sum of leftCap and rightCap is less than the width of the UI element."); } if (rightCap) { From b6bf84c2e61672a2ccb49cd142aae4170fe6d5be Mon Sep 17 00:00:00 2001 From: Shahmeer Esmail Date: Thu, 21 Jul 2016 16:50:03 -0700 Subject: [PATCH 5/7] Implement opacity and blendMode settings in drawRect(pos), drawRect(pos, blendMode, alpha), drawAtPoint(pos), drawAtPoint(pos, blendMode, alpha) - When alpha and blendMode are not provided in drawRect and drawAtPoint functions, use values from the current graphics state instead of hardcoded values which force full opacity or transparency and a KCGBlendModeNormal and thus ignoring the app's intentions - In drawRect/drawAtPoint, set opacity (alpha) as part of draw setup - Use cairo_paint_with_alpha using the current alpha/opacity state instead of using just cairo_paint --- Frameworks/CoreGraphics/CGContext.mm | 4 ---- Frameworks/CoreGraphics/CGContextCairo.mm | 8 ++++---- Frameworks/UIKit/UIImage.mm | 21 +++++++++++---------- Frameworks/include/CGContextImpl.h | 2 ++ Frameworks/include/CGContextInternal.h | 8 ++++++-- include/CoreGraphics/CGContext.h | 3 ++- 6 files changed, 25 insertions(+), 21 deletions(-) diff --git a/Frameworks/CoreGraphics/CGContext.mm b/Frameworks/CoreGraphics/CGContext.mm index 0390fa170c..c66142bd05 100644 --- a/Frameworks/CoreGraphics/CGContext.mm +++ b/Frameworks/CoreGraphics/CGContext.mm @@ -70,10 +70,6 @@ - (void)dealloc { delete _backing; } -CGContextImpl* __CGContext::Backing() { - return _backing; -} - /** @Status Interoperable */ diff --git a/Frameworks/CoreGraphics/CGContextCairo.mm b/Frameworks/CoreGraphics/CGContextCairo.mm index ebf444714d..77f4885038 100644 --- a/Frameworks/CoreGraphics/CGContextCairo.mm +++ b/Frameworks/CoreGraphics/CGContextCairo.mm @@ -325,7 +325,7 @@ cairo_new_path(_drawContext); cairo_rectangle(_drawContext, 0, 0, dest.size.width, dest.size.height); cairo_clip(_drawContext); - cairo_paint(_drawContext); + cairo_paint_with_alpha(_drawContext, curState->curFillColor.a); cairo_restore(_drawContext); cairo_new_path(_drawContext); @@ -375,7 +375,7 @@ cairo_clip(_drawContext); if (curState->_imgMask == NULL) { - cairo_paint(_drawContext); + cairo_paint_with_alpha(_drawContext, curState->curFillColor.a); } else { cairo_mask_surface(_drawContext, curState->_imgMask->Backing()->LockCairoSurface(), 0.0, 0.0); curState->_imgMask->Backing()->ReleaseCairoSurface(); @@ -1420,7 +1420,7 @@ cairo_mask_surface(_drawContext, curState->_imgMask->Backing()->LockCairoSurface(), 0.0, 0.0); curState->_imgMask->Backing()->ReleaseCairoSurface(); } else { - cairo_paint(_drawContext); + cairo_paint_with_alpha(_drawContext, curState->curFillColor.a); } cairo_pattern_destroy(pattern); UNLOCK_CAIRO(); @@ -1461,7 +1461,7 @@ cairo_mask_surface(_drawContext, curState->_imgMask->Backing()->LockCairoSurface(), 0.0, 0.0); curState->_imgMask->Backing()->ReleaseCairoSurface(); } else { - cairo_paint(_drawContext); + cairo_paint_with_alpha(_drawContext, curState->curFillColor.a); } cairo_pattern_destroy(pattern); UNLOCK_CAIRO(); diff --git a/Frameworks/UIKit/UIImage.mm b/Frameworks/UIKit/UIImage.mm index 697e791db1..5829663d12 100644 --- a/Frameworks/UIKit/UIImage.mm +++ b/Frameworks/UIKit/UIImage.mm @@ -667,7 +667,8 @@ - (void)draw1PartImageInRect:(CGRect)pos { @Status Interoperable */ - (void)drawAtPoint:(CGPoint)point { - [self drawAtPoint:CGPointMake(point.x, point.y) blendMode:kCGBlendModeNormal alpha:0.0f]; + const CGContextImpl* ctxImpl = UIGraphicsGetCurrentContext()->Backing(); + [self drawAtPoint:point blendMode:ctxImpl->GetBlendMode() alpha:ctxImpl->GetAlpha()]; } /** @@ -685,7 +686,9 @@ - (void)drawAtPoint:(CGPoint)point blendMode:(CGBlendMode)mode alpha:(float)alph } CGContextSaveGState(cur); + CGContextSetBlendMode(cur, mode); + CGContextSetAlpha(cur, alpha); CGRect srcRect; CGRect pos; @@ -1027,14 +1030,14 @@ static void drawLeftAndTopCap(UIImage* self, CGContextRef ctx, CGRect rect) { @Status Interoperable */ - (void)drawInRect:(CGRect)pos { - [self drawInRect:pos blendMode:kCGBlendModeNormal alpha:1.0f]; + CGContextImpl* ctxImpl = UIGraphicsGetCurrentContext()->Backing(); + [self drawInRect:pos blendMode:ctxImpl->GetBlendMode() alpha:ctxImpl->GetAlpha()]; } /** @Status Interoperable */ - (void)drawInRect:(CGRect)pos blendMode:(CGBlendMode)mode alpha:(float)alpha { - // [BUG: Need to honor mode and alpha] CGContextRef ctx = UIGraphicsGetCurrentContext(); CGImageRef img = getImage(self); @@ -1043,18 +1046,16 @@ - (void)drawInRect:(CGRect)pos blendMode:(CGBlendMode)mode alpha:(float)alpha { return; } - CGContextSaveGState(ctx); - CGContextSetBlendMode(ctx, mode); - - if (alpha != 1.0f) { - TraceVerbose(TAG, L"Should draw with alpha"); - } - if (_scale == 0.0f) { TraceWarning(TAG, L"Scale should be non-zero!"); return; } + CGContextSaveGState(ctx); + + CGContextSetBlendMode(ctx, mode); + CGContextSetAlpha(ctx, alpha); + // Destination rect taken from pos with origin transformed from TL to BL CGRect dstRect; dstRect.origin = { pos.origin.x, (static_cast(CGBitmapContextGetHeight(ctx)) - pos.origin.y - pos.size.height) }; diff --git a/Frameworks/include/CGContextImpl.h b/Frameworks/include/CGContextImpl.h index 183074f092..ee9eccc697 100644 --- a/Frameworks/include/CGContextImpl.h +++ b/Frameworks/include/CGContextImpl.h @@ -71,6 +71,8 @@ __CGCONTEXTIMPL_TEST_FRIENDS; virtual void ObtainLock(); public: + inline float GetAlpha() const { return curState->curFillColor.a; } + inline CGBlendMode GetBlendMode() const { return curState->curBlendMode; } virtual void ReleaseLock(); virtual void DrawImage(CGImageRef img, CGRect src, CGRect dest, bool tiled = false); diff --git a/Frameworks/include/CGContextInternal.h b/Frameworks/include/CGContextInternal.h index ab1fe24bf7..07bca0b44d 100644 --- a/Frameworks/include/CGContextInternal.h +++ b/Frameworks/include/CGContextInternal.h @@ -47,14 +47,18 @@ COREGRAPHICS_EXPORT CGImageRef CGJPEGImageCreateFromData(NSData* data); COREGRAPHICS_EXPORT bool CGContextIsPointInPath(CGContextRef c, bool eoFill, float x, float y); class __CGContext : private objc_object { +private: + CGContextImpl* _backing; + public: float scale; - CGContextImpl* _backing; __CGContext(CGImageRef pDest); ~__CGContext(); - CGContextImpl* Backing(); + inline CGContextImpl* Backing() { + return _backing; + } }; #include "CGContextImpl.h" diff --git a/include/CoreGraphics/CGContext.h b/include/CoreGraphics/CGContext.h index b3e6f3238a..cb1c3fdc44 100644 --- a/include/CoreGraphics/CGContext.h +++ b/include/CoreGraphics/CGContext.h @@ -64,7 +64,8 @@ typedef enum { kCGBlendModeDestinationAtop, kCGBlendModeXOR, kCGBlendModePlusDarker, - kCGBlendModePlusLighter + kCGBlendModePlusLighter, + kCGBlendModeInvalid, } CGBlendMode; typedef enum { kCGTextFill, From 532b33e68ad931ec90882b591204d6088b9fde9d Mon Sep 17 00:00:00 2001 From: Shahmeer Esmail Date: Thu, 21 Jul 2016 16:56:54 -0700 Subject: [PATCH 6/7] Update copyright headers and remove kCGBlendModeInvalid enum --- Frameworks/CoreGraphics/CGContext.mm | 1 + Frameworks/CoreGraphics/CGContextCairo.mm | 1 + Frameworks/include/CGContextImpl.h | 1 + Frameworks/include/CGContextInternal.h | 1 + include/CoreGraphics/CGContext.h | 3 +-- 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Frameworks/CoreGraphics/CGContext.mm b/Frameworks/CoreGraphics/CGContext.mm index c66142bd05..97118dc5d7 100644 --- a/Frameworks/CoreGraphics/CGContext.mm +++ b/Frameworks/CoreGraphics/CGContext.mm @@ -1,5 +1,6 @@ //****************************************************************************** // +// Copyright (c) 2016 Intel Corporation. All rights reserved. // Copyright (c) 2016 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). diff --git a/Frameworks/CoreGraphics/CGContextCairo.mm b/Frameworks/CoreGraphics/CGContextCairo.mm index 77f4885038..c4cd4bed9f 100644 --- a/Frameworks/CoreGraphics/CGContextCairo.mm +++ b/Frameworks/CoreGraphics/CGContextCairo.mm @@ -1,5 +1,6 @@ //****************************************************************************** // +// Copyright (c) 2016 Intel Corporation. All rights reserved. // Copyright (c) 2016 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). diff --git a/Frameworks/include/CGContextImpl.h b/Frameworks/include/CGContextImpl.h index ee9eccc697..4f5d2ea241 100644 --- a/Frameworks/include/CGContextImpl.h +++ b/Frameworks/include/CGContextImpl.h @@ -1,5 +1,6 @@ //****************************************************************************** // +// Copyright (c) 2016 Intel Corporation. All rights reserved. // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). diff --git a/Frameworks/include/CGContextInternal.h b/Frameworks/include/CGContextInternal.h index 07bca0b44d..c403640072 100644 --- a/Frameworks/include/CGContextInternal.h +++ b/Frameworks/include/CGContextInternal.h @@ -1,5 +1,6 @@ //****************************************************************************** // +// Copyright (c) 2016 Intel Corporation. All rights reserved. // Copyright (c) 2015 Microsoft Corporation. All rights reserved. // // This code is licensed under the MIT License (MIT). diff --git a/include/CoreGraphics/CGContext.h b/include/CoreGraphics/CGContext.h index cb1c3fdc44..b3e6f3238a 100644 --- a/include/CoreGraphics/CGContext.h +++ b/include/CoreGraphics/CGContext.h @@ -64,8 +64,7 @@ typedef enum { kCGBlendModeDestinationAtop, kCGBlendModeXOR, kCGBlendModePlusDarker, - kCGBlendModePlusLighter, - kCGBlendModeInvalid, + kCGBlendModePlusLighter } CGBlendMode; typedef enum { kCGTextFill, From 51f4f4f112456ffe52059882c3529c7e7bcb4af9 Mon Sep 17 00:00:00 2001 From: Shahmeer Esmail Date: Fri, 22 Jul 2016 17:53:06 -0700 Subject: [PATCH 7/7] Removed makeRect and substituted previous references to it with CGMakeRect, removed unused static functions, made changes to drawInRect(pos) and drawAtPoint(pos) so that blendMode and alpha default to normal and 1.0f as per the spec. --- Frameworks/UIKit/UIImage.mm | 271 +++++------------------------------- 1 file changed, 33 insertions(+), 238 deletions(-) diff --git a/Frameworks/UIKit/UIImage.mm b/Frameworks/UIKit/UIImage.mm index 5829663d12..b6a817fea4 100644 --- a/Frameworks/UIKit/UIImage.mm +++ b/Frameworks/UIKit/UIImage.mm @@ -667,20 +667,22 @@ - (void)draw1PartImageInRect:(CGRect)pos { @Status Interoperable */ - (void)drawAtPoint:(CGPoint)point { - const CGContextImpl* ctxImpl = UIGraphicsGetCurrentContext()->Backing(); - [self drawAtPoint:point blendMode:ctxImpl->GetBlendMode() alpha:ctxImpl->GetAlpha()]; + [self drawAtPoint:point blendMode:kCGBlendModeNormal alpha:1.0f]; } /** @Status Interoperable */ -- (void)drawAtPoint:(CGPoint)point blendMode:(CGBlendMode)mode alpha:(float)alpha { +-(void)drawAtPoint:(CGPoint)point blendMode : (CGBlendMode)mode alpha : (float)alpha { CGContextRef cur = UIGraphicsGetCurrentContext(); + CGImageRef img = getImage(self); + if (!cur) { TraceVerbose(TAG, L"CGContext = NULL!"); return; } - if (!getImage(self)) { + + if (!img) { TraceVerbose(TAG, L"m_pImage = NULL!"); return; } @@ -690,18 +692,20 @@ - (void)drawAtPoint:(CGPoint)point blendMode:(CGBlendMode)mode alpha:(float)alph CGContextSetBlendMode(cur, mode); CGContextSetAlpha(cur, alpha); + CGImageBacking* imgBacking = img->Backing(); + CGRect srcRect; CGRect pos; pos.origin = point; - pos.size.width = ((float)getImage(self)->Backing()->Width() / _scale); - pos.size.height = ((float)getImage(self)->Backing()->Height() / _scale); + pos.size.width = ((float)imgBacking->Width()); + pos.size.height = ((float)imgBacking->Height()); srcRect.origin.x = 0; - srcRect.origin.y = float(getImage(self)->Backing()->Height()); - srcRect.size.width = float(getImage(self)->Backing()->Width()); - srcRect.size.height = -((float)getImage(self)->Backing()->Height()); + srcRect.origin.y = float(imgBacking->Height()); + srcRect.size.width = float(imgBacking->Width()); + srcRect.size.height = -((float)imgBacking->Height()); - CGContextDrawImageRect(cur, getImage(self), srcRect, pos); + CGContextDrawImageRect(cur, img, srcRect, pos); CGContextRestoreGState(cur); } @@ -728,16 +732,16 @@ static inline void drawPatches(CGContextRef context, UIImage* img, CGRect* src, // MidHeightLeft CGContextDrawImageRect(context, cgImg, - makeRect(0, botCap, leftCap, (src->size.height - topCap - botCap)), - makeRect(dst->origin.x, (dst->origin.y + botCap), leftCap, (dst->size.height - topCap - botCap))); + CGRectMake(0, botCap, leftCap, (src->size.height - topCap - botCap)), + CGRectMake(dst->origin.x, (dst->origin.y + botCap), leftCap, (dst->size.height - topCap - botCap))); } if (src->size.width - leftCap - rightCap > 0) { // MidHeightMidWidth CGContextDrawImageRect(context, cgImg, - makeRect(leftCap, botCap, (src->size.width - leftCap - rightCap), (src->size.height - topCap - botCap)), - makeRect((dst->origin.x + leftCap), + CGRectMake(leftCap, botCap, (src->size.width - leftCap - rightCap), (src->size.height - topCap - botCap)), + CGRectMake((dst->origin.x + leftCap), (dst->origin.y + botCap), (dst->size.width - leftCap - rightCap), (dst->size.height - topCap - botCap))); @@ -749,8 +753,8 @@ static inline void drawPatches(CGContextRef context, UIImage* img, CGRect* src, // MidHeightRight CGContextDrawImageRect(context, cgImg, - makeRect((src->size.width - rightCap), botCap, rightCap, (src->size.height - topCap - botCap)), - makeRect((dst->origin.x + dst->size.width - rightCap), + CGRectMake((src->size.width - rightCap), botCap, rightCap, (src->size.height - topCap - botCap)), + CGRectMake((dst->origin.x + dst->size.width - rightCap), (dst->origin.y + botCap), rightCap, (dst->size.height - topCap - botCap))); @@ -764,16 +768,16 @@ static inline void drawPatches(CGContextRef context, UIImage* img, CGRect* src, // TL corner CGContextDrawImageRect(context, cgImg, - makeRect(0, (src->size.height - topCap), leftCap, topCap), - makeRect(dst->origin.x, (dst->origin.y + dst->size.height - topCap), leftCap, topCap)); + CGRectMake(0, (src->size.height - topCap), leftCap, topCap), + CGRectMake(dst->origin.x, (dst->origin.y + dst->size.height - topCap), leftCap, topCap)); } if (src->size.width - leftCap - rightCap > 0) { // TCenter CGContextDrawImageRect(context, cgImg, - makeRect(leftCap, (src->size.height - topCap), (src->size.width - leftCap - rightCap), topCap), - makeRect((dst->origin.x + leftCap), + CGRectMake(leftCap, (src->size.height - topCap), (src->size.width - leftCap - rightCap), topCap), + CGRectMake((dst->origin.x + leftCap), (dst->origin.y + dst->size.height - topCap), (dst->size.width - leftCap - rightCap), topCap)); @@ -783,8 +787,8 @@ static inline void drawPatches(CGContextRef context, UIImage* img, CGRect* src, // TR corner CGContextDrawImageRect(context, cgImg, - makeRect((src->size.width - rightCap), (src->size.height - topCap), rightCap, topCap), - makeRect((dst->origin.x + dst->size.width - rightCap), + CGRectMake((src->size.width - rightCap), (src->size.height - topCap), rightCap, topCap), + CGRectMake((dst->origin.x + dst->size.width - rightCap), (dst->origin.y + dst->size.height - topCap), rightCap, topCap)); @@ -796,242 +800,33 @@ static inline void drawPatches(CGContextRef context, UIImage* img, CGRect* src, // BL Corner CGContextDrawImageRect(context, cgImg, - makeRect(0, 0, leftCap, botCap), - makeRect(dst->origin.x, dst->origin.y, leftCap, botCap)); + CGRectMake(0, 0, leftCap, botCap), + CGRectMake(dst->origin.x, dst->origin.y, leftCap, botCap)); } if (src->size.width - leftCap - rightCap > 0) { // bottomMidWidth CGContextDrawImageRect(context, cgImg, - makeRect(leftCap, 0, (src->size.width - leftCap - rightCap), botCap), - makeRect((dst->origin.x + leftCap), dst->origin.y, (dst->size.width - leftCap - rightCap), botCap)); + CGRectMake(leftCap, 0, (src->size.width - leftCap - rightCap), botCap), + CGRectMake((dst->origin.x + leftCap), dst->origin.y, (dst->size.width - leftCap - rightCap), botCap)); } if (rightCap) { // BR corner CGContextDrawImageRect(context, cgImg, - makeRect((src->size.width - rightCap), 0, rightCap, botCap), - makeRect((dst->origin.x + dst->size.width - rightCap), dst->origin.y, rightCap, botCap)); + CGRectMake((src->size.width - rightCap), 0, rightCap, botCap), + CGRectMake((dst->origin.x + dst->size.width - rightCap), dst->origin.y, rightCap, botCap)); } } } -static void drawLeftCap(UIImage* self, CGContextRef cur, CGRect pos) { - CGRect srcRect; - CGRect destRect = pos; - - srcRect.origin.x = 0; - srcRect.origin.y = 0; - srcRect.size.width = float(getImage(self)->Backing()->Width()); - srcRect.size.height = float(getImage(self)->Backing()->Height()); - - CGRect drawRect, capRect; - - // Draw the left cap - drawRect.origin.x = destRect.origin.x; - drawRect.origin.y = destRect.origin.y; - drawRect.size.width = self->_imageInsets.left; - drawRect.size.height = destRect.size.height; - - capRect = srcRect; - capRect.size.width = self->_imageInsets.left; - - capRect.origin.y = getImage(self)->Backing()->Height() - capRect.origin.y; - capRect.size.height = -capRect.size.height; - - float minX = drawRect.origin.x + drawRect.size.width; - CGContextDrawImageRect(cur, getImage(self), capRect, drawRect); - - // Draw cap fragment - drawRect.origin.x = destRect.origin.x + self->_imageInsets.left; - drawRect.origin.y = destRect.origin.y; - drawRect.size.width = pos.size.width - srcRect.size.width; - drawRect.size.height = destRect.size.height; - - capRect.origin.x = self->_imageInsets.left; - capRect.origin.y = getImage(self)->Backing()->Height() - srcRect.origin.y; - capRect.size.width = 1; - capRect.size.height = -srcRect.size.height; - if (drawRect.size.width > 0.0f) { - CGContextDrawImageRect(cur, getImage(self), capRect, drawRect); - } - - // Adjust the source and desination rects - srcRect.origin.x = self->_imageInsets.left; - srcRect.size.width = getImage(self)->Backing()->Width() - self->_imageInsets.left; - destRect.origin.x += pos.size.width - (srcRect.size.width); - destRect.size.width = srcRect.size.width; - - // Invert srcRect - srcRect.origin.y = getImage(self)->Backing()->Height() - srcRect.origin.y; - srcRect.size.height = -srcRect.size.height; - - if (destRect.origin.x < minX) { - float diff = minX - destRect.origin.x; - destRect.origin.x += diff; - destRect.size.width -= diff; - srcRect.origin.x += diff; - srcRect.size.width -= diff; - } - if (destRect.size.width > 0.0f) { - CGContextDrawImageRect(cur, getImage(self), srcRect, destRect); - } -} - -static void drawTopCap(UIImage* self, CGContextRef cur, CGRect pos) { - CGRect srcRect; - CGRect destRect = pos; - - srcRect.origin.x = 0; - srcRect.origin.y = 0; - srcRect.size.width = float(getImage(self)->Backing()->Width()); - srcRect.size.height = float(getImage(self)->Backing()->Height()); - - CGRect drawRect, capRect; - - // Draw the left cap - drawRect.origin.x = destRect.origin.x; - drawRect.origin.y = destRect.origin.y; - drawRect.size.width = destRect.size.width; - drawRect.size.height = self->_imageInsets.top; - - capRect = srcRect; - capRect.size.height = self->_imageInsets.top; - - capRect.origin.y = getImage(self)->Backing()->Height() - capRect.origin.y; - capRect.size.height = -capRect.size.height; - - CGContextDrawImageRect(cur, getImage(self), capRect, drawRect); - - // Draw cap fragment - drawRect.origin.x = destRect.origin.x; - drawRect.origin.y = destRect.origin.y + self->_imageInsets.top; - drawRect.size.width = destRect.size.width; - drawRect.size.height = pos.size.height - srcRect.size.height; - - capRect.origin.x = srcRect.origin.x; - capRect.origin.y = self->_imageInsets.top; - capRect.size.width = srcRect.size.width; - capRect.size.height = -1; - CGContextDrawImageRect(cur, getImage(self), capRect, drawRect); - - // Adjust the source and desination rects - srcRect.origin.y = self->_imageInsets.top; - srcRect.size.height = getImage(self)->Backing()->Height() - self->_imageInsets.top; - destRect.origin.y += pos.size.height - srcRect.size.height; - destRect.size.height = srcRect.size.height; - - // Invert srcRect - srcRect.origin.y = getImage(self)->Backing()->Height() - srcRect.origin.y; - srcRect.size.height = -srcRect.size.height; - CGContextDrawImageRect(cur, getImage(self), srcRect, destRect); -} - -static void drawFromRect(UIImage* self, CGContextRef ctx, CGRect dest, CGRect source) { - source.origin.x *= self->_scale; - source.origin.y *= self->_scale; - source.size.width *= self->_scale; - source.size.height *= self->_scale; - - source.origin.y = getImage(self)->Backing()->Height() - source.origin.y; - source.size.height = -source.size.height; - - CGContextDrawImageRect(ctx, getImage(self), source, dest); -} - -static inline CGRect makeRect(float left, float top, float width, float height) { - CGRect ret = { left, top, width, height }; - - return ret; -} - -static void drawLeftAndTopCap(UIImage* self, CGContextRef ctx, CGRect rect) { - CGSize size = { 0, 0 }; - size = [self size]; - // FIXME: Floating point accuracy messes with the seams. - float stretchyWidth = (self->_imageInsets.left < size.width) ? 0.999f : 0.f; - float stretchyHeight = (self->_imageInsets.top < size.height) ? 0.999f : 0.f; - float bottomCapHeight = size.height - self->_imageInsets.top - stretchyHeight; - float rightCapWidth = size.width - self->_imageInsets.left - stretchyWidth; - - // topLeftCorner - drawFromRect(self, - ctx, - makeRect(CGRectGetMinX(rect), CGRectGetMinY(rect), self->_imageInsets.left, self->_imageInsets.top), - makeRect(0, 0, self->_imageInsets.left, self->_imageInsets.top)); - - // topEdgeFill - drawFromRect(self, - ctx, - makeRect(CGRectGetMinX(rect) + self->_imageInsets.left, - CGRectGetMinY(rect), - rect.size.width - rightCapWidth - self->_imageInsets.left, - self->_imageInsets.top), - makeRect(self->_imageInsets.left, 0, stretchyWidth, self->_imageInsets.top)); - - // topRightCorner - drawFromRect(self, - ctx, - makeRect(CGRectGetMaxX(rect) - rightCapWidth, CGRectGetMinY(rect), rightCapWidth, self->_imageInsets.top), - makeRect(size.width - rightCapWidth, 0, rightCapWidth, self->_imageInsets.top)); - - // bottomLeftCorner - drawFromRect(self, - ctx, - makeRect(CGRectGetMinX(rect), CGRectGetMaxY(rect) - bottomCapHeight, self->_imageInsets.left, bottomCapHeight), - makeRect(0, size.height - bottomCapHeight, self->_imageInsets.left, bottomCapHeight)); - - // bottomEdgeFill - drawFromRect(self, - ctx, - makeRect(CGRectGetMinX(rect) + self->_imageInsets.left, - CGRectGetMaxY(rect) - bottomCapHeight, - rect.size.width - rightCapWidth - self->_imageInsets.left, - bottomCapHeight), - makeRect(self->_imageInsets.left, size.height - bottomCapHeight, stretchyWidth, bottomCapHeight)); - - // bottomRightCorner - drawFromRect(self, - ctx, - makeRect(CGRectGetMaxX(rect) - rightCapWidth, CGRectGetMaxY(rect) - bottomCapHeight, rightCapWidth, bottomCapHeight), - makeRect(size.width - rightCapWidth, size.height - bottomCapHeight, rightCapWidth, bottomCapHeight)); - - // leftEdgeFill - drawFromRect(self, - ctx, - makeRect(CGRectGetMinX(rect), - CGRectGetMinY(rect) + self->_imageInsets.top, - self->_imageInsets.left, - rect.size.height - bottomCapHeight - self->_imageInsets.top), - makeRect(0, self->_imageInsets.top, self->_imageInsets.left, stretchyHeight)); - - // rightEdgeFill - drawFromRect(self, - ctx, - makeRect(CGRectGetMaxX(rect) - rightCapWidth, - CGRectGetMinY(rect) + self->_imageInsets.top, - rightCapWidth, - rect.size.height - bottomCapHeight - self->_imageInsets.top), - makeRect(size.width - rightCapWidth, self->_imageInsets.top, rightCapWidth, stretchyHeight)); - - // centerFill - drawFromRect(self, - ctx, - makeRect(CGRectGetMinX(rect) + self->_imageInsets.left, - CGRectGetMinY(rect) + self->_imageInsets.top, - rect.size.width - rightCapWidth - self->_imageInsets.left, - rect.size.height - bottomCapHeight - self->_imageInsets.top), - makeRect(self->_imageInsets.left, self->_imageInsets.top, stretchyWidth, stretchyHeight)); -} - /** @Status Interoperable */ - (void)drawInRect:(CGRect)pos { - CGContextImpl* ctxImpl = UIGraphicsGetCurrentContext()->Backing(); - [self drawInRect:pos blendMode:ctxImpl->GetBlendMode() alpha:ctxImpl->GetAlpha()]; + [self drawInRect:pos blendMode:kCGBlendModeNormal alpha:1.0f]; } /**