Skip to content
This repository has been archived by the owner on Mar 21, 2022. It is now read-only.

Commit

Permalink
feat: implement getBBox, getCTM, getScreenCTM
Browse files Browse the repository at this point in the history
make callback last argument, unless options and optional
  • Loading branch information
msand committed Oct 4, 2019
1 parent cd667d0 commit f13d54a
Show file tree
Hide file tree
Showing 14 changed files with 244 additions and 59 deletions.
4 changes: 3 additions & 1 deletion android/src/main/java/com/horcrux/svg/GroupView.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,9 @@ int hitTest(final float[] src) {
if (clipPath != null) {
if (mClipRegionPath != clipPath) {
mClipRegionPath = clipPath;
mClipRegion = getRegion(clipPath);
mClipBounds = new RectF();
clipPath.computeBounds(mClipBounds, true);
mClipRegion = getRegion(clipPath, mClipBounds);
}
if (!mClipRegion.contains(x, y)) {
return -1;
Expand Down
1 change: 0 additions & 1 deletion android/src/main/java/com/horcrux/svg/ImageView.java
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@ private void doRender(Canvas canvas, Paint paint, Bitmap bitmap, float opacity)
Paint alphaPaint = new Paint();
alphaPaint.setAlpha((int) (opacity * 255));
canvas.drawBitmap(bitmap, null, vbRect, alphaPaint);
//noinspection deprecation
mCTM.mapRect(vbRect);
this.setClientRect(vbRect);
}
Expand Down
67 changes: 63 additions & 4 deletions android/src/main/java/com/horcrux/svg/RNSVGRenderableManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@

package com.horcrux.svg;

import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;

import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
Expand Down Expand Up @@ -69,9 +72,9 @@ public void run() {
@SuppressWarnings("unused")
@ReactMethod
public void isPointInFill(int tag, ReadableMap options, Callback successCallback) {
float x = (float)options.getDouble("x");
float y = (float)options.getDouble("y");
float[] src = new float[] { x, y };
float x = (float) options.getDouble("x");
float y = (float) options.getDouble("y");
float[] src = new float[]{x, y};
isPointInFill(tag, src, successCallback, 0);
}

Expand All @@ -86,7 +89,7 @@ public void getTotalLength(int tag, Callback successCallback) {
@SuppressWarnings("unused")
@ReactMethod
public void getPointAtLength(int tag, ReadableMap options, Callback successCallback) {
float length = (float)options.getDouble("length");
float length = (float) options.getDouble("length");
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
PathMeasure pm = new PathMeasure(svg.getPath(null, null), false);
float pathLength = pm.getLength();
Expand All @@ -95,4 +98,60 @@ public void getPointAtLength(int tag, ReadableMap options, Callback successCallb
pm.getPosTan(Math.max(0, Math.min(length, pathLength)), pos, tan);
successCallback.invoke(pos[0], pos[1]);
}

@SuppressWarnings("unused")
@ReactMethod
public void getBBox(int tag, ReadableMap options, Callback successCallback) {
boolean fill = options.getBoolean("fill");
boolean stroke = options.getBoolean("stroke");
boolean markers = options.getBoolean("markers");
boolean clipped = options.getBoolean("clipped");
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
Path path = svg.getPath(null, null);
svg.initBounds();
RectF bounds = new RectF();
if (fill) {
bounds.union(svg.mFillBounds);
}
if (stroke) {
bounds.union(svg.mStrokeBounds);
}
if (markers) {
bounds.union(svg.mMarkerBounds);
}
if (clipped) {
bounds.intersect(svg.mClipBounds);
}
successCallback.invoke(bounds.left, bounds.top, bounds.width(), bounds.height());
}

@SuppressWarnings("unused")
@ReactMethod
public void getCTM(int tag, Callback successCallback) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
Matrix screenCTM = svg.mCTM;
Matrix invViewBox = svg.getSvgView().mInvViewBoxMatrix;
Matrix ctm = new Matrix(screenCTM);
ctm.preConcat(invViewBox);

float[] values = new float[9];
ctm.getValues(values);
successCallback.invoke(
values[Matrix.MSCALE_X], values[Matrix.MSKEW_X], values[Matrix.MTRANS_X],
values[Matrix.MSKEW_Y], values[Matrix.MSCALE_Y], values[Matrix.MTRANS_Y]
);
}

@SuppressWarnings("unused")
@ReactMethod
public void getScreenCTM(int tag, Callback successCallback) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
Matrix screenCTM = svg.mCTM;
float[] values = new float[9];
screenCTM.getValues(values);
successCallback.invoke(
values[Matrix.MSCALE_X], values[Matrix.MSKEW_X], values[Matrix.MTRANS_X],
values[Matrix.MSKEW_Y], values[Matrix.MSCALE_Y], values[Matrix.MTRANS_Y]
);
}
}
53 changes: 34 additions & 19 deletions android/src/main/java/com/horcrux/svg/RenderableView.java
Original file line number Diff line number Diff line change
Expand Up @@ -523,18 +523,8 @@ int hitTest(final float[] src) {
int x = Math.round(dst[0]);
int y = Math.round(dst[1]);

if (mRegion == null && mFillPath != null) {
mRegion = getRegion(mFillPath);
}
if (mRegion == null && mPath != null) {
mRegion = getRegion(mPath);
}
if (mStrokeRegion == null && mStrokePath != null) {
mStrokeRegion = getRegion(mStrokePath);
}
if (mMarkerRegion == null && mMarkerPath != null) {
mMarkerRegion = getRegion(mMarkerPath);
}
initBounds();

if (
(mRegion == null || !mRegion.contains(x, y)) &&
(mStrokeRegion == null || !mStrokeRegion.contains(x, y) &&
Expand All @@ -545,10 +535,6 @@ int hitTest(final float[] src) {

Path clipPath = getClipPath();
if (clipPath != null) {
if (mClipRegionPath != clipPath) {
mClipRegionPath = clipPath;
mClipRegion = getRegion(clipPath);
}
if (!mClipRegion.contains(x, y)) {
return -1;
}
Expand All @@ -557,10 +543,39 @@ int hitTest(final float[] src) {
return getId();
}

Region getRegion(Path path) {
RectF rectF = new RectF();
path.computeBounds(rectF, true);
void initBounds() {
if (mRegion == null && mFillPath != null) {
mFillBounds = new RectF();
mFillPath.computeBounds(mFillBounds, true);
mRegion = getRegion(mFillPath, mFillBounds);
}
if (mRegion == null && mPath != null) {
mFillBounds = new RectF();
mPath.computeBounds(mFillBounds, true);
mRegion = getRegion(mPath, mFillBounds);
}
if (mStrokeRegion == null && mStrokePath != null) {
mStrokeBounds = new RectF();
mStrokePath.computeBounds(mStrokeBounds, true);
mStrokeRegion = getRegion(mStrokePath, mStrokeBounds);
}
if (mMarkerRegion == null && mMarkerPath != null) {
mMarkerBounds = new RectF();
mMarkerPath.computeBounds(mMarkerBounds, true);
mMarkerRegion = getRegion(mMarkerPath, mMarkerBounds);
}
Path clipPath = getClipPath();
if (clipPath != null) {
if (mClipRegionPath != clipPath) {
mClipRegionPath = clipPath;
mClipBounds = new RectF();
clipPath.computeBounds(mClipBounds, true);
mClipRegion = getRegion(clipPath, mClipBounds);
}
}
}

Region getRegion(Path path, RectF rectF) {
Region region = new Region();
region.setPath(path,
new Region(
Expand Down
2 changes: 1 addition & 1 deletion android/src/main/java/com/horcrux/svg/SvgView.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public int reactTagForTouch(float touchX, float touchY) {
private SVGLength mbbHeight;
private String mAlign;
private int mMeetOrSlice;
private final Matrix mInvViewBoxMatrix = new Matrix();
final Matrix mInvViewBoxMatrix = new Matrix();
private boolean mInvertible = true;
private boolean mRendered = false;
int mTintColor = 0;
Expand Down
15 changes: 2 additions & 13 deletions android/src/main/java/com/horcrux/svg/TSpanView.java
Original file line number Diff line number Diff line change
Expand Up @@ -1158,15 +1158,8 @@ int hitTest(final float[] src) {
int x = Math.round(dst[0]);
int y = Math.round(dst[1]);

if (mRegion == null && mFillPath != null) {
mRegion = getRegion(mFillPath);
}
if (mRegion == null && mPath != null) {
mRegion = getRegion(mPath);
}
if (mStrokeRegion == null && mStrokePath != null) {
mStrokeRegion = getRegion(mStrokePath);
}
initBounds();

if (
(mRegion == null || !mRegion.contains(x, y)) &&
(mStrokeRegion == null || !mStrokeRegion.contains(x, y))
Expand All @@ -1176,10 +1169,6 @@ int hitTest(final float[] src) {

Path clipPath = getClipPath();
if (clipPath != null) {
if (mClipRegionPath != clipPath) {
mClipRegionPath = clipPath;
mClipRegion = getRegion(clipPath);
}
if (!mClipRegion.contains(x, y)) {
return -1;
}
Expand Down
4 changes: 4 additions & 0 deletions android/src/main/java/com/horcrux/svg/VirtualView.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ abstract public class VirtualView extends ReactViewGroup {
Path mStrokePath;
Path mMarkerPath;
RectF mBox;
RectF mFillBounds;
RectF mStrokeBounds;
RectF mMarkerBounds;
RectF mClipBounds;
Region mRegion;
Region mMarkerRegion;
Region mStrokeRegion;
Expand Down
14 changes: 10 additions & 4 deletions ios/Elements/RNSVGGroup.m
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,16 @@ - (void)renderGroupTo:(CGContextRef)context rect:(CGRect)rect
[self setHitArea:path];
if (!CGRectEqualToRect(bounds, CGRectNull)) {
self.clientRect = bounds;
const CGRect fillBounds = CGPathGetBoundingBox(path);
const CGRect strokeBounds = CGPathGetBoundingBox(self.strokePath);
self.pathBounds = CGRectUnion(fillBounds, strokeBounds);

self.fillBounds = CGPathGetBoundingBox(path);
self.strokeBounds = CGPathGetBoundingBox(self.strokePath);
self.pathBounds = CGRectUnion(self.fillBounds, self.strokeBounds);

CGAffineTransform current = CGContextGetCTM(context);
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);

self.ctm = svgToClientTransform;
self.screenCTM = current;

CGAffineTransform transform = CGAffineTransformConcat(self.matrix, self.transforms);
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
CGPoint center = CGPointApplyAffineTransform(mid, transform);
Expand Down
9 changes: 9 additions & 0 deletions ios/Elements/RNSVGImage.m
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
[self setHitArea:hitAreaPath];
CGPathRelease(hitAreaPath);
self.pathBounds = hitArea;
self.fillBounds = hitArea;
self.strokeBounds = hitArea;

// apply viewBox transform on Image render.
CGRect imageBounds = CGRectMake(0, 0, _imageSize.width, _imageSize.height);
Expand All @@ -136,6 +138,13 @@ - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect

CGRect bounds = hitArea;
self.clientRect = bounds;

CGAffineTransform current = CGContextGetCTM(context);
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);

self.ctm = svgToClientTransform;
self.screenCTM = current;

CGAffineTransform transform = CGAffineTransformConcat(self.matrix, self.transforms);
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
CGPoint center = CGPointApplyAffineTransform(mid, transform);
Expand Down
7 changes: 7 additions & 0 deletions ios/Elements/RNSVGUse.m
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
}
CGRect bounds = template.clientRect;
self.clientRect = bounds;

CGAffineTransform current = CGContextGetCTM(context);
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);

self.ctm = svgToClientTransform;
self.screenCTM = current;

CGAffineTransform transform = CGAffineTransformConcat(self.matrix, self.transforms);
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
CGPoint center = CGPointApplyAffineTransform(mid, transform);
Expand Down
4 changes: 4 additions & 0 deletions ios/RNSVGNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
@property (nonatomic, strong) NSString *markerMid;
@property (nonatomic, strong) NSString *markerEnd;
@property (nonatomic, assign) BOOL responsible;
@property (nonatomic, assign) CGAffineTransform ctm;
@property (nonatomic, assign) CGAffineTransform screenCTM;
@property (nonatomic, assign) CGAffineTransform matrix;
@property (nonatomic, assign) CGAffineTransform transforms;
@property (nonatomic, assign) CGAffineTransform invmatrix;
Expand All @@ -48,6 +50,8 @@ extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
@property (nonatomic, assign) CGPathRef markerPath;
@property (nonatomic, assign) CGRect clientRect;
@property (nonatomic, assign) CGRect pathBounds;
@property (nonatomic, assign) CGRect fillBounds;
@property (nonatomic, assign) CGRect strokeBounds;
@property (nonatomic, assign) CGRect markerBounds;
@property (nonatomic, copy) RCTDirectEventBlock onLayout;

Expand Down
8 changes: 5 additions & 3 deletions ios/RNSVGRenderable.m
Original file line number Diff line number Diff line change
Expand Up @@ -356,17 +356,19 @@ - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
self.path = CGPathRetain(path);
}
[self setHitArea:path];
const CGRect fillBounds = CGPathGetBoundingBox(path);
const CGRect strokeBounds = CGPathGetBoundingBox(self.strokePath);
self.pathBounds = CGRectUnion(fillBounds, strokeBounds);
self.fillBounds = CGPathGetBoundingBox(path);
self.strokeBounds = CGPathGetBoundingBox(self.strokePath);
self.pathBounds = CGRectUnion(self.fillBounds, self.strokeBounds);
}
const CGRect pathBounds = self.pathBounds;

CGAffineTransform current = CGContextGetCTM(context);
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);
CGRect clientRect = CGRectApplyAffineTransform(pathBounds, svgToClientTransform);

self.ctm = svgToClientTransform;
self.clientRect = clientRect;
self.screenCTM = current;

if (_vectorEffect == kRNSVGVectorEffectNonScalingStroke) {
path = CGPathCreateCopyByTransformingPath(path, &svgToClientTransform);
Expand Down
Loading

0 comments on commit f13d54a

Please sign in to comment.