Refactor extractGradient, simplify RNSVGCGGradient conversion, prettier

This commit is contained in:
Mikael Sand
2019-01-05 22:28:16 +02:00
parent 07292c1ab0
commit e8d23439a4
12 changed files with 66 additions and 99 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ class Shape extends Component {
super(...arguments);
for (let key of Object.keys(SvgTouchableMixin)) {
const method = SvgTouchableMixin[key];
if (typeof method === 'function') {
if (typeof method === "function") {
this[key] = method.bind(this);
} else {
this[key] = method;
+5 -2
View File
@@ -89,7 +89,10 @@ class Svg extends Shape {
onLayout,
...props
} = this.props;
const stylesAndProps = { ...(style && style.length ? Object.assign({}, ...style) : style), ...props };
const stylesAndProps = {
...(style && style.length ? Object.assign({}, ...style) : style),
...props,
};
const { color, width, height } = stylesAndProps;
let dimensions;
@@ -125,7 +128,7 @@ class Svg extends Shape {
dimensions,
]}
>
<G style={style} {...(pick(stylesAndProps, gProps))}>
<G style={style} {...pick(stylesAndProps, gProps)}>
{children}
</G>
</NativeSvgView>
+2 -2
View File
@@ -176,7 +176,7 @@ void PatternFunction(void* info, CGContextRef context)
- (void)paintLinearGradient:(CGContextRef)context bounds:(CGRect)bounds
{
CGGradientRef gradient = CGGradientRetain([RCTConvert RNSVGCGGradient:_colors offset:0]);
CGGradientRef gradient = CGGradientRetain([RCTConvert RNSVGCGGradient:_colors]);
CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
CGRect rect = [self getPaintRect:context bounds:bounds];
@@ -206,7 +206,7 @@ void PatternFunction(void* info, CGContextRef context)
- (void)paintRadialGradient:(CGContextRef)context bounds:(CGRect)bounds
{
CGGradientRef gradient = CGGradientRetain([RCTConvert RNSVGCGGradient:_colors offset:0]);
CGGradientRef gradient = CGGradientRetain([RCTConvert RNSVGCGGradient:_colors]);
CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
CGRect rect = [self getPaintRect:context bounds:bounds];
+1 -1
View File
@@ -29,6 +29,6 @@
+ (RNSVGPathParser *)RNSVGCGPath:(NSString *)d;
+ (CGRect)RNSVGCGRect:(id)json offset:(NSUInteger)offset;
+ (CGColorRef)RNSVGCGColor:(id)json offset:(NSUInteger)offset;
+ (CGGradientRef)RNSVGCGGradient:(id)json offset:(NSUInteger)offset;
+ (CGGradientRef)RNSVGCGGradient:(id)json;
@end
+11 -29
View File
@@ -33,25 +33,6 @@ RCT_ENUM_CONVERTER(RNSVGUnits, (@{
@"userSpaceOnUse": @(kRNSVGUnitsUserSpaceOnUse),
}), kRNSVGUnitsObjectBoundingBox, intValue)
+ (CGFloat*)RNSVGCGFloatArray:(id)json
{
NSArray *arr = [self NSNumberArray:json];
NSUInteger count = arr.count;
CGFloat* array = nil;
if (count) {
// Ideally, these arrays should already use the same memory layout.
// In that case we shouldn't need this new malloc.
array = malloc(sizeof(CGFloat) * count);
for (NSUInteger i = 0; i < count; i++) {
array[i] = (CGFloat)[arr[i] doubleValue];
}
}
return array;
}
+ (RNSVGBrush *)RNSVGBrush:(id)json
{
if ([json isKindOfClass:[NSString class]]) {
@@ -151,28 +132,29 @@ RCT_ENUM_CONVERTER(RNSVGUnits, (@{
return [self CGColor:[arr subarrayWithRange:(NSRange){offset, 4}]];
}
+ (CGGradientRef)RNSVGCGGradient:(id)json offset:(NSUInteger)offset
+ (CGGradientRef)RNSVGCGGradient:(id)json
{
NSArray *arr = [self NSArray:json];
if (arr.count < offset) {
NSArray *arr = [self NSNumberArray:json];
NSUInteger count = arr.count;
if (count < 5) {
RCTLogError(@"Too few elements in array (expected at least %zd): %@", (unsigned long)offset, arr);
return nil;
}
arr = [arr subarrayWithRange:(NSRange){offset, arr.count - offset}];
CGFloat* colorsAndOffsets = [self RNSVGCGFloatArray:arr];
size_t stops = arr.count / 5;
CGFloat colorsAndOffsets[count];
for (NSUInteger i = 0; i < count; i++) {
colorsAndOffsets[i] = (CGFloat)[arr[i] doubleValue];
}
size_t stops = count / 5;
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(
rgb,
colorsAndOffsets,
colorsAndOffsets + stops * 4,
stops
);
CGColorSpaceRelease(rgb);
free(colorsAndOffsets);
return (CGGradientRef)CFAutorelease(gradient);
}
+5 -5
View File
@@ -11,7 +11,7 @@ export default {
} else {
return Touchable.Mixin.touchableHandleStartShouldSetResponder.call(
this,
e
e,
);
}
},
@@ -22,7 +22,7 @@ export default {
} else {
return Touchable.Mixin.touchableHandleResponderTerminationRequest.call(
this,
e
e,
);
}
},
@@ -49,7 +49,7 @@ export default {
} else {
return Touchable.Mixin.touchableHandleResponderRelease.call(
this,
e
e,
);
}
},
@@ -60,7 +60,7 @@ export default {
} else {
return Touchable.Mixin.touchableHandleResponderTerminate.call(
this,
e
e,
);
}
},
@@ -101,5 +101,5 @@ export default {
touchableGetPressOutDelayMS: function() {
return this.props.delayPressOut || 0;
}
},
};
+23 -48
View File
@@ -22,66 +22,41 @@ function percentToFloat(percent) {
return matched[2] ? matched[1] / 100 : +matched[1];
}
function compareAscending(value, other) {
if (value !== other) {
if (value > other) {
return 1;
}
if (value < other) {
return -1;
}
}
return 0;
}
const offsetComparator = (object, other) => compareAscending(object.offset, other.offset);
const offsetComparator = (object, other) => object[0] - other[0];
export default function(props) {
if (!props.id) {
const { id, children, gradientTransform, transform, gradientUnits } = props;
if (!id) {
return null;
}
const stops = [];
Children.forEach(
props.children,
({ props: { offset, stopColor, stopOpacity } }) => {
offset = percentToFloat(offset);
if (stopColor && !isNaN(offset)) {
//noinspection JSUnresolvedFunction
stops.push({
stop: Color(stopColor).alpha(extractOpacity(stopOpacity)),
offset,
});
}
},
);
for (let child of Children.toArray(children)) {
const { props: { offset, stopColor, stopOpacity } } = child;
const offsetNumber = percentToFloat(offset);
if (stopColor && !isNaN(offsetNumber)) {
//noinspection JSUnresolvedFunction
const color = Color(stopColor).alpha(extractOpacity(stopOpacity));
const [r, g, b, a = 1] = color.rgb().array();
stops.push([offsetNumber, [r / 255, g / 255, b / 255, a]]);
}
}
stops.sort(offsetComparator);
const gradient = [];
stops.forEach(({ stop }) => {
const [r, g, b, a = 1] = stop.rgb().array();
gradient.push(r / 255);
gradient.push(g / 255);
gradient.push(b / 255);
gradient.push(a);
});
gradient.push(...stops.map(({ offset }) => offset));
let gradientTransform;
if (props.gradientTransform) {
gradientTransform = extractTransform(props.gradientTransform);
} else if (props.transform) {
gradientTransform = extractTransform(props.transform);
} else {
gradientTransform = extractTransform(props);
for (let stop of stops) {
gradient.push(...stop[1]);
}
for (let stop of stops) {
gradient.push(stop[0]);
}
const gt = extractTransform(gradientTransform || transform || props);
return {
gradient,
name: props.id,
gradientTransform,
gradientUnits: units[props.gradientUnits] || 0,
name: id,
gradientTransform: gt,
gradientUnits: units[gradientUnits] || 0,
};
}
+1 -1
View File
@@ -2,7 +2,7 @@ import { PanResponder } from "react-native";
const responderProps = [
...Object.keys(PanResponder.create({}).panHandlers),
"pointerEvents"
"pointerEvents",
];
const touchableProps = [
+6 -2
View File
@@ -86,8 +86,12 @@ export function props2transform(props) {
const [skewX, skewY] = universal2axis(props.skew, props.skewX, props.skewY);
const [translateX, translateY] = universal2axis(
props.translate,
props.translateX === undefined || props.translateX === null ? props.x || 0 : props.translateX,
props.translateY === undefined || props.translateY === null ? props.y || 0 : props.translateY,
props.translateX === undefined || props.translateX === null
? props.x || 0
: props.translateX,
props.translateY === undefined || props.translateY === null
? props.y || 0
: props.translateY,
);
return {
+10 -6
View File
@@ -29,9 +29,12 @@ export default function(props) {
return null;
}
const params = viewBox.trim().split(spacesRegExp);
const params = viewBox
.trim()
.split(spacesRegExp)
.map(Number);
if (params.length === 4 && params.some(param => isNaN(+param))) {
if (params.length === 4 && params.some(isNaN)) {
console.warn("Invalid `viewBox` prop:" + viewBox);
return null;
}
@@ -42,12 +45,13 @@ export default function(props) {
const meetOrSlice = meetOrSliceTypes[modes[1]] || 0;
const align = alignEnum[modes[0]] || "xMidYMid";
const [minX, minY, vbWidth, vbHeight] = params;
return {
minX: +params[0],
minY: +params[1],
vbWidth: +params[2],
vbHeight: +params[3],
minX,
minY,
vbWidth,
vbHeight,
align,
meetOrSlice,
};
+1 -1
View File
@@ -1,4 +1,4 @@
export default {
objectBoundingBox: 0,
userSpaceOnUse: 1
userSpaceOnUse: 1,
};
-1
View File
@@ -1,4 +1,3 @@
// eslint-disable-next-line eqeqeq
export const notNil = a => a != null;