-
Notifications
You must be signed in to change notification settings - Fork 806
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
Implementation of Linear Gradient #1535
Conversation
@@ -36,7 +36,7 @@ - (void)dealloc { | |||
@end | |||
|
|||
__CGGradient::__CGGradient() : _components(NULL), _locations(NULL) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cb1baad
to
9a99f65
Compare
* Convert CGGradient to D2D1_GRADIENT_STOP | ||
*/ | ||
static inline std::vector<D2D1_GRADIENT_STOP> __CGGradientToD2D1GradientStop(CGGradientRef gradient, CGGradientDrawingOptions options) { | ||
unsigned long gradientCount = _CGGradientGetCount(gradient); |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
super magic number #WontFix
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | ||
|
||
unsigned long _CGGradientGetCount(CGGradientRef gradient) { | ||
if (!gradient) { |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
float* _CGGradientGetStopLocation(CGGradientRef gradient); | ||
|
||
float* _CGGradientGetColorComponents(CGGradientRef gradient); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is part of the scope of this pull request!
#ByDesign
|
Created a bug, it isn't blocking this PR for say. 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; |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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
There was a problem hiding this 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(®ion, linearGradientBrush.Get()); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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)
a879990
to
c1f17f5
Compare
There was a problem hiding this 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?
// This will be used to insert the transparent color. | ||
std::vector<D2D1_GRADIENT_STOP> gradientStops((options == kCGGradientDrawsAfterEndLocation) ? gradientCount + 1 : gradientCount); | ||
|
||
float* colorComponenets = _CGGradientGetColorComponents(gradient); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -48,6 +48,8 @@ | |||
|
|||
static const wchar_t* TAG = L"CGContext"; | |||
|
|||
static float s_CGGradientStartPoint = 1E-45; |
There was a problem hiding this comment.
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
56b7a3e
to
613b276
Compare
// 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) { |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CGFloat* colorComponents = _CGGradientGetColorComponents(gradient); | ||
CGFloat* locations = _CGGradientGetStopLocation(gradient); | ||
for (unsigned long i = 0; i < gradientCount; ++i) { | ||
unsigned int colorIndex = (i * 4); |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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
There was a problem hiding this 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); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be sc_ #WontFix
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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(); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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), |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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
There was a problem hiding this 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) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CFRelease(gradient); | ||
} | ||
|
||
DISABLED_DRAW_TEST_F(CGGradient, LinearGradient2, UIKitMimicTest) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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)
This change is