mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-09 09:27:20 +00:00
fix memory leak issue with CGMutablePathRef
This commit is contained in:
@@ -37,7 +37,7 @@ class StrokeCircle extends Component{
|
|||||||
r="45"
|
r="45"
|
||||||
stroke="purple"
|
stroke="purple"
|
||||||
strokeWidth="2.5"
|
strokeWidth="2.5"
|
||||||
fill={null}
|
fill="none"
|
||||||
/>
|
/>
|
||||||
</Svg>;
|
</Svg>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ class DefsExample extends Component{
|
|||||||
>
|
>
|
||||||
<Defs>
|
<Defs>
|
||||||
<G id="path" x="5" y="2" opacity="0.9">
|
<G id="path" x="5" y="2" opacity="0.9">
|
||||||
<Path id="test" fill='red' d="M38.459,1.66A0.884,0.884,0,0,1,39,2.5a0.7,0.7,0,0,1-.3.575L23.235,16.092,27.58,26.1a1.4,1.4,0,0,1,.148.3,1.3,1.3,0,0,1,0,.377,1.266,1.266,0,0,1-2.078.991L15.526,20.6l-7.58,4.35a1.255,1.255,0,0,1-.485,0,1.267,1.267,0,0,1-1.277-1.258q0-.01,0-0.02a1.429,1.429,0,0,1,0-.446C7.243,20.253,8.6,16.369,8.6,16.29L3.433,13.545A0.743,0.743,0,0,1,2.9,12.822a0.822,0.822,0,0,1,.623-0.773l8.164-2.972,3.018-8.5A0.822,0.822,0,0,1,15.427,0a0.752,0.752,0,0,1,.752.555l2.563,6.936S37.65,1.727,37.792,1.685A1.15,1.15,0,0,1,38.459,1.66Z"/>
|
<Path id="test" d="M38.459,1.66A0.884,0.884,0,0,1,39,2.5a0.7,0.7,0,0,1-.3.575L23.235,16.092,27.58,26.1a1.4,1.4,0,0,1,.148.3,1.3,1.3,0,0,1,0,.377,1.266,1.266,0,0,1-2.078.991L15.526,20.6l-7.58,4.35a1.255,1.255,0,0,1-.485,0,1.267,1.267,0,0,1-1.277-1.258q0-.01,0-0.02a1.429,1.429,0,0,1,0-.446C7.243,20.253,8.6,16.369,8.6,16.29L3.433,13.545A0.743,0.743,0,0,1,2.9,12.822a0.822,0.822,0,0,1,.623-0.773l8.164-2.972,3.018-8.5A0.822,0.822,0,0,1,15.427,0a0.752,0.752,0,0,1,.752.555l2.563,6.936S37.65,1.727,37.792,1.685A1.15,1.15,0,0,1,38.459,1.66Z" />
|
||||||
</G>
|
</G>
|
||||||
<ClipPath id="clip">
|
<ClipPath id="clip">
|
||||||
<Circle r="20%" cx="0" cy="0" />
|
<Circle r="25%" cx="0%" cy="0%" />
|
||||||
</ClipPath>
|
</ClipPath>
|
||||||
<LinearGradient id="linear" x1="0%" y1="0%" x2="100%" y2="0%">
|
<LinearGradient id="linear" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
<Stop offset="0%" stopColor="yellow" />
|
<Stop offset="0%" stopColor="yellow" />
|
||||||
@@ -41,9 +41,9 @@ class DefsExample extends Component{
|
|||||||
<Stop offset="100%" stopColor="blue" />
|
<Stop offset="100%" stopColor="blue" />
|
||||||
</RadialGradient>
|
</RadialGradient>
|
||||||
</Defs>
|
</Defs>
|
||||||
<Use href="url(#path)" x="0" fill="blue" opacity="0.2" />
|
<Use href="url(#path)" x="0" fill="blue" opacity="0.6" />
|
||||||
<Use href="url(#path)" x="20" y="5" fill="url(#linear)" />
|
<Use href="url(#path)" x="20" y="5" fill="url(#linear)" />
|
||||||
<Use href="url(#path)" x="50" clipPath="url(#clip)" fillOpacity="0.6" />
|
<Use href="url(#path)" clipPath="url(#clip)" fillOpacity="0.6" stroke="#000" />
|
||||||
<Use href="url(#path)" x="-10" y="20" fill="red" fill="url(#radial)" />
|
<Use href="url(#path)" x="-10" y="20" fill="red" fill="url(#radial)" />
|
||||||
</Svg>;
|
</Svg>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import Svg, {
|
|||||||
|
|
||||||
class PathExample extends Component{
|
class PathExample extends Component{
|
||||||
static title = 'Path';
|
static title = 'Path';
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <Svg
|
return <Svg
|
||||||
height="100"
|
height="100"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import Svg, {
|
|||||||
|
|
||||||
class PolygonExample extends Component{
|
class PolygonExample extends Component{
|
||||||
static title = 'The following example creates a polygon with three sides';
|
static title = 'The following example creates a polygon with three sides';
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <Svg
|
return <Svg
|
||||||
height="100"
|
height="100"
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class TextExample extends Component{
|
|||||||
|
|
||||||
class TextRotate extends Component{
|
class TextRotate extends Component{
|
||||||
static title = 'Transform the text';
|
static title = 'Transform the text';
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <Svg
|
return <Svg
|
||||||
height="60"
|
height="60"
|
||||||
@@ -115,13 +116,31 @@ class TextFill extends Component{
|
|||||||
|
|
||||||
|
|
||||||
class TextPath extends Component{
|
class TextPath extends Component{
|
||||||
static title = 'Transform the text';
|
static title = 'Draw text along path';
|
||||||
|
|
||||||
|
constructor(...args) {
|
||||||
|
super(...args);
|
||||||
|
this.state = {
|
||||||
|
key: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
let self = this;
|
||||||
|
//setInterval(function () {
|
||||||
|
// self.setState({
|
||||||
|
// key: self.state.key + 1
|
||||||
|
// });
|
||||||
|
//}, 50);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <Svg
|
return <Svg
|
||||||
height="60"
|
height="60"
|
||||||
width="200"
|
width="200"
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
|
key={this.state.key}
|
||||||
fill="red"
|
fill="red"
|
||||||
path={`
|
path={`
|
||||||
M 10 20
|
M 10 20
|
||||||
|
|||||||
+1
-1
@@ -111,7 +111,7 @@ const styles = StyleSheet.create({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const names = ['Svg', 'Stroking', 'Path', 'Line', 'Rect', 'Polygon', 'Polyline', 'Circle', 'Ellipse', 'G', 'Text', 'Use', 'Symbol', 'Gradients', 'Clipping', 'Image', 'TouchEvents'];
|
const names = ['Svg', 'Stroking', 'Path', 'Line', 'Rect', 'Polygon', 'Polyline', 'Circle', 'Ellipse', 'G', 'Text', 'Use', 'Symbol', 'Gradients', 'Clipping', 'Image', 'TouchEvents', 'Definations'];
|
||||||
//const names = ['Definations'];
|
//const names = ['Definations'];
|
||||||
|
|
||||||
class SvgExample extends Component {
|
class SvgExample extends Component {
|
||||||
|
|||||||
+11
-2
@@ -4,6 +4,7 @@ import createReactNativeComponentClass from 'react/lib/createReactNativeComponen
|
|||||||
import {transformProps} from '../lib/props';
|
import {transformProps} from '../lib/props';
|
||||||
import {GroupAttributes} from '../lib/attributes';
|
import {GroupAttributes} from '../lib/attributes';
|
||||||
import extractProps from '../lib/extract/extractProps';
|
import extractProps from '../lib/extract/extractProps';
|
||||||
|
import reusableProps from '../lib/reusableProps';
|
||||||
|
|
||||||
class G extends Component{
|
class G extends Component{
|
||||||
static displayName = 'G';
|
static displayName = 'G';
|
||||||
@@ -15,10 +16,18 @@ class G extends Component{
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
let {props} = this;
|
||||||
|
|
||||||
|
let extractedProps = extractProps(props, {
|
||||||
|
stroke: true,
|
||||||
|
fill: true,
|
||||||
|
transform: true
|
||||||
|
});
|
||||||
|
|
||||||
return <RNSVGGroup
|
return <RNSVGGroup
|
||||||
{...extractProps(this.props, {transform: true})}
|
{...extractedProps}
|
||||||
ref={ele => this.root = ele}
|
ref={ele => this.root = ele}
|
||||||
asClipPath={this.props.asClipPath}
|
mergeList={reusableProps(extractedProps, props)}
|
||||||
>
|
>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</RNSVGGroup>;
|
</RNSVGGroup>;
|
||||||
|
|||||||
+3
-20
@@ -1,10 +1,11 @@
|
|||||||
import {PropTypes} from 'react';
|
import {PropTypes} from 'react';
|
||||||
import {pathProps} from '../lib/props';
|
import {pathProps} from '../lib/props';
|
||||||
import {UseAttributes, RenderableOnlyAttributes} from '../lib/attributes';
|
import {UseAttributes} from '../lib/attributes';
|
||||||
import Shape from './Shape';
|
import Shape from './Shape';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import patternReg from '../lib/extract/patternReg';
|
import patternReg from '../lib/extract/patternReg';
|
||||||
import createReactNativeComponentClass from 'react/lib/createReactNativeComponentClass';
|
import createReactNativeComponentClass from 'react/lib/createReactNativeComponentClass';
|
||||||
|
import reusableProps from '../lib/reusableProps';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
class Defs extends Shape {
|
class Defs extends Shape {
|
||||||
@@ -33,8 +34,6 @@ class Defs extends Shape {
|
|||||||
console.warn('Invalid `href` prop for `Use` element, expected a href like `"url(#id)"`, but got: "' + props.href + '"');
|
console.warn('Invalid `href` prop for `Use` element, expected a href like `"url(#id)"`, but got: "' + props.href + '"');
|
||||||
}
|
}
|
||||||
|
|
||||||
let mergeList = [];
|
|
||||||
|
|
||||||
let extractedProps = this.extractProps(props, {
|
let extractedProps = this.extractProps(props, {
|
||||||
stroke: true,
|
stroke: true,
|
||||||
fill: true,
|
fill: true,
|
||||||
@@ -42,26 +41,10 @@ class Defs extends Shape {
|
|||||||
transform: true
|
transform: true
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.keys(RenderableOnlyAttributes).forEach(name => {
|
|
||||||
|
|
||||||
if (!_.isNil(props[name])) {
|
|
||||||
// clipPath prop may provide `clipPathRef` as native prop
|
|
||||||
if (name === 'clipPath') {
|
|
||||||
if (extractedProps[name]) {
|
|
||||||
mergeList.push(name);
|
|
||||||
} else if (extractedProps.clipPathRef) {
|
|
||||||
mergeList.push('clipPathRef');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mergeList.push(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return <RNSVGUse
|
return <RNSVGUse
|
||||||
ref={ele => this.root = ele}
|
ref={ele => this.root = ele}
|
||||||
{...extractedProps}
|
{...extractedProps}
|
||||||
mergeList={mergeList}
|
mergeList={reusableProps(extractedProps, props)}
|
||||||
href={href}
|
href={href}
|
||||||
>{props.children}</RNSVGUse>;
|
>{props.children}</RNSVGUse>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
@interface RNSVGGroup : RNSVGNode <RNSVGContainer>
|
@interface RNSVGGroup : RNSVGNode <RNSVGContainer>
|
||||||
|
|
||||||
|
@property (nonatomic, copy) NSArray<NSString *> *mergeList;
|
||||||
|
|
||||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
|
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
[self clip:context];
|
[self clip:context];
|
||||||
|
|
||||||
for (RNSVGNode *node in self.subviews) {
|
for (RNSVGNode *node in self.subviews) {
|
||||||
|
//[node mergeProperties:self mergeList:self.mergeList];
|
||||||
[node renderTo:context];
|
[node renderTo:context];
|
||||||
|
|
||||||
if (node.responsible && !svg.responsible) {
|
if (node.responsible && !svg.responsible) {
|
||||||
@@ -32,7 +33,7 @@
|
|||||||
CGAffineTransform transform = node.transform;
|
CGAffineTransform transform = node.transform;
|
||||||
CGPathAddPath(path, &transform, [node getPath:context]);
|
CGPathAddPath(path, &transform, [node getPath:context]);
|
||||||
}
|
}
|
||||||
return path;
|
return (CGPathRef)CFAutorelease(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// hitTest delagate
|
// hitTest delagate
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
{
|
{
|
||||||
CGImageRef image;
|
CGImageRef image;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setSrc:(id)src
|
- (void)setSrc:(id)src
|
||||||
{
|
{
|
||||||
if (src == _src) {
|
if (src == _src) {
|
||||||
@@ -79,7 +80,10 @@
|
|||||||
CGFloat h = [convert stringToFloat:self.height relative:height offset:0];
|
CGFloat h = [convert stringToFloat:self.height relative:height offset:0];
|
||||||
|
|
||||||
// add hit area
|
// add hit area
|
||||||
CGPathAddPath(self.nodeArea, nil, CGPathCreateWithRect(CGRectMake(x, y, w, h), nil));
|
self.hitArea = CGPathCreateMutable();
|
||||||
|
CGPathRef rect = CGPathCreateWithRect(CGRectMake(x, y, w, h), nil);
|
||||||
|
CGPathAddPath(self.hitArea, nil, rect);
|
||||||
|
CGPathRelease(rect);
|
||||||
|
|
||||||
if (self.opacity == 0) {
|
if (self.opacity == 0) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -31,13 +31,14 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add path to nodeArea
|
// Add path to hitArea
|
||||||
CGPathAddPath(self.nodeArea, nil, _d);
|
self.hitArea = CGPathCreateMutableCopy(_d);
|
||||||
|
|
||||||
if (self.stroke) {
|
if (self.stroke) {
|
||||||
// Add stroke to nodeArea
|
// Add stroke to hitArea
|
||||||
CGPathRef strokePath = CGPathCreateCopyByStrokingPath(_d, nil, self.strokeWidth, self.strokeLinecap, self.strokeLinejoin, self.strokeMiterlimit);
|
CGPathRef strokePath = CGPathCreateCopyByStrokingPath(_d, nil, self.strokeWidth, self.strokeLinecap, self.strokeLinejoin, self.strokeMiterlimit);
|
||||||
CGPathAddPath(self.nodeArea, nil, strokePath);
|
CGPathAddPath(self.hitArea, nil, strokePath);
|
||||||
|
CGPathRelease(strokePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.opacity == 0) {
|
if (self.opacity == 0) {
|
||||||
|
|||||||
@@ -17,5 +17,4 @@
|
|||||||
@property (nonatomic, strong) NSString *href;
|
@property (nonatomic, strong) NSString *href;
|
||||||
@property (nonatomic, copy) NSArray<NSString *> *mergeList;
|
@property (nonatomic, copy) NSArray<NSString *> *mergeList;
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -23,9 +23,21 @@
|
|||||||
{
|
{
|
||||||
RNSVGNode* template = [[self getSvgView] getDefinedTemplate:self.href];
|
RNSVGNode* template = [[self getSvgView] getDefinedTemplate:self.href];
|
||||||
if (template) {
|
if (template) {
|
||||||
|
CGFloat opacity = self.opacity;
|
||||||
|
BOOL transparent = opacity < 1;
|
||||||
|
|
||||||
|
if (transparent) {
|
||||||
|
CGContextBeginTransparencyLayer(context, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[self clip:context];
|
||||||
[template mergeProperties:self mergeList:self.mergeList];
|
[template mergeProperties:self mergeList:self.mergeList];
|
||||||
[template renderTo:context];
|
[template renderTo:context];
|
||||||
[template resetProperties];
|
[template resetProperties];
|
||||||
|
|
||||||
|
if (transparent) {
|
||||||
|
CGContextEndTransparencyLayer(context);
|
||||||
|
}
|
||||||
} else if (self.href) {
|
} else if (self.href) {
|
||||||
// TODO: calling yellow box here
|
// TODO: calling yellow box here
|
||||||
RCTLogWarn(@"`Use` element expected a pre-defined svg template as `href` prop, template named: %@ is not defined.", self.href);
|
RCTLogWarn(@"`Use` element expected a pre-defined svg template as `href` prop, template named: %@ is not defined.", self.href);
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
1039D28A1CE71EB7001E90A8 /* RNSVGImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2841CE71EB7001E90A8 /* RNSVGImage.m */; };
|
1039D28A1CE71EB7001E90A8 /* RNSVGImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2841CE71EB7001E90A8 /* RNSVGImage.m */; };
|
||||||
1039D28B1CE71EB7001E90A8 /* RNSVGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2861CE71EB7001E90A8 /* RNSVGPath.m */; };
|
1039D28B1CE71EB7001E90A8 /* RNSVGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2861CE71EB7001E90A8 /* RNSVGPath.m */; };
|
||||||
1039D28C1CE71EB7001E90A8 /* RNSVGSvgView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2881CE71EB7001E90A8 /* RNSVGSvgView.m */; };
|
1039D28C1CE71EB7001E90A8 /* RNSVGSvgView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2881CE71EB7001E90A8 /* RNSVGSvgView.m */; };
|
||||||
1039D2941CE71EC2001E90A8 /* RnSVGGlyphCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D28E1CE71EC2001E90A8 /* RnSVGGlyphCache.m */; };
|
|
||||||
1039D2951CE71EC2001E90A8 /* RNSVGText.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2901CE71EC2001E90A8 /* RNSVGText.m */; };
|
1039D2951CE71EC2001E90A8 /* RNSVGText.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2901CE71EC2001E90A8 /* RNSVGText.m */; };
|
||||||
1039D2961CE71EC2001E90A8 /* UIBezierPath-Points.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2931CE71EC2001E90A8 /* UIBezierPath-Points.m */; };
|
1039D2961CE71EC2001E90A8 /* UIBezierPath-Points.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2931CE71EC2001E90A8 /* UIBezierPath-Points.m */; };
|
||||||
1039D2A01CE72177001E90A8 /* RCTConvert+RNSVG.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D29C1CE72177001E90A8 /* RCTConvert+RNSVG.m */; };
|
1039D2A01CE72177001E90A8 /* RCTConvert+RNSVG.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D29C1CE72177001E90A8 /* RCTConvert+RNSVG.m */; };
|
||||||
@@ -88,8 +87,6 @@
|
|||||||
1039D2861CE71EB7001E90A8 /* RNSVGPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGPath.m; path = Elements/RNSVGPath.m; sourceTree = "<group>"; };
|
1039D2861CE71EB7001E90A8 /* RNSVGPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGPath.m; path = Elements/RNSVGPath.m; sourceTree = "<group>"; };
|
||||||
1039D2871CE71EB7001E90A8 /* RNSVGSvgView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGSvgView.h; path = Elements/RNSVGSvgView.h; sourceTree = "<group>"; };
|
1039D2871CE71EB7001E90A8 /* RNSVGSvgView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGSvgView.h; path = Elements/RNSVGSvgView.h; sourceTree = "<group>"; };
|
||||||
1039D2881CE71EB7001E90A8 /* RNSVGSvgView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGSvgView.m; path = Elements/RNSVGSvgView.m; sourceTree = "<group>"; };
|
1039D2881CE71EB7001E90A8 /* RNSVGSvgView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGSvgView.m; path = Elements/RNSVGSvgView.m; sourceTree = "<group>"; };
|
||||||
1039D28D1CE71EC2001E90A8 /* RNSVGGlyphCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGGlyphCache.h; path = Text/RNSVGGlyphCache.h; sourceTree = "<group>"; };
|
|
||||||
1039D28E1CE71EC2001E90A8 /* RnSVGGlyphCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RnSVGGlyphCache.m; path = Text/RnSVGGlyphCache.m; sourceTree = "<group>"; };
|
|
||||||
1039D28F1CE71EC2001E90A8 /* RNSVGText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGText.h; path = Text/RNSVGText.h; sourceTree = "<group>"; };
|
1039D28F1CE71EC2001E90A8 /* RNSVGText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGText.h; path = Text/RNSVGText.h; sourceTree = "<group>"; };
|
||||||
1039D2901CE71EC2001E90A8 /* RNSVGText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGText.m; path = Text/RNSVGText.m; sourceTree = "<group>"; };
|
1039D2901CE71EC2001E90A8 /* RNSVGText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGText.m; path = Text/RNSVGText.m; sourceTree = "<group>"; };
|
||||||
1039D2911CE71EC2001E90A8 /* RNSVGTextFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGTextFrame.h; path = Text/RNSVGTextFrame.h; sourceTree = "<group>"; };
|
1039D2911CE71EC2001E90A8 /* RNSVGTextFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGTextFrame.h; path = Text/RNSVGTextFrame.h; sourceTree = "<group>"; };
|
||||||
@@ -265,8 +262,6 @@
|
|||||||
1039D27F1CE71D9B001E90A8 /* Text */ = {
|
1039D27F1CE71D9B001E90A8 /* Text */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
1039D28D1CE71EC2001E90A8 /* RNSVGGlyphCache.h */,
|
|
||||||
1039D28E1CE71EC2001E90A8 /* RnSVGGlyphCache.m */,
|
|
||||||
1039D28F1CE71EC2001E90A8 /* RNSVGText.h */,
|
1039D28F1CE71EC2001E90A8 /* RNSVGText.h */,
|
||||||
1039D2901CE71EC2001E90A8 /* RNSVGText.m */,
|
1039D2901CE71EC2001E90A8 /* RNSVGText.m */,
|
||||||
1039D2911CE71EC2001E90A8 /* RNSVGTextFrame.h */,
|
1039D2911CE71EC2001E90A8 /* RNSVGTextFrame.h */,
|
||||||
@@ -373,7 +368,6 @@
|
|||||||
1039D28A1CE71EB7001E90A8 /* RNSVGImage.m in Sources */,
|
1039D28A1CE71EB7001E90A8 /* RNSVGImage.m in Sources */,
|
||||||
10BA0D4B1CE74E3D00887C2B /* RNSVGRect.m in Sources */,
|
10BA0D4B1CE74E3D00887C2B /* RNSVGRect.m in Sources */,
|
||||||
10BA0D341CE74E3100887C2B /* RNSVGCircleManager.m in Sources */,
|
10BA0D341CE74E3100887C2B /* RNSVGCircleManager.m in Sources */,
|
||||||
1039D2941CE71EC2001E90A8 /* RnSVGGlyphCache.m in Sources */,
|
|
||||||
10BEC1BC1D3F66F500FDCB19 /* RNSVGLinearGradient.m in Sources */,
|
10BEC1BC1D3F66F500FDCB19 /* RNSVGLinearGradient.m in Sources */,
|
||||||
1039D2B01CE72F27001E90A8 /* RNSVGPercentageConverter.m in Sources */,
|
1039D2B01CE72F27001E90A8 /* RNSVGPercentageConverter.m in Sources */,
|
||||||
10BA0D491CE74E3D00887C2B /* RNSVGEllipse.m in Sources */,
|
10BA0D491CE74E3D00887C2B /* RNSVGEllipse.m in Sources */,
|
||||||
|
|||||||
+6
-7
@@ -11,9 +11,6 @@
|
|||||||
#import "RNSVGClipPath.h"
|
#import "RNSVGClipPath.h"
|
||||||
|
|
||||||
@implementation RNSVGNode
|
@implementation RNSVGNode
|
||||||
{
|
|
||||||
CGFloat originOpacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
|
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
|
||||||
{
|
{
|
||||||
@@ -76,11 +73,14 @@
|
|||||||
CGContextSaveGState(context);
|
CGContextSaveGState(context);
|
||||||
CGContextConcatCTM(context, self.transform);
|
CGContextConcatCTM(context, self.transform);
|
||||||
CGContextSetAlpha(context, opacity);
|
CGContextSetAlpha(context, opacity);
|
||||||
|
|
||||||
if (transparent) {
|
if (transparent) {
|
||||||
CGContextBeginTransparencyLayer(context, NULL);
|
CGContextBeginTransparencyLayer(context, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
[self renderClip:context];
|
[self renderClip:context];
|
||||||
[self renderLayerTo:context];
|
[self renderLayerTo:context];
|
||||||
|
|
||||||
if (transparent) {
|
if (transparent) {
|
||||||
CGContextEndTransparencyLayer(context);
|
CGContextEndTransparencyLayer(context);
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
- (CGPathRef)getPath: (CGContextRef) context
|
- (CGPathRef)getPath: (CGContextRef) context
|
||||||
{
|
{
|
||||||
// abstract
|
// abstract
|
||||||
return CGPathCreateMutable();
|
return (CGPathRef)CFAutorelease(CGPathCreateMutable());
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)clip:(CGContextRef)context
|
- (void)clip:(CGContextRef)context
|
||||||
@@ -193,13 +193,12 @@
|
|||||||
|
|
||||||
- (void)mergeProperties:(__kindof RNSVGNode *)target mergeList:(NSArray<NSString *> *)mergeList
|
- (void)mergeProperties:(__kindof RNSVGNode *)target mergeList:(NSArray<NSString *> *)mergeList
|
||||||
{
|
{
|
||||||
originOpacity = self.opacity;
|
// abstract
|
||||||
self.opacity = target.opacity * self.opacity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)resetProperties
|
- (void)resetProperties
|
||||||
{
|
{
|
||||||
self.opacity = originOpacity;
|
// abstract
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
@property (nonatomic, assign) CGFloat strokeMiterlimit;
|
@property (nonatomic, assign) CGFloat strokeMiterlimit;
|
||||||
@property (nonatomic, assign) RNSVGCGFloatArray strokeDasharray;
|
@property (nonatomic, assign) RNSVGCGFloatArray strokeDasharray;
|
||||||
@property (nonatomic, assign) CGFloat strokeDashoffset;
|
@property (nonatomic, assign) CGFloat strokeDashoffset;
|
||||||
@property (nonatomic, assign) CGMutablePathRef nodeArea;
|
@property (nonatomic, assign) CGMutablePathRef hitArea;
|
||||||
|
|
||||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
|
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
|
||||||
|
|
||||||
|
|||||||
+16
-7
@@ -16,13 +16,24 @@
|
|||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
self = [super init];
|
if (self = [super init]) {
|
||||||
if (self) {
|
_fillOpacity = 1;
|
||||||
_nodeArea = CGPathCreateMutable();
|
_strokeOpacity = 1;
|
||||||
|
_strokeWidth = 1;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setHitArea:(CGMutablePathRef)hitArea
|
||||||
|
{
|
||||||
|
if (hitArea == _hitArea) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[self invalidate];
|
||||||
|
CGPathRelease(_hitArea);
|
||||||
|
_hitArea = hitArea;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setFill:(RNSVGBrush *)fill
|
- (void)setFill:(RNSVGBrush *)fill
|
||||||
{
|
{
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
@@ -79,7 +90,7 @@
|
|||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
CGPathRelease(_nodeArea);
|
CGPathRelease(_hitArea);
|
||||||
if (_strokeDasharray.array) {
|
if (_strokeDasharray.array) {
|
||||||
free(_strokeDasharray.array);
|
free(_strokeDasharray.array);
|
||||||
}
|
}
|
||||||
@@ -106,7 +117,7 @@
|
|||||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||||
{
|
{
|
||||||
CGPathRef clipPath = self.clipPath;
|
CGPathRef clipPath = self.clipPath;
|
||||||
if (self.nodeArea && CGPathContainsPoint(self.nodeArea, nil, point, NO)) {
|
if (self.hitArea && CGPathContainsPoint(self.hitArea, nil, point, NO)) {
|
||||||
if (!clipPath) {
|
if (!clipPath) {
|
||||||
return self;
|
return self;
|
||||||
} else {
|
} else {
|
||||||
@@ -131,8 +142,6 @@
|
|||||||
[originProperties setValue:[self valueForKey:key] forKey:key];
|
[originProperties setValue:[self valueForKey:key] forKey:key];
|
||||||
[self setValue:[target valueForKey:key] forKey:key];
|
[self setValue:[target valueForKey:key] forKey:key];
|
||||||
}
|
}
|
||||||
|
|
||||||
[super mergeProperties:target mergeList:mergeList];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)resetProperties
|
- (void)resetProperties
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
CGPathAddArc(path, nil, cx, cy, r, 0, 2*M_PI, YES);
|
CGPathAddArc(path, nil, cx, cy, r, 0, 2*M_PI, YES);
|
||||||
return path;
|
return (CGPathRef)CFAutorelease(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
CGFloat rx = [convert stringToFloat:self.rx relative:width offset:0];
|
CGFloat rx = [convert stringToFloat:self.rx relative:width offset:0];
|
||||||
CGFloat ry = [convert stringToFloat:self.ry relative:height offset:0];
|
CGFloat ry = [convert stringToFloat:self.ry relative:height offset:0];
|
||||||
CGPathAddEllipseInRect(path, nil, CGRectMake(cx - rx, cy - ry, rx * 2, ry * 2));
|
CGPathAddEllipseInRect(path, nil, CGRectMake(cx - rx, cy - ry, rx * 2, ry * 2));
|
||||||
return path;
|
return (CGPathRef)CFAutorelease(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
CGPathMoveToPoint(path, nil, x1, y1);
|
CGPathMoveToPoint(path, nil, x1, y1);
|
||||||
CGPathAddLineToPoint(path, nil, x2, y2);
|
CGPathAddLineToPoint(path, nil, x2, y2);
|
||||||
|
|
||||||
return path;
|
return (CGPathRef)CFAutorelease(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -109,7 +109,7 @@
|
|||||||
CGPathAddRect(path, nil, CGRectMake(x, y, w, h));
|
CGPathAddRect(path, nil, CGRectMake(x, y, w, h));
|
||||||
}
|
}
|
||||||
|
|
||||||
return path;
|
return (CGPathRef)CFAutorelease(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -1,27 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This implements a very simple glyph cache.
|
|
||||||
// It maps from CTFontRef to CGGlyph to CGPathRef in order to reuse glyphs.
|
|
||||||
// It does NOT try to retain the keys that are used (CTFontRef or CGGlyph)
|
|
||||||
// but that is not an issue with respect to how it is used by this sample.
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import <CoreText/CoreText.h>
|
|
||||||
#import "RNSVGRenderable.h"
|
|
||||||
|
|
||||||
@interface RNSVGGlyphCache : NSObject
|
|
||||||
{
|
|
||||||
CFMutableDictionaryRef cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)init;
|
|
||||||
- (CGPathRef)pathForGlyph:(CGGlyph)glyph fromFont:(CTFontRef)font;
|
|
||||||
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
#import "UIBezierPath-Points.h"
|
#import "UIBezierPath-Points.h"
|
||||||
#import "RNSVGPath.h"
|
#import "RNSVGPath.h"
|
||||||
#import "RNSVGTextFrame.h"
|
#import "RNSVGTextFrame.h"
|
||||||
#import "RNSVGGlyphCache.h"
|
|
||||||
|
|
||||||
@interface RNSVGText : RNSVGPath
|
@interface RNSVGText : RNSVGPath
|
||||||
|
|
||||||
|
|||||||
+22
-14
@@ -32,7 +32,7 @@ static void RNSVGFreeTextFrame(RNSVGTextFrame frame)
|
|||||||
|
|
||||||
- (void)setTextFrame:(RNSVGTextFrame)frame
|
- (void)setTextFrame:(RNSVGTextFrame)frame
|
||||||
{
|
{
|
||||||
if (frame.lines != _textFrame.lines) {
|
if (frame.lines == _textFrame.lines) {
|
||||||
RNSVGFreeTextFrame(_textFrame);
|
RNSVGFreeTextFrame(_textFrame);
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
@@ -82,25 +82,25 @@ static void RNSVGFreeTextFrame(RNSVGTextFrame frame)
|
|||||||
// We should consider snapping this shift to device pixels to improve rendering quality
|
// We should consider snapping this shift to device pixels to improve rendering quality
|
||||||
// when a line has subpixel width.
|
// when a line has subpixel width.
|
||||||
CGAffineTransform offset = CGAffineTransformMakeTranslation(-shift, frame.baseLine + frame.lineHeight * i + (self.path ? -frame.lineHeight : 0));
|
CGAffineTransform offset = CGAffineTransformMakeTranslation(-shift, frame.baseLine + frame.lineHeight * i + (self.path ? -frame.lineHeight : 0));
|
||||||
CGPathAddPath(path, &offset, [self setLinePath:frame.lines[i]]);
|
|
||||||
|
CGMutablePathRef line = [self setLinePath:frame.lines[i]];
|
||||||
|
CGPathAddPath(path, &offset, line);
|
||||||
|
CGPathRelease(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
return path;
|
return (CGPathRef)CFAutorelease(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPathRef)setLinePath:(CTLineRef)line
|
- (CGMutablePathRef)setLinePath:(CTLineRef)line
|
||||||
{
|
{
|
||||||
|
|
||||||
CGAffineTransform upsideDown = CGAffineTransformMakeScale(1.0, -1.0);
|
CGAffineTransform upsideDown = CGAffineTransformMakeScale(1.0, -1.0);
|
||||||
CGMutablePathRef path = CGPathCreateMutable();
|
CGMutablePathRef path = CGPathCreateMutable();
|
||||||
RNSVGGlyphCache *cache = [[RNSVGGlyphCache alloc] init];
|
|
||||||
CTLineGetGlyphRuns(line);
|
CTLineGetGlyphRuns(line);
|
||||||
CFArrayRef glyphRuns = CTLineGetGlyphRuns(line);
|
CFArrayRef glyphRuns = CTLineGetGlyphRuns(line);
|
||||||
CFIndex runCount = CFArrayGetCount(glyphRuns);
|
CFIndex runCount = CFArrayGetCount(glyphRuns);
|
||||||
CFIndex glyphIndex = 0;
|
CFIndex glyphIndex = 0;
|
||||||
for(CFIndex i = 0; i < runCount; ++i)
|
|
||||||
{
|
for(CFIndex i = 0; i < runCount; ++i) {
|
||||||
|
|
||||||
// For each run, we need to get the glyphs, their font (to get the path) and their locations.
|
// For each run, we need to get the glyphs, their font (to get the path) and their locations.
|
||||||
CTRunRef run = CFArrayGetValueAtIndex(glyphRuns, i);
|
CTRunRef run = CFArrayGetValueAtIndex(glyphRuns, i);
|
||||||
CFIndex runGlyphCount = CTRunGetGlyphCount(run);
|
CFIndex runGlyphCount = CTRunGetGlyphCount(run);
|
||||||
@@ -112,9 +112,11 @@ static void RNSVGFreeTextFrame(RNSVGTextFrame frame)
|
|||||||
CTRunGetGlyphs(run, CFRangeMake(0, 0), glyphs);
|
CTRunGetGlyphs(run, CFRangeMake(0, 0), glyphs);
|
||||||
CFDictionaryRef attributes = CTRunGetAttributes(run);
|
CFDictionaryRef attributes = CTRunGetAttributes(run);
|
||||||
CTFontRef runFont = CFDictionaryGetValue(attributes, kCTFontAttributeName);
|
CTFontRef runFont = CFDictionaryGetValue(attributes, kCTFontAttributeName);
|
||||||
|
|
||||||
for(CFIndex j = 0; j < runGlyphCount; ++j, ++glyphIndex) {
|
for(CFIndex j = 0; j < runGlyphCount; ++j, ++glyphIndex) {
|
||||||
CGPathRef letter = [cache pathForGlyph:glyphs[j] fromFont:runFont];
|
CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyphs[j], nil);
|
||||||
CGPoint point = positions[j];
|
CGPoint point = positions[j];
|
||||||
|
|
||||||
if (letter) {
|
if (letter) {
|
||||||
CGAffineTransform transform;
|
CGAffineTransform transform;
|
||||||
|
|
||||||
@@ -122,23 +124,29 @@ static void RNSVGFreeTextFrame(RNSVGTextFrame frame)
|
|||||||
if (self.path) {
|
if (self.path) {
|
||||||
CGPoint slope;
|
CGPoint slope;
|
||||||
CGRect bounding = CGPathGetBoundingBox(letter);
|
CGRect bounding = CGPathGetBoundingBox(letter);
|
||||||
UIBezierPath* path = [UIBezierPath bezierPathWithCGPath:self.path];
|
UIBezierPath* pathAlong = [UIBezierPath bezierPathWithCGPath:self.path];
|
||||||
CGFloat percentConsumed = (point.x + bounding.size.width) / path.length;
|
CGFloat percentConsumed = (point.x + bounding.size.width) / pathAlong.length;
|
||||||
if (percentConsumed >= 1.0f) {
|
if (percentConsumed >= 1.0f) {
|
||||||
|
CGPathRelease(letter);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGPoint targetPoint = [path pointAtPercent:percentConsumed withSlope: &slope];
|
CGPoint targetPoint = [pathAlong pointAtPercent:percentConsumed withSlope: &slope];
|
||||||
float angle = atan(slope.y / slope.x); // + M_PI;
|
float angle = atan(slope.y / slope.x); // + M_PI;
|
||||||
if (slope.x < 0) angle += M_PI; // going left, update the angle
|
if (slope.x < 0) {
|
||||||
|
angle += M_PI; // going left, update the angle
|
||||||
|
}
|
||||||
transform = CGAffineTransformMakeTranslation(targetPoint.x - bounding.size.width, targetPoint.y);
|
transform = CGAffineTransformMakeTranslation(targetPoint.x - bounding.size.width, targetPoint.y);
|
||||||
transform = CGAffineTransformRotate(transform, angle);
|
transform = CGAffineTransformRotate(transform, angle);
|
||||||
transform = CGAffineTransformScale(transform, 1.0, -1.0);
|
transform = CGAffineTransformScale(transform, 1.0, -1.0);
|
||||||
} else {
|
} else {
|
||||||
transform = CGAffineTransformTranslate(upsideDown, point.x, point.y);
|
transform = CGAffineTransformTranslate(upsideDown, point.x, point.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
CGPathAddPath(path, &transform, letter);
|
CGPathAddPath(path, &transform, letter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CGPathRelease(letter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,63 +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 "RNSVGGlyphCache.h"
|
|
||||||
|
|
||||||
@implementation RNSVGGlyphCache
|
|
||||||
|
|
||||||
-(id)init
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
if(self)
|
|
||||||
{
|
|
||||||
cache = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)dealloc
|
|
||||||
{
|
|
||||||
CFRelease(cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
-(CGPathRef)pathForGlyph:(CGGlyph)glyph fromFont:(CTFontRef)font
|
|
||||||
{
|
|
||||||
// First we lookup the font to get to its glyph dictionary
|
|
||||||
CFMutableDictionaryRef glyphDict = (CFMutableDictionaryRef)CFDictionaryGetValue(cache, font);
|
|
||||||
if(!glyphDict)
|
|
||||||
{
|
|
||||||
// And if this font hasn't been seen before, we'll create and set the dictionary for it
|
|
||||||
glyphDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
|
|
||||||
CFDictionarySetValue(cache, font, glyphDict);
|
|
||||||
CFRelease(glyphDict);
|
|
||||||
}
|
|
||||||
// Next we try to get a path for the given glyph from the glyph dictionary
|
|
||||||
CGPathRef path = (CGPathRef)CFDictionaryGetValue(glyphDict, (const void *)(uintptr_t)glyph);
|
|
||||||
if(!path)
|
|
||||||
{
|
|
||||||
// If the path hasn't been seen before, then we'll create the path from the font & glyph and cache it.
|
|
||||||
path = CTFontCreatePathForGlyph(font, glyph, NULL);
|
|
||||||
if(!path)
|
|
||||||
{
|
|
||||||
// If a glyph does not have a path, then we need a placeholder to set in the dictionary
|
|
||||||
path = (CGPathRef)kCFNull;
|
|
||||||
}
|
|
||||||
CFDictionarySetValue(glyphDict, (const void *)(uintptr_t)glyph, path);
|
|
||||||
CFRelease(path);
|
|
||||||
}
|
|
||||||
if(path == (CGPathRef)kCFNull)
|
|
||||||
{
|
|
||||||
// If we got the placeholder, then set the path to NULL
|
|
||||||
// (this will happen either after discovering the glyph path is NULL,
|
|
||||||
// or after looking that up in the dictionary).
|
|
||||||
path = NULL;
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -76,7 +76,7 @@ void getPointsFromBezier(void *info, const CGPathElement *element)
|
|||||||
{
|
{
|
||||||
// Use total length to calculate the percent of path consumed at each control point
|
// Use total length to calculate the percent of path consumed at each control point
|
||||||
NSArray *points = self.points;
|
NSArray *points = self.points;
|
||||||
int pointCount = points.count;
|
NSUInteger pointCount = points.count;
|
||||||
|
|
||||||
float totalPointLength = self.length;
|
float totalPointLength = self.length;
|
||||||
float distanceTravelled = 0.0f;
|
float distanceTravelled = 0.0f;
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "RNSVGNodeManager.h"
|
#import "RNSVGRenderableManager.h"
|
||||||
|
|
||||||
@interface RNSVGGroupManager : RNSVGNodeManager
|
@interface RNSVGGroupManager : RNSVGRenderableManager
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ RCT_EXPORT_MODULE()
|
|||||||
return [RNSVGGroup new];
|
return [RNSVGGroup new];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(mergeList, NSArray<NSString *>)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(clipPath, CGPath)
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(clipRule, RNSVGCGFCRule)
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ RCT_EXPORT_VIEW_PROPERTY(name, NSString)
|
|||||||
RCT_EXPORT_VIEW_PROPERTY(opacity, CGFloat)
|
RCT_EXPORT_VIEW_PROPERTY(opacity, CGFloat)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(transform, CGAffineTransform)
|
RCT_EXPORT_VIEW_PROPERTY(transform, CGAffineTransform)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(clipPathRef, NSString)
|
RCT_EXPORT_VIEW_PROPERTY(clipPathRef, NSString)
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(clipPath, CGPath)
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(clipRule, RNSVGCGFCRule)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(responsible, BOOL)
|
RCT_EXPORT_VIEW_PROPERTY(responsible, BOOL)
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ RCT_EXPORT_VIEW_PROPERTY(strokeOpacity, CGFloat)
|
|||||||
RCT_EXPORT_VIEW_PROPERTY(strokeWidth, CGFloat)
|
RCT_EXPORT_VIEW_PROPERTY(strokeWidth, CGFloat)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(strokeLinecap, CGLineCap)
|
RCT_EXPORT_VIEW_PROPERTY(strokeLinecap, CGLineCap)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(strokeLinejoin, CGLineJoin)
|
RCT_EXPORT_VIEW_PROPERTY(strokeLinejoin, CGLineJoin)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(clipPath, CGPath)
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(clipRule, RNSVGCGFCRule)
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(strokeDasharray, RNSVGCGFloatArray)
|
RCT_EXPORT_VIEW_PROPERTY(strokeDasharray, RNSVGCGFloatArray)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(strokeDashoffset, CGFloat)
|
RCT_EXPORT_VIEW_PROPERTY(strokeDashoffset, CGFloat)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(strokeMiterlimit, CGFloat)
|
RCT_EXPORT_VIEW_PROPERTY(strokeMiterlimit, CGFloat)
|
||||||
|
|||||||
+6
-7
@@ -47,7 +47,11 @@ const NodeAttributes = {
|
|||||||
diff: arrayDiffer
|
diff: arrayDiffer
|
||||||
},
|
},
|
||||||
opacity: true,
|
opacity: true,
|
||||||
|
clipRule: true,
|
||||||
clipPathRef: true,
|
clipPathRef: true,
|
||||||
|
clipPath: {
|
||||||
|
diff: arrayDiffer
|
||||||
|
},
|
||||||
responsible: true
|
responsible: true
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,10 +68,6 @@ const RenderableOnlyAttributes = {
|
|||||||
strokeWidth: true,
|
strokeWidth: true,
|
||||||
strokeLinecap: true,
|
strokeLinecap: true,
|
||||||
strokeLinejoin: true,
|
strokeLinejoin: true,
|
||||||
clipPath: {
|
|
||||||
diff: arrayDiffer
|
|
||||||
},
|
|
||||||
clipRule: true,
|
|
||||||
strokeDasharray: {
|
strokeDasharray: {
|
||||||
diff: arrayDiffer
|
diff: arrayDiffer
|
||||||
},
|
},
|
||||||
@@ -78,10 +78,9 @@ const RenderableOnlyAttributes = {
|
|||||||
const RenderableAttributes = merge({}, NodeAttributes, RenderableOnlyAttributes);
|
const RenderableAttributes = merge({}, NodeAttributes, RenderableOnlyAttributes);
|
||||||
|
|
||||||
const GroupAttributes = merge({
|
const GroupAttributes = merge({
|
||||||
clipPath: {
|
mergeList: {
|
||||||
diff: arrayDiffer
|
diff: arrayDiffer
|
||||||
},
|
}
|
||||||
clipRule: true
|
|
||||||
}, NodeAttributes);
|
}, NodeAttributes);
|
||||||
|
|
||||||
const UseAttributes = merge({
|
const UseAttributes = merge({
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ import extractStroke from './extractStroke';
|
|||||||
import extractTransform from './extractTransform';
|
import extractTransform from './extractTransform';
|
||||||
import extractClipping from './extractClipping';
|
import extractClipping from './extractClipping';
|
||||||
import extractResponder from './extractResponder';
|
import extractResponder from './extractResponder';
|
||||||
|
import extractOpacity from './extractOpacity';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
export default function(props, options = {stroke: true, transform: true, fill: true, responder: true}) {
|
export default function(props, options = {stroke: true, transform: true, fill: true, responder: true}) {
|
||||||
let extractedProps = {
|
let extractedProps = {
|
||||||
opacity: +props.opacity || 1
|
opacity: extractOpacity(props.opacity)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (props.id) {
|
if (props.id) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import extractBrush from './extractBrush';
|
import extractBrush from './extractBrush';
|
||||||
import extractOpacity from './extractOpacity';
|
import extractOpacity from './extractOpacity';
|
||||||
|
import _ from 'lodash';
|
||||||
let separator = /\s*,\s*/;
|
let separator = /\s*,\s*/;
|
||||||
|
|
||||||
const caps = {
|
const caps = {
|
||||||
@@ -15,12 +16,19 @@ const joins = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function(props) {
|
export default function(props) {
|
||||||
let strokeWidth = +props.strokeWidth;
|
|
||||||
let {stroke} = props;
|
let {stroke} = props;
|
||||||
if (!strokeWidth && !stroke) {
|
if (!stroke) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let strokeWidth = +props.strokeWidth;
|
||||||
|
|
||||||
|
if (_.isNil(props.strokeWidth)) {
|
||||||
|
strokeWidth = 1;
|
||||||
|
} else if (!strokeWidth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let strokeDasharray = props.strokeDasharray;
|
let strokeDasharray = props.strokeDasharray;
|
||||||
|
|
||||||
if (typeof strokeDasharray === 'string') {
|
if (typeof strokeDasharray === 'string') {
|
||||||
@@ -42,7 +50,7 @@ export default function(props) {
|
|||||||
strokeLinecap: caps[props.strokeLinecap] || 0,
|
strokeLinecap: caps[props.strokeLinecap] || 0,
|
||||||
strokeLinejoin: joins[props.strokeLinejoin] || 0,
|
strokeLinejoin: joins[props.strokeLinejoin] || 0,
|
||||||
strokeDasharray: strokeDasharray || null,
|
strokeDasharray: strokeDasharray || null,
|
||||||
strokeWidth: strokeWidth || 1,
|
strokeWidth: strokeWidth,
|
||||||
strokeDashoffset: strokeDasharray ? (+props.strokeDashoffset || 0) : null,
|
strokeDashoffset: strokeDasharray ? (+props.strokeDashoffset || 0) : null,
|
||||||
strokeMiterlimit: props.strokeMiterlimit || 4
|
strokeMiterlimit: props.strokeMiterlimit || 4
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import {RenderableOnlyAttributes} from '../lib/attributes';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
export default function (extractedProps, originProps) {
|
||||||
|
let reusableProps = [];
|
||||||
|
Object.keys(RenderableOnlyAttributes).forEach(name => {
|
||||||
|
if (!_.isNil(originProps[name])) {
|
||||||
|
// clipPath prop may provide `clipPathRef` as native prop
|
||||||
|
if (name === 'clipPath') {
|
||||||
|
if (extractedProps[name]) {
|
||||||
|
reusableProps.push(name);
|
||||||
|
} else if (extractedProps.clipPathRef) {
|
||||||
|
reusableProps.push('clipPathRef');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reusableProps.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return reusableProps;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user