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