[iOS] Attempt to fix text-anchor subtree advance/extent calculation

Related to
https://github.com/react-native-community/react-native-svg/issues/600
https://github.com/react-native-community/react-native-svg/issues/570
This commit is contained in:
Mikael Sand
2019-02-09 22:05:47 +02:00
parent 8e888ac1fc
commit 04fc2cdce5
3 changed files with 104 additions and 2 deletions
+61 -2
View File
@@ -100,6 +100,65 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI;
return path;
}
- (CGFloat)getSubtreeTextChunksTotalAdvance
{
CGFloat advance = 0;
NSString *str = self.content;
if (!str) {
for (UIView *node in self.subviews) {
if ([node isKindOfClass:[RNSVGText class]]) {
RNSVGText *text = (RNSVGText*)node;
advance += [text getSubtreeTextChunksTotalAdvance];
}
}
return advance;
}
// Create a dictionary for this font
CTFontRef fontRef = [self getFontFromContext];
RNSVGGlyphContext* gc = [self.textRoot getGlyphContext];
RNSVGFontData* font = [gc getFont];
CGFloat letterSpacing = font->letterSpacing;
bool autoKerning = !font->manualKerning;
bool allowOptionalLigatures = letterSpacing == 0 && font->fontVariantLigatures == RNSVGFontVariantLigaturesNormal;
NSMutableDictionary *attrs = [[NSMutableDictionary alloc] init];
NSNumber *lig = [NSNumber numberWithInt:allowOptionalLigatures ? 2 : 1];
attrs[NSLigatureAttributeName] = lig;
CFDictionaryRef attributes;
if (fontRef != nil) {
attrs[NSFontAttributeName] = (__bridge id)fontRef;
}
if (!autoKerning) {
NSNumber *noAutoKern = [NSNumber numberWithFloat:0.0f];
#if DTCORETEXT_SUPPORT_NS_ATTRIBUTES
if (___useiOS6Attributes)
{
[attrs setObject:noAutoKern forKey:NSKernAttributeName];
}
else
#endif
{
[attrs setObject:noAutoKern forKey:(id)kCTKernAttributeName];
}
}
attributes = (__bridge CFDictionaryRef)attrs;
CFStringRef string = (__bridge CFStringRef)str;
CFAttributedStringRef attrString = CFAttributedStringCreate(kCFAllocatorDefault, string, attributes);
CTLineRef line = CTLineCreateWithAttributedString(attrString);
CGRect textBounds = CTLineGetBoundsWithOptions(line, 0);
CGFloat textMeasure = CGRectGetWidth(textBounds);
return textMeasure;
}
- (CGPathRef)getLinePath:(NSString *)str context:(CGContextRef)context
{
// Create a dictionary for this font
@@ -292,8 +351,8 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI;
attributes, such as a dx attribute value on a tspan element.
*/
enum RNSVGTextAnchor textAnchor = font->textAnchor;
CGRect textBounds = CTLineGetBoundsWithOptions(line, 0);
CGFloat textMeasure = CGRectGetWidth(textBounds);
RNSVGText *anchorRoot = [self getTextAnchorRoot];
CGFloat textMeasure = [anchorRoot getSubtreeTextChunksTotalAdvance];
CGFloat offset = [RNSVGTSpan getTextAnchorOffset:textAnchor width:textMeasure];
bool hasTextPath = textPath != nil;
+2
View File
@@ -23,5 +23,7 @@
- (CGPathRef)getGroupPath:(CGContextRef)context;
- (CTFontRef)getFontFromContext;
- (CGFloat)getSubtreeTextChunksTotalAdvance;
- (RNSVGText*)getTextAnchorRoot;
@end
+41
View File
@@ -18,6 +18,7 @@
RNSVGGlyphContext *_glyphContext;
NSString *_alignmentBaseline;
NSString *_baselineShift;
CGFloat cachedAdvance;
}
- (void)invalidate
@@ -25,6 +26,7 @@
if (self.dirty || self.merging) {
return;
}
cachedAdvance = NAN;
[super invalidate];
[self clearChildCache];
}
@@ -248,4 +250,43 @@
return [[self.textRoot getGlyphContext] getGlyphFont];
}
- (RNSVGText*)getTextAnchorRoot
{
RNSVGGlyphContext* gc = [self.textRoot getGlyphContext];
RNSVGFontData* font = [gc getFont];
enum RNSVGTextAnchor textAnchor = font->textAnchor;
if (textAnchor == RNSVGTextAnchorStart) {
return self;
}
UIView* parent = [self superview];
if ([parent isKindOfClass:[RNSVGText class]]) {
RNSVGText *parentText = (RNSVGText*)parent;
RNSVGGlyphContext* gc = [parentText.textRoot getGlyphContext];
RNSVGFontData* font = [gc getFont];
enum RNSVGTextAnchor textAnchor = font->textAnchor;
if (textAnchor == RNSVGTextAnchorStart) {
return self;
} else {
return [parentText getTextAnchorRoot];
}
}
return self;
}
- (CGFloat)getSubtreeTextChunksTotalAdvance
{
if (!isnan(cachedAdvance)) {
return cachedAdvance;
}
CGFloat advance = 0;
for (UIView *node in self.subviews) {
if ([node isKindOfClass:[RNSVGText class]]) {
RNSVGText *text = (RNSVGText*)node;
advance += [text getSubtreeTextChunksTotalAdvance];
}
}
cachedAdvance = advance;
return advance;
}
@end