Skip to content

Commit

Permalink
Implementation of Linear Gradients
Browse files Browse the repository at this point in the history
  • Loading branch information
msft-Jeyaram committed Dec 14, 2016
1 parent 497eb97 commit cb1baad
Show file tree
Hide file tree
Showing 15 changed files with 252 additions and 8 deletions.
58 changes: 55 additions & 3 deletions Frameworks/CoreGraphics/CGContext.mm
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
#import <CoreGraphics/CGPath.h>
#import <CoreGraphics/CGLayer.h>
#import <CoreGraphics/CGAffineTransform.h>
#import <CoreGraphics/CGGradient.h>
#import <LoggingNative.h>
#import <CoreGraphics/D2DWrapper.h>
#import "CGColorSpaceInternal.h"
#import "CGContextInternal.h"
#import "CGPathInternal.h"
#import "CGIWICBitmap.h"
#import "CGGradientInternal.h"

#import <CFCppBase.h>

Expand Down Expand Up @@ -2032,15 +2032,67 @@ void CGContextDrawTiledImage(CGContextRef context, CGRect rect, CGImageRef image
#pragma endregion

#pragma region Drawing Operations - Gradient + Shading
/*
* Convert CGGradient to D2D1_GRADIENT_STOP
*/
static inline std::vector<D2D1_GRADIENT_STOP> __CGGradientToD2D1GradientStop(CGGradientRef gradient) {
unsigned long gradientCount = _CGGradientGetCount(gradient);
std::vector<D2D1_GRADIENT_STOP> gradientStops(gradientCount);

float* colorComponenets = _CGGradientGetColorComponents(gradient);
float* locations = _CGGradientGetStopLocation(gradient);
for (unsigned long i = 0; i < gradientCount; ++i) {
unsigned int colorIndex = (i * 4);
gradientStops[i].color = D2D1::ColorF(colorComponenets[colorIndex],
colorComponenets[colorIndex + 1],
colorComponenets[colorIndex + 2],
colorComponenets[colorIndex + 3]);
gradientStops[i].position = locations[i];
}

return gradientStops;
}

/**
@Status Stub
@Status Caveat
@Notes kCGGradientDrawsAfterEndLocation option is applied by default.
*/
void CGContextDrawLinearGradient(
CGContextRef context, CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint, CGGradientDrawingOptions options) {
NOISY_RETURN_IF_NULL(context);
NOISY_RETURN_IF_NULL(gradient);
RETURN_IF(!context->ShouldDraw());

UNIMPLEMENTED();
RETURN_IF(_CGGradientGetCount(gradient) == 0);

std::vector<D2D1_GRADIENT_STOP> gradientStops = __CGGradientToD2D1GradientStop(gradient);

ComPtr<ID2D1GradientStopCollection> gradientStopCollection;

ComPtr<ID2D1DeviceContext> deviceContext = context->DeviceContext();
FAIL_FAST_IF_FAILED(deviceContext->CreateGradientStopCollection(gradientStops.data(),
gradientStops.size(),
D2D1_GAMMA_2_2,
D2D1_EXTEND_MODE_CLAMP,
&gradientStopCollection));

ComPtr<ID2D1LinearGradientBrush> linearGradientBrush;
FAIL_FAST_IF_FAILED(deviceContext->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(_CGPointToD2D_F(startPoint),
_CGPointToD2D_F(endPoint)),
gradientStopCollection.Get(),
&linearGradientBrush));

// set the transform for the brush and alpha
linearGradientBrush->SetTransform(__CGAffineTransformToD2D_F(CGContextGetUserSpaceToDeviceSpaceTransform(context)));
linearGradientBrush->SetOpacity(context->CurrentGState().alpha);

// Area to fill
D2D1_SIZE_F targetSize = deviceContext->GetSize();
D2D1_RECT_F region = D2D1::RectF(0, 0, targetSize.width, targetSize.height);

deviceContext->BeginDraw();
deviceContext->FillRectangle(&region, linearGradientBrush.Get());
FAIL_FAST_IF_FAILED(deviceContext->EndDraw());
}

/**
Expand Down
28 changes: 27 additions & 1 deletion Frameworks/CoreGraphics/CGGradient.mm
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ - (void)dealloc {
@end

__CGGradient::__CGGradient() : _components(NULL), _locations(NULL) {
object_setClass((id) this, [CGNSGradient class]);
object_setClass((id)this, [CGNSGradient class]);
}

__CGGradient::~__CGGradient() {
Expand Down Expand Up @@ -181,3 +181,29 @@ CFTypeID CGGradientGetTypeID() {
UNIMPLEMENTED();
return StubReturn();
}

float* _CGGradientGetStopLocation(CGGradientRef gradient) {
RETURN_NULL_IF(!gradient);
return gradient->_locations;
}

float* _CGGradientGetColorComponents(CGGradientRef gradient) {
RETURN_NULL_IF(!gradient);
return gradient->_components;
}

unsigned long _CGGradientGetCount(CGGradientRef gradient) {
if (!gradient) {
return 0;
}

return gradient->_count;
}

CGColorSpaceModel _CGGradientGetColorSpaceModel(CGGradientRef gradient) {
if (!gradient) {
return kCGColorSpaceModelRGB;
}

return gradient->_colorSpaceModel;
}
14 changes: 11 additions & 3 deletions Frameworks/include/CGGradientInternal.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//******************************************************************************
//
// Copyright (c) 2016 Intel Corporation. All rights reserved.
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
Expand All @@ -17,8 +17,8 @@

#pragma once

#include "CoreGraphics/CGGradient.h"
#include "CoreGraphicsInternal.h"
#import <CoreGraphics/CGGradient.h>
#import "CoreGraphicsInternal.h"
#include <objc/runtime.h>

class __CGGradient : private objc_object {
Expand All @@ -34,3 +34,11 @@ class __CGGradient : private objc_object {
void initWithColorComponents(const float* components, const float* locations, size_t count, CGColorSpaceRef colorspace);
void initWithColors(CFArrayRef components, const float* locations, CGColorSpaceRef colorspace);
};

COREGRAPHICS_EXPORT unsigned long _CGGradientGetCount(CGGradientRef gradient);

COREGRAPHICS_EXPORT float* _CGGradientGetStopLocation(CGGradientRef gradient);

COREGRAPHICS_EXPORT float* _CGGradientGetColorComponents(CGGradientRef gradient);

COREGRAPHICS_EXPORT CGColorSpaceModel _CGGradientGetColorSpaceModel(CGGradientRef gradient);
6 changes: 6 additions & 0 deletions build/CoreGraphics/dll/CoreGraphics.def
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,12 @@ LIBRARY CoreGraphics
_CGImageGetRawBytes
_CGImageGetDisplayTexture

; CGGradient private exports
_CGGradientGetCount
_CGGradientGetStopLocation
_CGGradientGetColorComponents
_CGGradientGetColorSpaceModel

; private exports below
CGImageAddDestructionListener

Expand Down
124 changes: 123 additions & 1 deletion tests/UnitTests/CoreGraphics.drawing/CGContextDrawingTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,129 @@ DISABLED_DRAW_TEST_F(CGContext, DrawIntoRect, UIKitMimicTest) {
}
#endif

DRAW_TEST_F(CGContext, LinearGradient, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
woc::unique_cf<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());

CGFloat locations[2] = { 1.0, 0.0 };
CGFloat components[8] = { 0.0, 0.5, 0.0, 1.0, 1.0, 1.0, 0.8, 1.0 };
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, 2);

CGPoint startPoint = CGPointMake(0, 0);
CGPoint endPoint = CGPointMake(512, 1024);

CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
}

DRAW_TEST_F(CGContext, LinearGradientInvalidCount, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
woc::unique_cf<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());

CGFloat locations[] = { 0.0 };

CGFloat components[] = {
0.85, 0, 0, 1.0,
};

CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, 0);
CGPoint startPoint = CGPointMake(0, 0);
CGPoint endPoint = CGPointMake(512, 1024);

CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
}

DRAW_TEST_F(CGContext, LinearGradient2, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
woc::unique_cf<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());

CGFloat locations[] = { 0.0, 0.33, 0.66, 1.0 };

CGFloat components[] = {
0.85, 0, 0, 1.0, 1, 0, 0, 1.0, 0.85, 0.3, 0, 1.0, 0.1, 0, 0.9, 1.0,
};

CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, 4);
CGPoint startPoint = CGPointMake(0, 0);
CGPoint endPoint = CGPointMake(512, 1024);

CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
}

DRAW_TEST_F(CGContext, LinearGradient3, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
woc::unique_cf<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());

CGFloat locations[] = { 0.0, 0.5, 1 };

CGFloat components[] = {
1, 0, 0, 1.0, 0, 1, 0, 1.0, 0, 0, 1, 1.0,
};

CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, 3);
CGPoint startPoint = CGPointMake(0, 0);
CGPoint endPoint = CGPointMake(512, 1024);

CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
}

DRAW_TEST_F(CGContext, LinearGradientWithLowOpacity, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
woc::unique_cf<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());

CGFloat locations[] = { 0.0, 0.5, 1 };

CGFloat components[] = {
1, 0, 0, 0.1, 0, 1, 0, 0.9, 0, 0, 1, 0.8,
};

CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, 3);
CGPoint startPoint = CGPointMake(512, 1024);
CGPoint endPoint = CGPointMake(0, 0);

CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
}

DRAW_TEST_F(CGContext, LinearGradientWithAlpha, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
woc::unique_cf<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());

CGFloat locations[] = { 0.0, 0.25, 0.5, 0.6, 0.8, 0.9, 1 };

CGFloat components[] = {
1, 0, 0, 1, 0.4, 0.1, 0.5, 1, 0.50, 0.2, 0.99, 1, 0.41, 0.56, 0, 1, 0.12, 0.12, .3, 1, 0.9, 0.4, 1, 1, 0.2, 0.3, 0.8, 1,
};

CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, 7);
CGPoint startPoint = CGPointMake(512, 1024);
CGPoint endPoint = CGPointMake(0, 0);

CGContextSetAlpha(context, 0.75);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
}

DRAW_TEST_F(CGContext, LinearGradientWithLowOpacityShort, UIKitMimicTest) {
CGContextRef context = GetDrawingContext();
woc::unique_cf<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());

CGFloat locations[] = { 0.0, 0.5, 1 };

CGFloat components[] = {
1, 0, 0, 0.8, 0, 1, 0, 0.9, 0, 0, 1, 0.1,
};

CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, 3);
CGPoint startPoint = CGPointMake(250, 300);
CGPoint endPoint = CGPointMake(0, 0);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, kCGGradientDrawsAfterEndLocation);
}

DISABLED_DRAW_TEST_F(CGContext, DrawAnImage, UIKitMimicTest) {
// Load an Image and draw it into the canvas context
auto drawingConfig = DrawingTestConfig::Get();
Expand Down Expand Up @@ -98,7 +221,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();
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit cb1baad

Please sign in to comment.