Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of Linear Gradient #1535

Merged
merged 5 commits into from
Dec 21, 2016

Conversation

msft-Jeyaram
Copy link
Contributor

@msft-Jeyaram msft-Jeyaram commented Dec 14, 2016

This change is Reviewable

@msft-Jeyaram msft-Jeyaram changed the title Linear gradient push Implementation of Linear Gradient Dec 14, 2016
@@ -36,7 +36,7 @@ - (void)dealloc {
@end

__CGGradient::__CGGradient() : _components(NULL), _locations(NULL) {
Copy link

@DHowett-MSFT DHowett-MSFT Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switch to CoreFoundation::CppBase? 😄 #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#1541 will in the future


In reply to: 92309043 [](ancestors = 92309043)

* Convert CGGradient to D2D1_GRADIENT_STOP
*/
static inline std::vector<D2D1_GRADIENT_STOP> __CGGradientToD2D1GradientStop(CGGradientRef gradient, CGGradientDrawingOptions options) {
unsigned long gradientCount = _CGGradientGetCount(gradient);
Copy link
Contributor

@aballway aballway Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super nit: no implicit int please #WontFix


float* colorComponenets = _CGGradientGetColorComponents(gradient);
float* locations = _CGGradientGetStopLocation(gradient);
for (unsigned long i = 0; i < gradientCount; ++i) {
Copy link
Contributor

@aballway aballway Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super nit: same as above #WontFix


float* colorComponenets = _CGGradientGetColorComponents(gradient);
float* locations = _CGGradientGetStopLocation(gradient);
for (unsigned long i = 0; i < gradientCount; ++i) {
Copy link
Contributor

@aballway aballway Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i += 4 would be clearer than multiplying below #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need the indexing to be incremental by 1 + keeps it simple


In reply to: 92449056 [](ancestors = 92449056)


if (options == kCGGradientDrawsAfterEndLocation) {
// Set the edge to be just a bit lower on the location
gradientStops[0].position = 1E-45;
Copy link
Contributor

@aballway aballway Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super magic number #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the comments explains it.
Pretty much get close to the border as possible.
so smallest delta is needed.


In reply to: 92449152 [](ancestors = 92449152)

Copy link
Contributor

@aballway aballway Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't mean you need an arbitrary value hardcoded in. FLT_MIN? #ByDesign

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sadly D2D is interpreting that as 0


In reply to: 92517563 [](ancestors = 92517563)

}

unsigned long _CGGradientGetCount(CGGradientRef gradient) {
if (!gradient) {
Copy link
Contributor

@aballway aballway Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: keep consistent with macro pattern #Resolved

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

class __CGGradient : private objc_object {
Copy link
Contributor

@aballway aballway Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should fix this class up while you're doing this. No DWORD, CppBase, etc. #WontFix

Copy link
Contributor Author

@msft-Jeyaram msft-Jeyaram Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not part of this scope.
Yep does definitely needs to be updated #1541


In reply to: 92450352 [](ancestors = 92450352)

Copy link
Contributor

@aballway aballway Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're implementing CGGradient in this PR, why not just fix it now? #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not implementing CGGradient (it's already implemented in a poor way).
I'm merely reading the data. It needs to be properly implemented (separate CR #1541)


In reply to: 92517645 [](ancestors = 92517645)


float* _CGGradientGetStopLocation(CGGradientRef gradient);

float* _CGGradientGetColorComponents(CGGradientRef gradient);
Copy link
Contributor

@aballway aballway Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't much like returning raw float* here. I think this entire class could use some updating #ByDesign

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, but again it's internal access + we can wrap it at a cost,


In reply to: 92450607 [](ancestors = 92450607)


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();
Copy link
Contributor

@aballway aballway Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to be released #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOL missed.


In reply to: 92450707 [](ancestors = 92450707)

@DHowett-MSFT
Copy link

DHowett-MSFT commented Dec 14, 2016 via email

@msft-Jeyaram
Copy link
Contributor Author

Created a bug, it isn't blocking this PR for say.
Still tracked figured out.


In reply to: 267120339 [](ancestors = 267120339)


if (options == kCGGradientDrawsAfterEndLocation) {
// Set the edge to be just a bit lower on the location
gradientStops[0].position = 1E-45;
Copy link
Contributor

@aballway aballway Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't mean you need an arbitrary value hardcoded in. FLT_MIN? #ByDesign

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

class __CGGradient : private objc_object {
Copy link
Contributor

@aballway aballway Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're implementing CGGradient in this PR, why not just fix it now? #WontFix

Copy link

@DHowett-MSFT DHowett-MSFT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rebase and remove tiled images.

D2D1_RECT_F region = D2D1::RectF(0, 0, targetSize.width, targetSize.height);

deviceContext->BeginDraw();
deviceContext->FillRectangle(&region, linearGradientBrush.Get());
Copy link

@DHowett-MSFT DHowett-MSFT Dec 15, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put this through the rendering stack as in my comment in #1542. Otherwise, you get no clipping and no masking and no global transform. #Resolved

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

@DHowett-MSFT DHowett-MSFT Dec 15, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are a good candidate for parameterized testing! #ByDesign

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

going to leave it as, there are too many parameters that will keep on changing and making it will reduce readability.


In reply to: 92529089 [](ancestors = 92529089)

@@ -2050,12 +2051,20 @@ void CGContextDrawTiledImage(CGContextRef context, CGRect rect, CGImageRef image
gradientStops[i].position = locations[i];
}

if (options == kCGGradientDrawsAfterEndLocation) {
Copy link

@DHowett-MSFT DHowett-MSFT Dec 15, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add support for kCGGradientDrawsBeforeStartLocation.

I don't know what this is doing, actually:
It's setting the start to be at 1E-45, and then setting the end (gradientCount) to be at .. 0?
So a gradient 0.1 0.2 0.3 would become: 1E-45 0.2 0.3 0 ??
#ByDesign

Copy link
Contributor Author

@msft-Jeyaram msft-Jeyaram Dec 16, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

talked off line, no that would be 1e-45, 0.1, 0.2, 0.3 ...
by default kCGGradientDrawsBeforeStartLocation is supported (it's pretty much a binary option)


In reply to: 92529276 [](ancestors = 92529276)

Copy link
Contributor

@aballway aballway left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you have test images for Tiled Images stuff in here, is that by design? :shipit:

// This will be used to insert the transparent color.
std::vector<D2D1_GRADIENT_STOP> gradientStops((options == kCGGradientDrawsAfterEndLocation) ? gradientCount + 1 : gradientCount);

float* colorComponenets = _CGGradientGetColorComponents(gradient);
Copy link
Contributor

@rajsesh rajsesh Dec 16, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

colorComponents. Also CGFloat* (could be different from float*) #Resolved

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 };
woc::unique_cf<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());
CGGradientRef gradient = CGGradientCreateWithColorComponents(rgbColorSpace.get(), components, locations, 2);
Copy link
Contributor

@aballway aballway Dec 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be released? #Resolved

0.85, 0, 0, 1.0,
};

CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
Copy link
Contributor

@aballway aballway Dec 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

71-77 is almost the same for all of these. Break into helper function #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

technically we are only going to be able to fully modularize 2-3 lines and we will have multitude of variables being passed in, which ends up being just like the DrawLinearGradient.


In reply to: 93269632 [](ancestors = 93269632)

/*
* Convert CGGradient to D2D1_GRADIENT_STOP
*/
static inline std::vector<D2D1_GRADIENT_STOP> __CGGradientToD2D1GradientStop(CGGradientRef gradient, CGGradientDrawingOptions options) {
Copy link
Contributor

@aballway aballway Dec 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems pretty hefty for an inline #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not supposed to be


In reply to: 93269884 [](ancestors = 93269884)

@@ -48,6 +48,8 @@

static const wchar_t* TAG = L"CGContext";

static float s_CGGradientStartPoint = 1E-45;
Copy link
Contributor

@aballway aballway Dec 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const? move comment explaining this to here #Resolved

// effect based on the extend mode). We support that by inserting a point (with transparent color) close to the start/end points, such
// that d2d will automatically extend the transparent color, thus we obtain the desired effect for CGGradientDrawingOptions.

switch (options) {
Copy link

@DHowett-MSFT DHowett-MSFT Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be modelled as two ifs. It looks like that is the intended configuration, since the two constants are bitshifted.

if (!(options & kCGGradientDrawsAfterEndLocation)) {
    // insert transparent end
}

if (!(options & ...before start...)) {
    // insert transparent start
}

Using a switch requires you to duplicate the stops in two different branches. #Closed

* Insert a transparent color at the specified 'location'.
* This will also move the color at the specified 'location' to the supplied 'position'
*/
static inline void __CGGradientInsertTransparentColor(std::vector<D2D1_GRADIENT_STOP>& gradientStops, int location, float position) {
Copy link

@DHowett-MSFT DHowett-MSFT Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not appear to insert them in order. Are we required to do that for D2D's sake? #ByDesign

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tested it and d2d uses the position rather than the order as it seems


In reply to: 93370134 [](ancestors = 93370134)

@@ -49,6 +50,9 @@

static const wchar_t* TAG = L"CGContext";

// Coordinate offset to support CGGradientDrawingOptions
static const float s_CGGradientStartPoint = 1E-45;
Copy link

@DHowett-MSFT DHowett-MSFT Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a "start point" but you are subtracting it from 1 later. That seems like a bad constant name :) #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOL yep


In reply to: 93370154 [](ancestors = 93370154)

CGFloat* colorComponents = _CGGradientGetColorComponents(gradient);
CGFloat* locations = _CGGradientGetStopLocation(gradient);
for (unsigned long i = 0; i < gradientCount; ++i) {
unsigned int colorIndex = (i * 4);
Copy link

@DHowett-MSFT DHowett-MSFT Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a note or a todo referencing the CGColorSpace issue; this hardcoded *4 will bite somebody otherwise. #Resolved

@@ -589,3 +589,181 @@ DRAW_TEST(CGContext, PremultipliedAlphaImage) {
CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 0.5);
CGContextFillRect(context, { 0, 0, 100, 100 });
}

#pragma region LinearGradient
Copy link

@DHowett-MSFT DHowett-MSFT Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move these to another drawing test file named similarly to the others? CGContext_GradientDrawingTests.cpp or something similar?

Our hygiene is subpar here, we can improve incrementally. #Resolved

_drawShortLinearGradientWithOptions(GetDrawingContext(), GetDrawingBounds(), 0);
}

DRAW_TEST_F(CGContext, LinearGradientShortBothSides_Options_kCGGradientDrawsBeforeStartLocation, UIKitMimicTest) {
Copy link

@DHowett-MSFT DHowett-MSFT Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each of these tests that resolves to a single function is better modelled as a parameterized test. #WontFix

Copy link

@DHowett-MSFT DHowett-MSFT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔢

D2D1_GRADIENT_STOP transparent;
transparent.color = D2D1::ColorF(0, 0, 0, 0);
transparent.position = location;
gradientStops.push_back(transparent);
Copy link
Contributor

@aballway aballway Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: just emplace_back{colorf..., location} #WontFix

}

if (!(options & kCGGradientDrawsAfterEndLocation)) {
__CGGradientInsertTransparentColor(gradientStops, 1, 1 - s_CGGradientOffsetPoint);
Copy link
Contributor

@aballway aballway Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.0 - #Resolved

@@ -49,6 +50,9 @@

static const wchar_t* TAG = L"CGContext";

// Coordinate offset to support CGGradientDrawingOptions
static const float s_CGGradientOffsetPoint = 1E-45;
Copy link
Contributor

@aballway aballway Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be sc_ #WontFix

Copy link
Contributor Author

@msft-Jeyaram msft-Jeyaram Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm s_k* is more appropriate #Resolved

@@ -36,7 +36,7 @@ - (void)dealloc {
@end
Copy link
Contributor

@aballway aballway Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: update copyright #Resolved

0.85, 0, 0, 1.0,
};

CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
Copy link
Contributor

@aballway aballway Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use unique_cf for tests
c'mon I've gotten several of this exact nit from you :P #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha I think these are simpler for now :)


In reply to: 93475189 [](ancestors = 93475189)

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();
Copy link
Contributor

@aballway aballway Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nearly identical above, make into helper function #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the helpers would end up being a plain convoluted wrappers around CGContextDrawLinearGradient


In reply to: 93475425 [](ancestors = 93475425)

};

CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, 0);
Copy link
Contributor

@aballway aballway Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use std::extent to keep track of array length rather than hardcoding for all of these #WontFix

static void _drawLinearGradient(CGContextRef context,
CGPoint startPoint,
CGPoint endPoint,
CGFloat* components,
Copy link
Contributor

@aballway aballway Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pass this in as an array rather than a pointer, and you can just use std::extent on it rather than passing in count #Resolved

@@ -51,7 +51,7 @@
static const wchar_t* TAG = L"CGContext";

// Coordinate offset to support CGGradientDrawingOptions
static const float s_CGGradientOffsetPoint = 1E-45;
static const float s_kCGGradientOffsetPoint = 1E-45;
Copy link
Contributor

@aballway aballway Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that works too XD #ByDesign

CGPointMake(borderRect.size.width, borderRect.size.height),
components,
locations,
_countof(locations),
Copy link
Contributor

@aballway aballway Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use extent instead of _countof which is MS only and shouldn't work on reference platform. #Resolved

Copy link
Contributor Author

@msft-Jeyaram msft-Jeyaram Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

darn i forgot about that #Resolved

CGPointMake(512, 1024),
kCGGradientDrawsBeforeStartLocation);
CFRelease(colorspace);
CFRelease(gradient);
Copy link
Contributor Author

@msft-Jeyaram msft-Jeyaram Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is going to stay likes this. given it's an odd case and i'd rather not generalize the function more for an odd case. #ByDesign

Copy link
Contributor

@aballway aballway left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add some tests to verify everything with odd locations rather than them all bumping against the edges of the image. Since you'll be changing this up in #1541 it'd be nice to make sure no edge cases regress.

kCGGradientDrawsBeforeStartLocation);
}

DISABLED_DRAW_TEST_F(CGGradient, LinearGradientShortBothSides_Options_0, UIKitMimicTest) {
Copy link
Contributor

@aballway aballway Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are begging to be parameterized #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are simple enough for now


In reply to: 93496267 [](ancestors = 93496267)

CFRelease(gradient);
}

DISABLED_DRAW_TEST_F(CGGradient, LinearGradient2, UIKitMimicTest) {
Copy link
Contributor

@aballway aballway Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should make these paremeterized too, combinations of locations/components, different points, changes in alpha, etc. #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uh it's going to be a huge wrapped convoluted function, going to lock it down on this.


In reply to: 93496632 [](ancestors = 93496632)

@msft-Jeyaram msft-Jeyaram merged commit 0c1e282 into microsoft:CGD2D Dec 21, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants