diff --git a/android/src/main/java/com/horcrux/svg/Brush.java b/android/src/main/java/com/horcrux/svg/Brush.java index 1d0a2453..6ca03129 100644 --- a/android/src/main/java/com/horcrux/svg/Brush.java +++ b/android/src/main/java/com/horcrux/svg/Brush.java @@ -9,6 +9,9 @@ package com.horcrux.svg; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Matrix; @@ -23,12 +26,14 @@ import com.facebook.react.bridge.ReadableArray; import com.facebook.react.common.ReactConstants; class Brush { - private BrushType mType = BrushType.LINEAR_GRADIENT; + private BrushType mType; private final ReadableArray mPoints; private ReadableArray mColors; private final boolean mUseObjectBoundingBox; + private boolean mUseContentObjectBoundingBox; private Matrix mMatrix; private Rect mUserSpaceBoundingBox; + PatternShadowNode mPattern; Brush(BrushType type, ReadableArray points, BrushUnits units) { mType = type; @@ -36,6 +41,14 @@ class Brush { mUseObjectBoundingBox = units == BrushUnits.OBJECT_BOUNDING_BOX; } + void setContentUnits(BrushUnits units) { + mUseContentObjectBoundingBox = units == BrushUnits.OBJECT_BOUNDING_BOX; + } + + void setPattern(PatternShadowNode pattern) { + mPattern = pattern; + } + enum BrushType { LINEAR_GRADIENT(0), RADIAL_GRADIENT(1), @@ -105,6 +118,35 @@ class Brush { float offsetX = rect.left; float offsetY = rect.top; + if (mType == BrushType.PATTERN) { + double x = PropHelper.fromRelative(mPoints.getString(0), width, offsetX, scale, paint.getTextSize()); + double y = PropHelper.fromRelative(mPoints.getString(1), height, offsetY, scale, paint.getTextSize()); + double w = PropHelper.fromRelative(mPoints.getString(2), width, offsetX, scale, paint.getTextSize()); + double h = PropHelper.fromRelative(mPoints.getString(3), height, offsetY, scale, paint.getTextSize()); + + RectF vbRect = mPattern.getViewBox(); + RectF eRect = new RectF((float)x, (float)y, (float)w, (float)h); + Matrix mViewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mPattern.mAlign, mPattern.mMeetOrSlice); + + Bitmap bitmap = Bitmap.createBitmap( + (int) w, + (int) h, + Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.concat(mViewBoxMatrix); + mPattern.draw(canvas, new Paint(), opacity); + + Matrix patternMatrix = new Matrix(); + if (mMatrix != null) { + patternMatrix.preConcat(mMatrix); + } + + BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); + bitmapShader.setLocalMatrix(patternMatrix); + paint.setShader(bitmapShader); + return; + } + int stopsCount = mColors.size() / 5; int[] stopsColors = new int[stopsCount]; float[] stops = new float[stopsCount]; @@ -170,12 +212,5 @@ class Brush { radialGradient.setLocalMatrix(radialMatrix); paint.setShader(radialGradient); } - // else { - // todo: pattern support - - //Shader mShader1 = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); - //paint.setShader(mShader1); - //bitmap.recycle(); - // } } } diff --git a/android/src/main/java/com/horcrux/svg/PatternShadowNode.java b/android/src/main/java/com/horcrux/svg/PatternShadowNode.java new file mode 100644 index 00000000..92eda0ae --- /dev/null +++ b/android/src/main/java/com/horcrux/svg/PatternShadowNode.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + + +package com.horcrux.svg; + +import android.graphics.Matrix; +import android.graphics.RectF; + +import com.facebook.common.logging.FLog; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.common.ReactConstants; +import com.facebook.react.uimanager.annotations.ReactProp; + +import javax.annotation.Nullable; + +/** + * Shadow node for virtual Pattern definition view + */ +class PatternShadowNode extends GroupShadowNode { + + private String mX; + private String mY; + private String mWidth; + private String mHeight; + private Brush.BrushUnits mPatternUnits; + private Brush.BrushUnits mPatternContentUnits; + + private float mMinX; + private float mMinY; + private float mVbWidth; + private float mVbHeight; + String mAlign; + int mMeetOrSlice; + + private static final float[] sRawMatrix = new float[]{ + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + }; + private Matrix mMatrix = null; + + @ReactProp(name = "x") + public void setX(String x) { + mX = x; + markUpdated(); + } + + @ReactProp(name = "y") + public void setY(String y) { + mY = y; + markUpdated(); + } + + @ReactProp(name = "patternwidth") + public void setWidth(String width) { + mWidth = width; + markUpdated(); + } + + @ReactProp(name = "patternheight") + public void setHeight(String height) { + mHeight = height; + markUpdated(); + } + + @ReactProp(name = "patternUnits") + public void setPatternUnits(int patternUnits) { + switch (patternUnits) { + case 0: + mPatternUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; + break; + case 1: + mPatternUnits = Brush.BrushUnits.USER_SPACE_ON_USE; + break; + } + markUpdated(); + } + + @ReactProp(name = "patternContentUnits") + public void setPatternContentUnits(int patternContentUnits) { + switch (patternContentUnits) { + case 0: + mPatternContentUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; + break; + case 1: + mPatternContentUnits = Brush.BrushUnits.USER_SPACE_ON_USE; + break; + } + markUpdated(); + } + + @ReactProp(name = "patternTransform") + public void setPatternTransform(@Nullable ReadableArray matrixArray) { + if (matrixArray != null) { + int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale); + if (matrixSize == 6) { + if (mMatrix == null) { + mMatrix = new Matrix(); + } + mMatrix.setValues(sRawMatrix); + } else if (matrixSize != -1) { + FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6"); + } + } else { + mMatrix = null; + } + + markUpdated(); + } + + @ReactProp(name = "minX") + public void setMinX(float minX) { + mMinX = minX; + markUpdated(); + } + + @ReactProp(name = "minY") + public void setMinY(float minY) { + mMinY = minY; + markUpdated(); + } + + @ReactProp(name = "vbWidth") + public void setVbWidth(float vbWidth) { + mVbWidth = vbWidth; + markUpdated(); + } + + @ReactProp(name = "vbHeight") + public void setVbHeight(float vbHeight) { + mVbHeight = vbHeight; + markUpdated(); + } + + @ReactProp(name = "align") + public void setAlign(String align) { + mAlign = align; + markUpdated(); + } + + @ReactProp(name = "meetOrSlice") + public void setMeetOrSlice(int meetOrSlice) { + mMeetOrSlice = meetOrSlice; + markUpdated(); + } + + + RectF getViewBox() { + return new RectF(mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale); + } + + @Override + protected void saveDefinition() { + if (mName != null) { + WritableArray points = Arguments.createArray(); + points.pushString(mX); + points.pushString(mY); + points.pushString(mWidth); + points.pushString(mHeight); + + Brush brush = new Brush(Brush.BrushType.PATTERN, points, mPatternUnits); + brush.setContentUnits(mPatternContentUnits); + brush.setPattern(this); + + if (mMatrix != null) { + brush.setGradientTransform(mMatrix); + } + + SvgViewShadowNode svg = getSvgShadowNode(); + if (mPatternUnits == Brush.BrushUnits.USER_SPACE_ON_USE || mPatternContentUnits == Brush.BrushUnits.USER_SPACE_ON_USE) { + brush.setUserSpaceBoundingBox(svg.getCanvasBounds()); + } + + svg.defineBrush(brush, mName); + } + } +} diff --git a/android/src/main/java/com/horcrux/svg/RenderableViewManager.java b/android/src/main/java/com/horcrux/svg/RenderableViewManager.java index 804912f3..1069457e 100644 --- a/android/src/main/java/com/horcrux/svg/RenderableViewManager.java +++ b/android/src/main/java/com/horcrux/svg/RenderableViewManager.java @@ -49,6 +49,7 @@ class RenderableViewManager extends ViewGroupManager extends ViewGroupManager createPatternManager() { + return new RenderableViewManager(CLASS_PATTERN) { + + @ReactProp(name = "x") + public void setX(RenderableView node, String x) { + node.shadowNode.setX(x); + } + + @ReactProp(name = "y") + public void setY(RenderableView node, String y) { + node.shadowNode.setY(y); + } + + @ReactProp(name = "patternwidth") + public void setWidth(RenderableView node, String width) { + node.shadowNode.setWidth(width); + } + + @ReactProp(name = "patternheight") + public void setHeight(RenderableView node, String height) { + node.shadowNode.setHeight(height); + } + + @ReactProp(name = "patternUnits") + public void setPatternUnits(RenderableView node, int patternUnits) { + node.shadowNode.setPatternUnits(patternUnits); + } + + @ReactProp(name = "patternContentUnits") + public void setPatternContentUnits(RenderableView node, int patternContentUnits) { + node.shadowNode.setPatternContentUnits(patternContentUnits); + } + + @ReactProp(name = "patternTransform") + public void setPatternTransform(RenderableView node, @Nullable ReadableArray matrixArray) { + node.shadowNode.setPatternTransform(matrixArray); + } + + @ReactProp(name = "minX") + public void setMinX(RenderableView node, float minX) { + node.shadowNode.setMinX(minX); + } + + @ReactProp(name = "minY") + public void setMinY(RenderableView node, float minY) { + node.shadowNode.setMinY(minY); + } + + @ReactProp(name = "vbWidth") + public void setVbWidth(RenderableView node, float vbWidth) { + node.shadowNode.setVbWidth(vbWidth); + } + + @ReactProp(name = "vbHeight") + public void setVbHeight(RenderableView node, float vbHeight) { + node.shadowNode.setVbHeight(vbHeight); + } + + @ReactProp(name = "align") + public void setAlign(RenderableView node, String align) { + node.shadowNode.setAlign(align); + } + + @ReactProp(name = "meetOrSlice") + public void setMeetOrSlice(RenderableView node, int meetOrSlice) { + node.shadowNode.setMeetOrSlice(meetOrSlice); + } + }; + } + static RenderableViewManager createLinearGradientManager() { return new RenderableViewManager(CLASS_LINEAR_GRADIENT) { @@ -523,6 +594,8 @@ class RenderableViewManager extends ViewGroupManager extends ViewGroupManager + {children} + + ); } } + +const RNSVGPattern = requireNativeComponent('RNSVGPattern', null, { + nativeOnly: PatternAttributes, +}); diff --git a/index.js b/index.js index ba0e6837..f1848316 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,7 @@ import LinearGradient from "./elements/LinearGradient"; import RadialGradient from "./elements/RadialGradient"; import Stop from "./elements/Stop"; import ClipPath from "./elements/ClipPath"; +import Pattern from "./elements/Pattern"; export { Svg, @@ -39,7 +40,8 @@ export { LinearGradient, RadialGradient, Stop, - ClipPath + ClipPath, + Pattern }; //noinspection JSUnusedGlobalSymbols diff --git a/ios/Brushes/RNSVGPainter.h b/ios/Brushes/RNSVGPainter.h index 0f52a4b8..00c680ef 100644 --- a/ios/Brushes/RNSVGPainter.h +++ b/ios/Brushes/RNSVGPainter.h @@ -10,14 +10,21 @@ #import "RNSVGBrushType.h" #import "RNSVGUnits.h" +@class RNSVGPattern; + @interface RNSVGPainter : NSObject +@property (nonatomic, assign) RNSVGPattern* pattern; +@property (nonatomic, assign) CGRect paintBounds; + - (instancetype)initWithPointsArray:(NSArray *)pointsArray NS_DESIGNATED_INITIALIZER; - (void)paint:(CGContextRef)context bounds:(CGRect)bounds; - (void)setUnits:(RNSVGUnits)unit; +- (void)setContentUnits:(RNSVGUnits)unit; + - (void)setUserSpaceBoundingBox:(CGRect)userSpaceBoundingBox; - (void)setTransform:(CGAffineTransform)transform; diff --git a/ios/Brushes/RNSVGPainter.m b/ios/Brushes/RNSVGPainter.m index 1ac93f26..b8973e9e 100644 --- a/ios/Brushes/RNSVGPainter.m +++ b/ios/Brushes/RNSVGPainter.m @@ -7,7 +7,9 @@ */ #import "RNSVGPainter.h" +#import "RNSVGPattern.h" #import "RNSVGPercentageConverter.h" +#import "RNSVGViewBox.h" @implementation RNSVGPainter { @@ -15,6 +17,7 @@ NSArray *_colors; RNSVGBrushType _type; BOOL _useObjectBoundingBox; + BOOL _useContentObjectBoundingBox; CGAffineTransform _transform; CGRect _userSpaceBoundingBox; } @@ -34,6 +37,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) _useObjectBoundingBox = unit == kRNSVGUnitsObjectBoundingBox; } +- (void)setContentUnits:(RNSVGUnits)unit +{ + _useContentObjectBoundingBox = unit == kRNSVGUnitsObjectBoundingBox; +} + - (void)setUserSpaceBoundingBox:(CGRect)userSpaceBoundingBox { _userSpaceBoundingBox = userSpaceBoundingBox; @@ -44,6 +52,17 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) _transform = transform; } +- (void)setPattern:(RNSVGPattern *)pattern +{ + if (_type != kRNSVGUndefinedType) { + // todo: throw error + return; + } + + _type = kRNSVGPattern; + _pattern = pattern; +} + - (void)setLinearGradientColors:(NSArray *)colors { if (_type != kRNSVGUndefinedType) { @@ -73,7 +92,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) } else if (_type == kRNSVGRadialGradient) { [self paintRidialGradient:context bounds:(CGRect)bounds]; } else if (_type == kRNSVGPattern) { - // todo: + [self paintPattern:context bounds:(CGRect)bounds]; } } @@ -93,6 +112,67 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) return CGRectMake(x, y, width, height); } +void PatternFunction(void* info, CGContextRef context) +{ + RNSVGPainter *_painter = (__bridge RNSVGPainter *)info; + RNSVGPattern *_pattern = [_painter pattern]; + CGRect rect = _painter.paintBounds; + + CGAffineTransform _viewBoxTransform = [RNSVGViewBox getTransform:CGRectMake(_pattern.minX, _pattern.minY, _pattern.vbWidth, _pattern.vbHeight) + eRect:rect + align:_pattern.align + meetOrSlice:_pattern.meetOrSlice]; + CGContextConcatCTM(context, _viewBoxTransform); + + [_pattern renderTo:context rect:rect]; +} + +- (void)paintPattern:(CGContextRef)context bounds:(CGRect)bounds +{ + CGRect rect = [self getPaintRect:context bounds:bounds]; + float height = CGRectGetHeight(rect); + float width = CGRectGetWidth(rect); + float offsetX = CGRectGetMinX(rect); + float offsetY = CGRectGetMinY(rect); + + CGFloat x = [RNSVGPercentageConverter stringToFloat:(NSString *)[_points objectAtIndex:0] + relative:width + offset:offsetX]; + CGFloat y = [RNSVGPercentageConverter stringToFloat:(NSString *)[_points objectAtIndex:1] + relative:height + offset:offsetY]; + CGFloat w = [RNSVGPercentageConverter stringToFloat:(NSString *)[_points objectAtIndex:2] + relative:width + offset:offsetX]; + CGFloat h = [RNSVGPercentageConverter stringToFloat:(NSString *)[_points objectAtIndex:3] + relative:height + offset:offsetY]; + + CGAffineTransform viewbox = [self.pattern.svgView getViewBoxTransform]; + CGRect newBounds = CGRectApplyAffineTransform(CGRectMake(x, y, w, h), viewbox); + CGSize size = newBounds.size; + self.paintBounds = newBounds; + + const CGPatternCallbacks callbacks = { 0, &PatternFunction, NULL }; + CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL); + CGContextSetFillColorSpace(context, patternSpace); + CGColorSpaceRelease(patternSpace); + + CGPatternRef pattern = CGPatternCreate((__bridge void * _Nullable)(self), + newBounds, + CGAffineTransformIdentity, + size.width, + size.height, + kCGPatternTilingConstantSpacing, + true, + &callbacks); + CGFloat alpha = 1.0; + CGContextSetFillPattern(context, pattern, &alpha); + CGPatternRelease(pattern); + + CGContextFillRect(context, bounds); +} + - (void)paintLinearGradient:(CGContextRef)context bounds:(CGRect)bounds { diff --git a/ios/Brushes/RNSVGPattern.m b/ios/Brushes/RNSVGPattern.m deleted file mode 100644 index 02983742..00000000 --- a/ios/Brushes/RNSVGPattern.m +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2015-present, Horcrux. - * All rights reserved. - * - * This source code is licensed under the MIT-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#import "RNSVGPattern.h" - -#import "RCTConvert+RNSVG.h" -#import - -@implementation RNSVGPattern -{ - CGImageRef _image; - CGRect _rect; -} - -- (instancetype)initWithArray:(NSArray *)array -{ - if ((self = [super initWithArray:array])) { - if (array.count < 6) { - RCTLogError(@"-[%@ %@] expects 6 elements, received %@", - self.class, NSStringFromSelector(_cmd), array); - return nil; - } - _image = CGImageRetain([RCTConvert CGImage:array[1]]); - _rect = [RCTConvert RNSVGCGRect:array offset:2]; - } - return self; -} - -- (void)dealloc -{ - CGImageRelease(_image); -} - -// Note: This could use applyFillColor with a pattern. This could be more efficient but -// to do that, we need to calculate our own user space CTM. - -- (void)paint:(CGContextRef)context opacity:(CGFloat)opacity brushConverter:(RNSVGPainter *)brushConverter; -{ - CGContextDrawTiledImage(context, _rect, _image); -} - - - -@end diff --git a/ios/Elements/RNSVGPattern.m b/ios/Elements/RNSVGPattern.m new file mode 100644 index 00000000..1010abd1 --- /dev/null +++ b/ios/Elements/RNSVGPattern.m @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ +#import "RNSVGPattern.h" +#import "RNSVGPainter.h" +#import "RNSVGBrushType.h" +#import "RNSVGNode.h" + +@implementation RNSVGPattern + +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event +{ + return nil; +} + +- (void)parseReference +{ + NSArray *points = @[self.x, self.y, self.patternwidth, self.patternheight]; + RNSVGPainter *painter = [[RNSVGPainter alloc] initWithPointsArray:points]; + [painter setUnits:self.patternUnits]; + [painter setContentUnits:self.patternContentUnits]; + [painter setTransform:self.patternTransform]; + [painter setPattern:self]; + + if (self.patternUnits == kRNSVGUnitsUserSpaceOnUse || self.patternContentUnits == kRNSVGUnitsUserSpaceOnUse) { + [painter setUserSpaceBoundingBox:[self.svgView getContextBounds]]; + } + + [self.svgView definePainter:painter painterName:self.name]; +} + +@end + diff --git a/ios/Elements/RNSVGSvgView.h b/ios/Elements/RNSVGSvgView.h index 031f2cb5..3a76e0c2 100644 --- a/ios/Elements/RNSVGSvgView.h +++ b/ios/Elements/RNSVGSvgView.h @@ -54,4 +54,6 @@ - (void)drawToContext:(CGContextRef)context withRect:(CGRect)rect; +- (CGAffineTransform)getViewBoxTransform; + @end diff --git a/ios/Elements/RNSVGSvgView.m b/ios/Elements/RNSVGSvgView.m index 833c8441..a1db83c8 100644 --- a/ios/Elements/RNSVGSvgView.m +++ b/ios/Elements/RNSVGSvgView.m @@ -268,4 +268,9 @@ return CGContextGetClipBoundingBox(UIGraphicsGetCurrentContext()); } +- (CGAffineTransform)getViewBoxTransform +{ + return _viewBoxTransform; +} + @end diff --git a/ios/RNSVG.xcodeproj/project.pbxproj b/ios/RNSVG.xcodeproj/project.pbxproj index 182aa547..e8b9d9bb 100644 --- a/ios/RNSVG.xcodeproj/project.pbxproj +++ b/ios/RNSVG.xcodeproj/project.pbxproj @@ -58,6 +58,10 @@ 7FC260CE1E3499BC00A39833 /* RNSVGViewBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FC260CD1E3499BC00A39833 /* RNSVGViewBox.m */; }; 7FC260D11E34A12000A39833 /* RNSVGSymbol.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FC260D01E34A12000A39833 /* RNSVGSymbol.m */; }; 7FC260D41E34A12A00A39833 /* RNSVGSymbolManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FC260D31E34A12A00A39833 /* RNSVGSymbolManager.m */; }; + 94241666213B0D4500088E93 /* RNSVGPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 94241665213B0D4500088E93 /* RNSVGPattern.m */; }; + 94241667213B0D4500088E93 /* RNSVGPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 94241665213B0D4500088E93 /* RNSVGPattern.m */; }; + 9424166D213B302600088E93 /* RNSVGPatternManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9424166C213B302600088E93 /* RNSVGPatternManager.m */; }; + 9424166E213B302600088E93 /* RNSVGPatternManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9424166C213B302600088E93 /* RNSVGPatternManager.m */; }; 9494C4D81F473BA700D5BCFD /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4D71F473BA700D5BCFD /* QuartzCore.framework */; }; 9494C4DA1F473BCB00D5BCFD /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4D91F473BCB00D5BCFD /* CoreText.framework */; }; 9494C4DC1F473BD900D5BCFD /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4DB1F473BD900D5BCFD /* CoreGraphics.framework */; }; @@ -238,6 +242,10 @@ 7FC260D01E34A12000A39833 /* RNSVGSymbol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGSymbol.m; path = Elements/RNSVGSymbol.m; sourceTree = ""; }; 7FC260D21E34A12A00A39833 /* RNSVGSymbolManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGSymbolManager.h; sourceTree = ""; }; 7FC260D31E34A12A00A39833 /* RNSVGSymbolManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGSymbolManager.m; sourceTree = ""; }; + 94241665213B0D4500088E93 /* RNSVGPattern.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNSVGPattern.m; path = Elements/RNSVGPattern.m; sourceTree = ""; }; + 94241669213B0DB800088E93 /* RNSVGPattern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSVGPattern.h; sourceTree = ""; }; + 9424166A213B2FF100088E93 /* RNSVGPatternManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSVGPatternManager.h; sourceTree = ""; }; + 9424166C213B302600088E93 /* RNSVGPatternManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSVGPatternManager.m; sourceTree = ""; }; 9494C4D71F473BA700D5BCFD /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 9494C4D91F473BCB00D5BCFD /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; }; 9494C4DB1F473BD900D5BCFD /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; @@ -334,6 +342,8 @@ 7F08CE971E23476900650F83 /* RNSVGTextPathManager.m */, 7F08CE981E23476900650F83 /* RNSVGTSpanManager.h */, 7F08CE991E23476900650F83 /* RNSVGTSpanManager.m */, + 9424166A213B2FF100088E93 /* RNSVGPatternManager.h */, + 9424166C213B302600088E93 /* RNSVGPatternManager.m */, 10BEC1BE1D3F680F00FDCB19 /* RNSVGLinearGradientManager.h */, 10BEC1BF1D3F680F00FDCB19 /* RNSVGLinearGradientManager.m */, 10BEC1C01D3F680F00FDCB19 /* RNSVGRadialGradientManager.h */, @@ -413,6 +423,8 @@ 7FC260D01E34A12000A39833 /* RNSVGSymbol.m */, 10BEC1B81D3F66F500FDCB19 /* RNSVGLinearGradient.h */, 10BEC1B91D3F66F500FDCB19 /* RNSVGLinearGradient.m */, + 94241669213B0DB800088E93 /* RNSVGPattern.h */, + 94241665213B0D4500088E93 /* RNSVGPattern.m */, 10BEC1BA1D3F66F500FDCB19 /* RNSVGRadialGradient.h */, 10BEC1BB1D3F66F500FDCB19 /* RNSVGRadialGradient.m */, 1023B4911D3DF5060051496D /* RNSVGUse.h */, @@ -543,6 +555,7 @@ B56895AA20352B36004DBF1E /* RNSVGBezierElement.m in Sources */, 10BA0D3F1CE74E3100887C2B /* RNSVGTextManager.m in Sources */, 1039D28A1CE71EB7001E90A8 /* RNSVGImage.m in Sources */, + 94241666213B0D4500088E93 /* RNSVGPattern.m in Sources */, 10BA0D4B1CE74E3D00887C2B /* RNSVGRect.m in Sources */, 10BA0D341CE74E3100887C2B /* RNSVGCircleManager.m in Sources */, 10BEC1BC1D3F66F500FDCB19 /* RNSVGLinearGradient.m in Sources */, @@ -580,6 +593,7 @@ 7FC260D41E34A12A00A39833 /* RNSVGSymbolManager.m in Sources */, 7F9CDAFA1E1F809C00E0C805 /* RNSVGPathParser.m in Sources */, 10BA0D361CE74E3100887C2B /* RNSVGGroupManager.m in Sources */, + 9424166D213B302600088E93 /* RNSVGPatternManager.m in Sources */, 7F08CE9A1E23476900650F83 /* RNSVGTextPathManager.m in Sources */, 7F08CE9B1E23476900650F83 /* RNSVGTSpanManager.m in Sources */, B56895B120352B9C004DBF1E /* RNSVGPropHelper.m in Sources */, @@ -601,6 +615,7 @@ A361E76E1EB0C33D00646005 /* RNSVGTextManager.m in Sources */, A361E76F1EB0C33D00646005 /* RNSVGImage.m in Sources */, A361E7701EB0C33D00646005 /* RNSVGRect.m in Sources */, + 94241667213B0D4500088E93 /* RNSVGPattern.m in Sources */, A361E7711EB0C33D00646005 /* RNSVGCircleManager.m in Sources */, A361E7721EB0C33D00646005 /* RNSVGLinearGradient.m in Sources */, A361E7731EB0C33D00646005 /* RNSVGPercentageConverter.m in Sources */, @@ -638,6 +653,7 @@ A361E7921EB0C33D00646005 /* RNSVGSymbolManager.m in Sources */, A361E7931EB0C33D00646005 /* RNSVGPathParser.m in Sources */, A361E7941EB0C33D00646005 /* RNSVGGroupManager.m in Sources */, + 9424166E213B302600088E93 /* RNSVGPatternManager.m in Sources */, A361E7951EB0C33D00646005 /* RNSVGTextPathManager.m in Sources */, 167AF45B2087C2A10035AA75 /* RNSVGTextProperties.m in Sources */, A361E7961EB0C33D00646005 /* RNSVGTSpanManager.m in Sources */, diff --git a/ios/RNSVGPattern.h b/ios/RNSVGPattern.h new file mode 100644 index 00000000..36db325e --- /dev/null +++ b/ios/RNSVGPattern.h @@ -0,0 +1,21 @@ + +#import "RNSVGGroup.h" + +@interface RNSVGPattern : RNSVGGroup + +@property (nonatomic, strong) NSString *x; +@property (nonatomic, strong) NSString *y; +@property (nonatomic, strong) NSString *patternwidth; +@property (nonatomic, strong) NSString *patternheight; +@property (nonatomic, assign)RNSVGUnits patternUnits; +@property (nonatomic, assign)RNSVGUnits patternContentUnits; +@property (nonatomic, assign)CGAffineTransform patternTransform; + +@property (nonatomic, assign) CGFloat minX; +@property (nonatomic, assign) CGFloat minY; +@property (nonatomic, assign) CGFloat vbWidth; +@property (nonatomic, assign) CGFloat vbHeight; +@property (nonatomic, strong) NSString *align; +@property (nonatomic, assign) RNSVGVBMOS meetOrSlice; + +@end diff --git a/ios/Brushes/RNSVGPattern.h b/ios/ViewManagers/RNSVGPatternManager.h similarity index 72% rename from ios/Brushes/RNSVGPattern.h rename to ios/ViewManagers/RNSVGPatternManager.h index b0a622c9..05d546b6 100644 --- a/ios/Brushes/RNSVGPattern.h +++ b/ios/ViewManagers/RNSVGPatternManager.h @@ -6,8 +6,8 @@ * LICENSE file in the root directory of this source tree. */ -#import "RNSVGBrush.h" +#import "RNSVGGroupManager.h" -@interface RNSVGPattern : RNSVGBrush +@interface RNSVGPatternManager : RNSVGGroupManager @end diff --git a/ios/ViewManagers/RNSVGPatternManager.m b/ios/ViewManagers/RNSVGPatternManager.m new file mode 100644 index 00000000..a6e97b24 --- /dev/null +++ b/ios/ViewManagers/RNSVGPatternManager.m @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015-present, Horcrux. + * All rights reserved. + * + * This source code is licensed under the MIT-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RNSVGPatternManager.h" +#import "RNSVGPattern.h" + +@implementation RNSVGPatternManager + +RCT_EXPORT_MODULE() + +- (RNSVGPattern *)node +{ + return [RNSVGPattern new]; +} + +RCT_EXPORT_VIEW_PROPERTY(x, NSString) +RCT_EXPORT_VIEW_PROPERTY(y, NSString) +RCT_EXPORT_VIEW_PROPERTY(patternwidth, NSString) +RCT_EXPORT_VIEW_PROPERTY(patternheight, NSString) +RCT_EXPORT_VIEW_PROPERTY(patternUnits, RNSVGUnits) +RCT_EXPORT_VIEW_PROPERTY(patternContentUnits, RNSVGUnits) +RCT_EXPORT_VIEW_PROPERTY(patternTransform, CGAffineTransform) + +RCT_EXPORT_VIEW_PROPERTY(minX, CGFloat) +RCT_EXPORT_VIEW_PROPERTY(minY, CGFloat) +RCT_EXPORT_VIEW_PROPERTY(vbWidth, CGFloat) +RCT_EXPORT_VIEW_PROPERTY(vbHeight, CGFloat) +RCT_EXPORT_VIEW_PROPERTY(align, NSString) +RCT_EXPORT_VIEW_PROPERTY(meetOrSlice, RNSVGVBMOS) + +@end diff --git a/lib/attributes.js b/lib/attributes.js index d9e03dc6..316174f2 100644 --- a/lib/attributes.js +++ b/lib/attributes.js @@ -161,6 +161,20 @@ const GradientAttributes = { } }; +const PatternAttributes = { + ...ViewBoxAttributes, + name: true, + x: true, + y: true, + patternwidth: true, + patternheight: true, + patternUnits: true, + patternContentUnits: true, + patternTransform: { + diff: arrayDiffer + } +}; + const LinearGradientAttributes = { ...GradientAttributes, x1: true, @@ -240,5 +254,6 @@ export { SymbolAttributes, LinearGradientAttributes, RadialGradientAttributes, - ViewBoxAttributes + ViewBoxAttributes, + PatternAttributes };