Skip to content

Commit

Permalink
feat: implement support for context-fill and context-stroke color
Browse files Browse the repository at this point in the history
  • Loading branch information
msand committed Oct 3, 2019
1 parent 2af5b6c commit f9a7238
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 0 deletions.
16 changes: 16 additions & 0 deletions android/src/main/java/com/horcrux/svg/RenderableView.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ abstract public class RenderableView extends VirtualView {
super(reactContext);
}

static RenderableView contextElement;
// strokeLinecap
private static final int CAP_BUTT = 0;
static final int CAP_ROUND = 1;
Expand Down Expand Up @@ -378,6 +379,7 @@ void renderMarkers(Canvas canvas, Paint paint, float opacity) {
MarkerView markerMid = (MarkerView)getSvgView().getDefinedMarker(mMarkerMid);
MarkerView markerEnd = (MarkerView)getSvgView().getDefinedMarker(mMarkerEnd);
if (elements != null && (markerStart != null || markerMid != null || markerEnd != null)) {
contextElement = this;
ArrayList<RNSVGMarkerPosition> positions = RNSVGMarkerPosition.fromPath(elements);
float width = (float)(this.strokeWidth != null ? relativeOnOther(this.strokeWidth) : 1);
for (RNSVGMarkerPosition position : positions) {
Expand All @@ -399,8 +401,10 @@ void renderMarkers(Canvas canvas, Paint paint, float opacity) {
break;
}
}
contextElement = null;
}
}

/**
* Sets up paint according to the props set on a view. Returns {@code true}
* if the fill should be drawn, {@code false} if not.
Expand Down Expand Up @@ -477,6 +481,18 @@ private void setupPaint(Paint paint, float opacity, ReadableArray colors) {
paint.setColor(brush);
break;
}
case 3: {
if (contextElement != null && contextElement.fill != null) {
setupPaint(paint, opacity, contextElement.fill);
}
break;
}
case 4: {
if (contextElement != null && contextElement.stroke != null) {
setupPaint(paint, opacity, contextElement.stroke);
}
break;
}
}

}
Expand Down
16 changes: 16 additions & 0 deletions ios/Brushes/RNSVGContextBrush.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Copyright (c) 2015-present, react-native-community.
* 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 "RNSVGBrush.h"

@interface RNSVGContextBrush : RNSVGBrush

- (instancetype)initFill;
- (instancetype)initStroke;

@end
85 changes: 85 additions & 0 deletions ios/Brushes/RNSVGContextBrush.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* Copyright (c) 2015-present, react-native-community.
* 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 "RNSVGContextBrush.h"
#import "RNSVGRenderable.h"
#import "RNSVGNode.h"

#import "RCTConvert+RNSVG.h"
#import <React/RCTLog.h>

@implementation RNSVGContextBrush
{
BOOL _isStroke;
}

- (instancetype)initFill
{
if ((self = [super initWithArray:nil])) {
_isStroke = NO;
}
return self;
}

- (instancetype)initStroke
{
if ((self = [super initWithArray:nil])) {
_isStroke = YES;
}
return self;
}

- (void)dealloc
{
}

- (BOOL)applyFillColor:(CGContextRef)context opacity:(CGFloat)opacity
{
RNSVGRenderable *element = RNSVGRenderable.contextElement;
if (!element) {
return NO;
}

RNSVGBrush *brush = _isStroke ? element.stroke : element.fill;

BOOL fillColor;

if (brush.class == RNSVGBrush.class) {
CGContextSetFillColorWithColor(context, [element.tintColor CGColor]);
fillColor = YES;
} else {
fillColor = [brush applyFillColor:context opacity:opacity];
}

return fillColor;
}



- (BOOL)applyStrokeColor:(CGContextRef)context opacity:(CGFloat)opacity
{
RNSVGRenderable *element = RNSVGRenderable.contextElement;
if (!element) {
return NO;
}

RNSVGBrush *brush = _isStroke ? element.stroke : element.fill;

BOOL strokeColor;

if (brush.class == RNSVGBrush.class) {
CGContextSetStrokeColorWithColor(context, [element.tintColor CGColor]);
strokeColor = YES;
} else {
strokeColor = [brush applyStrokeColor:context opacity:opacity];
}

return YES;
}

@end
8 changes: 8 additions & 0 deletions ios/RNSVG.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
947F380C214810DC00677F2A /* RNSVGMask.m in Sources */ = {isa = PBXBuildFile; fileRef = 947F380A214810DC00677F2A /* RNSVGMask.m */; };
947F380F2148119A00677F2A /* RNSVGMaskManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 947F380E2148119A00677F2A /* RNSVGMaskManager.m */; };
947F38102148119A00677F2A /* RNSVGMaskManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 947F380E2148119A00677F2A /* RNSVGMaskManager.m */; };
9482DEFA23460EC800FC486E /* RNSVGContextBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 9482DEF823460EC700FC486E /* RNSVGContextBrush.m */; };
9482DEFB23460EC800FC486E /* RNSVGContextBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 9482DEF823460EC700FC486E /* RNSVGContextBrush.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 */; };
Expand Down Expand Up @@ -257,6 +259,8 @@
947F380A214810DC00677F2A /* RNSVGMask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGMask.m; path = Elements/RNSVGMask.m; sourceTree = "<group>"; };
947F380D2148118300677F2A /* RNSVGMaskManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGMaskManager.h; sourceTree = "<group>"; };
947F380E2148119A00677F2A /* RNSVGMaskManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGMaskManager.m; sourceTree = "<group>"; };
9482DEF823460EC700FC486E /* RNSVGContextBrush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGContextBrush.m; sourceTree = "<group>"; };
9482DEF923460EC800FC486E /* RNSVGContextBrush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGContextBrush.h; sourceTree = "<group>"; };
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; };
Expand Down Expand Up @@ -340,6 +344,8 @@
0CF68AEA1AF0549300FF9E5C /* Brushes */ = {
isa = PBXGroup;
children = (
9482DEF923460EC800FC486E /* RNSVGContextBrush.h */,
9482DEF823460EC700FC486E /* RNSVGContextBrush.m */,
10FDEEB31D3FBED400A5C46C /* RNSVGBrushType.h */,
10FDEEB01D3FB60500A5C46C /* RNSVGPainterBrush.h */,
10FDEEB11D3FB60500A5C46C /* RNSVGPainterBrush.m */,
Expand Down Expand Up @@ -599,6 +605,7 @@
10BEC1C21D3F680F00FDCB19 /* RNSVGLinearGradientManager.m in Sources */,
1039D2951CE71EC2001E90A8 /* RNSVGText.m in Sources */,
10BA0D3B1CE74E3100887C2B /* RNSVGRectManager.m in Sources */,
9482DEFA23460EC800FC486E /* RNSVGContextBrush.m in Sources */,
0CF68B071AF0549300FF9E5C /* RNSVGRenderable.m in Sources */,
1039D2891CE71EB7001E90A8 /* RNSVGGroup.m in Sources */,
10ED4A9E1CF0656A0078BC02 /* RNSVGClipPathManager.m in Sources */,
Expand Down Expand Up @@ -664,6 +671,7 @@
A361E77A1EB0C33D00646005 /* RNSVGText.m in Sources */,
A361E77B1EB0C33D00646005 /* RNSVGRectManager.m in Sources */,
A361E77C1EB0C33D00646005 /* RNSVGRenderable.m in Sources */,
9482DEFB23460EC800FC486E /* RNSVGContextBrush.m in Sources */,
A361E77D1EB0C33D00646005 /* RNSVGGroup.m in Sources */,
A361E77E1EB0C33D00646005 /* RNSVGClipPathManager.m in Sources */,
A361E77F1EB0C33D00646005 /* RNSVGPainter.m in Sources */,
Expand Down
1 change: 1 addition & 0 deletions ios/RNSVGRenderable.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

@interface RNSVGRenderable : RNSVGNode

@property (class) RNSVGRenderable *contextElement;
@property (nonatomic, strong) RNSVGBrush *fill;
@property (nonatomic, assign) CGFloat fillOpacity;
@property (nonatomic, assign) RNSVGCGFCRule fillRule;
Expand Down
6 changes: 6 additions & 0 deletions ios/RNSVGRenderable.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ @implementation RNSVGRenderable
CGPathRef _hitArea;
}

static RNSVGRenderable * _contextElement;
+ (RNSVGRenderable *)contextElement { return _contextElement; }
+ (void)setContextElement:(RNSVGRenderable *)contextElement { _contextElement = contextElement; }

- (id)init
{
if (self = [super init]) {
Expand Down Expand Up @@ -304,6 +308,7 @@ - (void)renderMarkers:(CGContextRef)context path:(CGPathRef)path rect:(const CGR
RNSVGMarker *markerMid = (RNSVGMarker*)[self.svgView getDefinedMarker:self.markerMid];
RNSVGMarker *markerEnd = (RNSVGMarker*)[self.svgView getDefinedMarker:self.markerEnd];
if (markerStart || markerMid || markerEnd) {
_contextElement = self;
NSArray<RNSVGMarkerPosition*>* positions = [RNSVGMarkerPosition fromCGPath:path];
CGFloat width = self.strokeWidth ? [self relativeOnOther:self.strokeWidth] : 1;
for (RNSVGMarkerPosition* position in positions) {
Expand All @@ -325,6 +330,7 @@ - (void)renderMarkers:(CGContextRef)context path:(CGPathRef)path rect:(const CGR
break;
}
}
_contextElement = nil;
}
}

Expand Down
5 changes: 5 additions & 0 deletions ios/Utils/RCTConvert+RNSVG.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#import "RNSVGPainterBrush.h"
#import "RNSVGSolidColorBrush.h"
#import "RNSVGContextBrush.h"
#import <React/RCTLog.h>
#import <React/RCTFont.h>

Expand Down Expand Up @@ -65,6 +66,10 @@ + (RNSVGBrush *)RNSVGBrush:(id)json
return [[RNSVGPainterBrush alloc] initWithArray:arr];
case 2: // currentColor
return [[RNSVGBrush alloc] initWithArray:nil];
case 3: // context-fill
return [[RNSVGContextBrush alloc] initFill];
case 4: // context-stroke
return [[RNSVGContextBrush alloc] initStroke];
default:
RCTLogError(@"Unknown brush type: %zd", (unsigned long)type);
return nil;
Expand Down
10 changes: 10 additions & 0 deletions src/lib/extract/extractBrush.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Color } from './types';
const urlIdPattern = /^url\(#(.+)\)$/;

const currentColorBrush = [2];
const contextFillBrush = [3];
const contextStrokeBrush = [4];

export default function extractBrush(color?: Color) {
if (typeof color === 'number') {
Expand All @@ -20,6 +22,14 @@ export default function extractBrush(color?: Color) {
return currentColorBrush;
}

if (color === 'context-fill') {
return contextFillBrush;
}

if (color === 'context-stroke') {
return contextStrokeBrush;
}

const brush = typeof color === 'string' && color.match(urlIdPattern);
if (brush) {
return [1, brush[1]];
Expand Down

0 comments on commit f9a7238

Please sign in to comment.