From abb17bc7f0985c0b5eaa85ead7351e5c74a731f8 Mon Sep 17 00:00:00 2001 From: Mikael Sand Date: Fri, 8 Feb 2019 03:19:21 +0200 Subject: [PATCH] Fix re-rendering of emoji when path data is cached, closes #927 --- .../main/java/com/horcrux/svg/TSpanView.java | 33 +++++++++++++++---- ios/Text/RNSVGTSpan.m | 26 +++++++++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/android/src/main/java/com/horcrux/svg/TSpanView.java b/android/src/main/java/com/horcrux/svg/TSpanView.java index 04c95760..32248517 100644 --- a/android/src/main/java/com/horcrux/svg/TSpanView.java +++ b/android/src/main/java/com/horcrux/svg/TSpanView.java @@ -28,6 +28,8 @@ import com.facebook.react.bridge.ReadableMap; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.views.text.ReactFontManager; +import java.util.ArrayList; + import javax.annotation.Nullable; import static android.graphics.Matrix.MTRANS_X; @@ -47,6 +49,8 @@ class TSpanView extends TextView { @Nullable String mContent; private TextPathView textPath; + ArrayList emoji = new ArrayList<>(); + ArrayList emojiTransforms = new ArrayList<>(); public TSpanView(ReactContext reactContext) { super(reactContext); @@ -61,6 +65,20 @@ class TSpanView extends TextView { @Override void draw(Canvas canvas, Paint paint, float opacity) { if (mContent != null) { + int numEmoji = emoji.size(); + if (numEmoji > 0) { + GlyphContext gc = getTextRootGlyphContext(); + FontData font = gc.getFont(); + applyTextPropertiesToPaint(paint, font); + for (int i = 0; i < numEmoji; i++) { + String current = emoji.get(i); + Matrix mid = emojiTransforms.get(i); + canvas.save(); + canvas.concat(mid); + canvas.drawText(current, 0, 0, paint); + canvas.restore(); + } + } drawPath(canvas, paint, opacity); } else { clip(canvas, paint); @@ -676,6 +694,9 @@ class TSpanView extends TextView { final float[] midPointMatrixData = new float[9]; final float[] endPointMatrixData = new float[9]; + emoji.clear(); + emojiTransforms.clear(); + for (int index = 0; index < length; index++) { char currentChar = chars[index]; String current = String.valueOf(currentChar); @@ -855,12 +876,12 @@ class TSpanView extends TextView { glyph.computeBounds(bounds, true); float width = bounds.width(); if (width == 0) { // Render unicode emoji - mid.getValues(midPointMatrixData); - double midX = midPointMatrixData[MTRANS_X]; - double midY = midPointMatrixData[MTRANS_Y]; - canvas.rotate((float) r, (float)midX, (float)midY); - canvas.drawText(current, (float)midX, (float)midY, paint); - canvas.rotate((float) -r, (float)midX, (float)midY); + canvas.save(); + canvas.concat(mid); + emoji.add(current); + emojiTransforms.add(new Matrix(mid)); + canvas.drawText(current, 0, 0, paint); + canvas.restore(); } else { glyph.transform(mid); path.addPath(glyph); diff --git a/ios/Text/RNSVGTSpan.m b/ios/Text/RNSVGTSpan.m index c9171aae..70b11adc 100644 --- a/ios/Text/RNSVGTSpan.m +++ b/ios/Text/RNSVGTSpan.m @@ -23,6 +23,8 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI; NSArray *lines; NSUInteger lineCount; BOOL isClosed; + NSMutableArray *emoji; + NSMutableArray *emojiTransform; } - (id)init @@ -33,6 +35,9 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI; RNSVGTSpan_separators = [NSCharacterSet whitespaceCharacterSet]; } + emoji = [NSMutableArray arrayWithCapacity:0]; + emojiTransform = [NSMutableArray arrayWithCapacity:0]; + return self; } @@ -48,6 +53,21 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI; - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect { if (self.content) { + if (self.path) { + NSUInteger count = [emoji count]; + RNSVGGlyphContext* gc = [self.textRoot getGlyphContext]; + CGFloat fontSize = [gc getFontSize]; + for (NSUInteger i = 0; i < count; i++) { + UILabel *label = [emoji objectAtIndex:i]; + NSValue *transformValue = [emojiTransform objectAtIndex:i]; + CGAffineTransform transform = [transformValue CGAffineTransformValue]; + CGContextConcatCTM(context, transform); + CGContextTranslateCTM(context, 0, -fontSize); + [label.layer renderInContext:context]; + CGContextTranslateCTM(context, 0, fontSize); + CGContextConcatCTM(context, CGAffineTransformInvert(transform)); + } + } [self renderPathTo:context rect:rect]; } else { [self clip:context]; @@ -658,6 +678,9 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI; } } + [emoji removeAllObjects]; + [emojiTransform removeAllObjects]; + CFArrayRef runs = CTLineGetGlyphRuns(line); CFIndex runEnd = CFArrayGetCount(runs); for (CFIndex r = 0; r < runEnd; r++) { @@ -829,6 +852,9 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI; [label.layer renderInContext:context]; CGContextTranslateCTM(context, 0, fontSize); CGContextConcatCTM(context, CGAffineTransformInvert(transform)); + + [emoji addObject:label]; + [emojiTransform addObject:[NSValue valueWithCGAffineTransform:transform]]; } else { transform = CGAffineTransformScale(transform, 1.0, -1.0); CGPathAddPath(path, &transform, glyphPath);