GT2/GT2-iOS/node_modules/react-native-svg/ios/RNSVGRenderable.m

348 lines
8.6 KiB
Objective-C

/**
* 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 "RNSVGRenderable.h"
@implementation RNSVGRenderable
{
NSMutableDictionary *_originProperties;
NSArray<NSString *> *_lastMergedList;
NSArray<NSString *> *_attributeList;
CGPathRef _hitArea;
}
- (id)init
{
if (self = [super init]) {
_fillOpacity = 1;
_strokeOpacity = 1;
_strokeWidth = 1;
_fillRule = kRNSVGCGFCRuleNonzero;
}
return self;
}
- (void)setFill:(RNSVGBrush *)fill
{
if (fill == _fill) {
return;
}
[self invalidate];
_fill = fill;
}
- (void)setFillOpacity:(CGFloat)fillOpacity
{
if (fillOpacity == _fillOpacity) {
return;
}
[self invalidate];
_fillOpacity = fillOpacity;
}
- (void)setFillRule:(RNSVGCGFCRule)fillRule
{
if (fillRule == _fillRule) {
return;
}
[self invalidate];
_fillRule = fillRule;
}
- (void)setStroke:(RNSVGBrush *)stroke
{
if (stroke == _stroke) {
return;
}
[self invalidate];
_stroke = stroke;
}
- (void)setStrokeOpacity:(CGFloat)strokeOpacity
{
if (strokeOpacity == _strokeOpacity) {
return;
}
[self invalidate];
_strokeOpacity = strokeOpacity;
}
- (void)setStrokeWidth:(CGFloat)strokeWidth
{
if (strokeWidth == _strokeWidth) {
return;
}
[self invalidate];
_strokeWidth = strokeWidth;
}
- (void)setStrokeLinecap:(CGLineCap)strokeLinecap
{
if (strokeLinecap == _strokeLinecap) {
return;
}
[self invalidate];
_strokeLinecap = strokeLinecap;
}
- (void)setStrokeJoin:(CGLineJoin)strokeLinejoin
{
if (strokeLinejoin == _strokeLinejoin) {
return;
}
[self invalidate];
_strokeLinejoin = strokeLinejoin;
}
- (void)setStrokeMiterlimit:(CGFloat)strokeMiterlimit
{
if (strokeMiterlimit == _strokeMiterlimit) {
return;
}
[self invalidate];
_strokeMiterlimit = strokeMiterlimit;
}
- (void)setStrokeDasharray:(RNSVGCGFloatArray)strokeDasharray
{
if (strokeDasharray.array == _strokeDasharray.array) {
return;
}
if (_strokeDasharray.array) {
free(_strokeDasharray.array);
}
[self invalidate];
_strokeDasharray = strokeDasharray;
}
- (void)setStrokeDashoffset:(CGFloat)strokeDashoffset
{
if (strokeDashoffset == _strokeDashoffset) {
return;
}
[self invalidate];
_strokeDashoffset = strokeDashoffset;
}
- (void)setPropList:(NSArray<NSString *> *)propList
{
if (propList == _propList) {
return;
}
_propList = _attributeList = propList;
[self invalidate];
}
- (void)dealloc
{
CGPathRelease(_hitArea);
if (_strokeDasharray.array) {
free(_strokeDasharray.array);
}
}
- (void)renderTo:(CGContextRef)context
{
// This needs to be painted on a layer before being composited.
CGContextSaveGState(context);
CGContextConcatCTM(context, self.matrix);
CGContextSetAlpha(context, self.opacity);
[self beginTransparencyLayer:context];
[self renderLayerTo:context];
[self endTransparencyLayer:context];
CGContextRestoreGState(context);
}
- (void)renderLayerTo:(CGContextRef)context
{
if (!self.fill && !self.stroke) {
return;
}
CGPathRef path = [self getPath:context];
[self setHitArea:path];
if (self.opacity == 0) {
return;
}
CGPathDrawingMode mode = kCGPathStroke;
BOOL fillColor = NO;
[self clip:context];
BOOL evenodd = self.fillRule == kRNSVGCGFCRuleEvenodd;
if (self.fill) {
fillColor = [self.fill applyFillColor:context opacity:self.fillOpacity];
if (fillColor) {
mode = evenodd ? kCGPathEOFill : kCGPathFill;
} else {
CGContextSaveGState(context);
CGContextAddPath(context, path);
CGContextClip(context);
[self.fill paint:context
opacity:self.fillOpacity
painter:[[self getSvgView] getDefinedPainter:self.fill.brushRef]
];
CGContextRestoreGState(context);
if (!self.stroke) {
return;
}
}
}
if (self.stroke) {
CGContextSetLineWidth(context, self.strokeWidth);
CGContextSetLineCap(context, self.strokeLinecap);
CGContextSetLineJoin(context, self.strokeLinejoin);
RNSVGCGFloatArray dash = self.strokeDasharray;
if (dash.count) {
CGContextSetLineDash(context, self.strokeDashoffset, dash.array, dash.count);
}
if (!fillColor) {
CGContextAddPath(context, path);
CGContextReplacePathWithStrokedPath(context);
CGContextClip(context);
}
BOOL strokeColor = [self.stroke applyStrokeColor:context opacity:self.strokeOpacity];
if (strokeColor && fillColor) {
mode = evenodd ? kCGPathEOFillStroke : kCGPathFillStroke;
} else if (!strokeColor) {
// draw fill
if (fillColor) {
CGContextAddPath(context, path);
CGContextDrawPath(context, mode);
}
// draw stroke
CGContextAddPath(context, path);
CGContextReplacePathWithStrokedPath(context);
CGContextClip(context);
[self.stroke paint:context
opacity:self.strokeOpacity
painter:[[self getSvgView] getDefinedPainter:self.stroke.brushRef]
];
return;
}
}
CGContextAddPath(context, path);
CGContextDrawPath(context, mode);
}
- (void)setHitArea:(CGPathRef)path
{
CGPathRelease(_hitArea);
if ([self getSvgView].responsible) {
// Add path to hitArea
CGMutablePathRef hitArea = CGPathCreateMutableCopy(path);
if (self.stroke && self.strokeWidth) {
// Add stroke to hitArea
CGPathRef strokePath = CGPathCreateCopyByStrokingPath(hitArea, nil, self.strokeWidth, self.strokeLinecap, self.strokeLinejoin, self.strokeMiterlimit);
CGPathAddPath(hitArea, nil, strokePath);
CGPathRelease(strokePath);
}
_hitArea = CGPathRetain(CFAutorelease(CGPathCreateCopy(hitArea)));
CGPathRelease(hitArea);
}
}
// hitTest delagate
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
return [self hitTest:point withEvent:event withTransform:CGAffineTransformIdentity];
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event withTransform:(CGAffineTransform)transform
{
if (!_hitArea) {
return nil;
}
if (self.active) {
if (!event) {
self.active = NO;
}
return self;
}
CGAffineTransform matrix = CGAffineTransformConcat(self.matrix, transform);
CGPathRef hitArea = CGPathCreateCopyByTransformingPath(_hitArea, &matrix);
BOOL contains = CGPathContainsPoint(hitArea, nil, point, NO);
CGPathRelease(hitArea);
if (contains) {
CGPathRef clipPath = [self getClipPath];
if (!clipPath) {
return self;
} else {
CGPathRef transformedClipPath = CGPathCreateCopyByTransformingPath(clipPath, &matrix);
BOOL result = CGPathContainsPoint(transformedClipPath, nil, point, self.clipRule == kRNSVGCGFCRuleEvenodd);
CGPathRelease(transformedClipPath);
return result ? self : nil;
}
} else {
return nil;
}
}
- (NSArray<NSString *> *)getAttributeList
{
return _attributeList;
}
- (void)mergeProperties:(__kindof RNSVGRenderable *)target
{
NSArray<NSString *> *targetAttributeList = [target getAttributeList];
if (targetAttributeList.count == 0) {
return;
}
NSMutableArray* attributeList = [self.propList mutableCopy];
_originProperties = [[NSMutableDictionary alloc] init];
for (NSString *key in targetAttributeList) {
[_originProperties setValue:[self valueForKey:key] forKey:key];
if (![attributeList containsObject:key]) {
[attributeList addObject:key];
[self setValue:[target valueForKey:key] forKey:key];
}
}
_lastMergedList = targetAttributeList;
_attributeList = [attributeList copy];
}
- (void)resetProperties
{
for (NSString *key in _lastMergedList) {
[self setValue:[_originProperties valueForKey:key] forKey:key];
}
_lastMergedList = nil;
_attributeList = _propList;
}
@end