Implement support for patternUnits="objectBoundingBox"
 seems to work well on both platforms
Implement support for patternContentUnits="objectBoundingBox"
 Android has issues with small paths
This commit is contained in:
Mikael Sand
2019-01-25 04:23:33 +02:00
parent 76fb495920
commit 5551ff2bfa
5 changed files with 52 additions and 24 deletions
@@ -33,7 +33,7 @@ class Brush {
// TODO implement pattern units // TODO implement pattern units
@SuppressWarnings({"FieldCanBeLocal", "unused"}) @SuppressWarnings({"FieldCanBeLocal", "unused"})
private boolean mUseContentObjectBoundingBox; private boolean mUseContentObjectBoundingBoxUnits;
private Matrix mMatrix; private Matrix mMatrix;
private Rect mUserSpaceBoundingBox; private Rect mUserSpaceBoundingBox;
@@ -46,7 +46,7 @@ class Brush {
} }
void setContentUnits(BrushUnits units) { void setContentUnits(BrushUnits units) {
mUseContentObjectBoundingBox = units == BrushUnits.OBJECT_BOUNDING_BOX; mUseContentObjectBoundingBoxUnits = units == BrushUnits.OBJECT_BOUNDING_BOX;
} }
void setPattern(PatternView pattern) { void setPattern(PatternView pattern) {
@@ -104,6 +104,11 @@ class Brush {
return new RectF(x, y, x + width, y + height); return new RectF(x, y, x + width, y + height);
} }
private double getVal(SVGLength length, double relative, float scale, float textSize) {
return PropHelper.fromRelative(length, relative, 0, mUseObjectBoundingBox &&
length.unit == SVGLengthUnitType.SVG_LENGTHTYPE_NUMBER ? relative : scale, textSize);
}
void setupPaint(Paint paint, RectF pathBoundingBox, float scale, float opacity) { void setupPaint(Paint paint, RectF pathBoundingBox, float scale, float opacity) {
RectF rect = getPaintRect(pathBoundingBox); RectF rect = getPaintRect(pathBoundingBox);
float width = rect.width(); float width = rect.width();
@@ -113,10 +118,14 @@ class Brush {
float textSize = paint.getTextSize(); float textSize = paint.getTextSize();
if (mType == BrushType.PATTERN) { if (mType == BrushType.PATTERN) {
double x = PropHelper.fromRelative(mPoints[0], width, offsetX, scale, textSize); double x = getVal(mPoints[0], width, scale, textSize);
double y = PropHelper.fromRelative(mPoints[1], height, offsetY, scale, textSize); double y = getVal(mPoints[1], height, scale, textSize);
double w = PropHelper.fromRelative(mPoints[2], width, offsetX, scale, textSize); double w = getVal(mPoints[2], width, scale, textSize);
double h = PropHelper.fromRelative(mPoints[3], height, offsetY, scale, textSize); double h = getVal(mPoints[3], height, scale, textSize);
if (!(w > 1 && h > 1)) {
return;
}
Bitmap bitmap = Bitmap.createBitmap( Bitmap bitmap = Bitmap.createBitmap(
(int) w, (int) w,
@@ -131,6 +140,10 @@ class Brush {
canvas.concat(mViewBoxMatrix); canvas.concat(mViewBoxMatrix);
} }
if (mUseContentObjectBoundingBoxUnits) {
canvas.scale(width / scale, height / scale);
}
mPattern.draw(canvas, new Paint(), opacity); mPattern.draw(canvas, new Paint(), opacity);
Matrix patternMatrix = new Matrix(); Matrix patternMatrix = new Matrix();
+7
View File
@@ -8,6 +8,13 @@ import Shape from "./Shape";
export default class Pattern extends Shape { export default class Pattern extends Shape {
static displayName = "Pattern"; static displayName = "Pattern";
static defaultProps = {
x: "0%",
y: "0%",
width: "100%",
height: "100%",
};
render() { render() {
const { props } = this; const { props } = this;
const { const {
+2
View File
@@ -17,6 +17,8 @@
@property (nonatomic, assign) RNSVGPattern* pattern; @property (nonatomic, assign) RNSVGPattern* pattern;
@property (nonatomic, assign) CGRect paintBounds; @property (nonatomic, assign) CGRect paintBounds;
@property (nonatomic, assign) bool useObjectBoundingBoxForContentUnits;
@property (nonatomic, assign) CGRect bounds;
- (instancetype)initWithPointsArray:(NSArray<RNSVGLength *> *)pointsArray NS_DESIGNATED_INITIALIZER; - (instancetype)initWithPointsArray:(NSArray<RNSVGLength *> *)pointsArray NS_DESIGNATED_INITIALIZER;
+22 -16
View File
@@ -131,34 +131,40 @@ void PatternFunction(void* info, CGContextRef context)
CGContextConcatCTM(context, _viewBoxTransform); CGContextConcatCTM(context, _viewBoxTransform);
} }
if (_painter.useObjectBoundingBoxForContentUnits) {
CGRect bounds = _painter.bounds;
CGContextConcatCTM(context, CGAffineTransformMakeScale(bounds.size.width, bounds.size.height));
}
[_pattern renderTo:context rect:rect]; [_pattern renderTo:context rect:rect];
} }
- (CGFloat)getVal:(RNSVGLength*)length relative:(CGFloat)relative
{
RNSVGLengthUnitType unit = [length unit];
CGFloat val = [RNSVGPropHelper fromRelative:length
relative:relative];
return _useObjectBoundingBox &&
unit == SVG_LENGTHTYPE_NUMBER ? val * relative : val;
}
- (void)paintPattern:(CGContextRef)context bounds:(CGRect)bounds - (void)paintPattern:(CGContextRef)context bounds:(CGRect)bounds
{ {
CGRect rect = [self getPaintRect:context bounds:bounds]; CGRect rect = [self getPaintRect:context bounds:bounds];
CGFloat height = CGRectGetHeight(rect); CGFloat height = CGRectGetHeight(rect);
CGFloat width = CGRectGetWidth(rect); CGFloat width = CGRectGetWidth(rect);
CGFloat offsetX = CGRectGetMinX(rect);
CGFloat offsetY = CGRectGetMinY(rect);
CGFloat x = [RNSVGPercentageConverter lengthToFloat:[_points objectAtIndex:0] CGFloat x = [self getVal:[_points objectAtIndex:0] relative:width];
relative:width CGFloat y = [self getVal:[_points objectAtIndex:1] relative:height];
offset:offsetX]; CGFloat w = [self getVal:[_points objectAtIndex:2] relative:width];
CGFloat y = [RNSVGPercentageConverter lengthToFloat:[_points objectAtIndex:1] CGFloat h = [self getVal:[_points objectAtIndex:3] relative:height];
relative:height
offset:offsetY];
CGFloat w = [RNSVGPercentageConverter lengthToFloat:[_points objectAtIndex:2]
relative:width
offset:offsetX];
CGFloat h = [RNSVGPercentageConverter lengthToFloat:[_points objectAtIndex:3]
relative:height
offset:offsetY];
CGAffineTransform viewbox = [self.pattern.svgView getViewBoxTransform]; CGAffineTransform viewbox = [self.pattern.svgView getViewBoxTransform];
CGRect newBounds = CGRectApplyAffineTransform(CGRectMake(x, y, w, h), viewbox); CGRect newBounds = CGRectMake(x, y, w, h);
CGSize size = newBounds.size; CGSize size = newBounds.size;
self.useObjectBoundingBoxForContentUnits = _useContentObjectBoundingBox;
self.paintBounds = newBounds; self.paintBounds = newBounds;
self.bounds = rect;
const CGPatternCallbacks callbacks = { 0, &PatternFunction, NULL }; const CGPatternCallbacks callbacks = { 0, &PatternFunction, NULL };
CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL); CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
@@ -167,7 +173,7 @@ void PatternFunction(void* info, CGContextRef context)
CGPatternRef pattern = CGPatternCreate((__bridge void * _Nullable)(self), CGPatternRef pattern = CGPatternCreate((__bridge void * _Nullable)(self),
newBounds, newBounds,
CGAffineTransformIdentity, viewbox,
size.width, size.width,
size.height, size.height,
kCGPatternTilingConstantSpacing, kCGPatternTilingConstantSpacing,
+2 -2
View File
@@ -133,7 +133,7 @@
} }
CGMutablePathRef __block path = CGPathCreateMutable(); CGMutablePathRef __block path = CGPathCreateMutable();
[self traverseSubviews:^(RNSVGNode *node) { [self traverseSubviews:^(RNSVGNode *node) {
if ([node isKindOfClass:[RNSVGNode class]]) { if ([node isKindOfClass:[RNSVGNode class]] && ![node isKindOfClass:[RNSVGMask class]]) {
CGAffineTransform transform = CGAffineTransformConcat(node.matrix, node.transforms); CGAffineTransform transform = CGAffineTransformConcat(node.matrix, node.transforms);
CGPathAddPath(path, &transform, [node getPath:context]); CGPathAddPath(path, &transform, [node getPath:context]);
} }
@@ -174,7 +174,7 @@
} }
for (RNSVGNode *node in [self.subviews reverseObjectEnumerator]) { for (RNSVGNode *node in [self.subviews reverseObjectEnumerator]) {
if (![node isKindOfClass:[RNSVGNode class]]) { if (![node isKindOfClass:[RNSVGNode class]] || [node isKindOfClass:[RNSVGMask class]]) {
continue; continue;
} }