mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-05 07:59:28 +00:00
[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:
+61
-2
@@ -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;
|
||||
|
||||
@@ -23,5 +23,7 @@
|
||||
|
||||
- (CGPathRef)getGroupPath:(CGContextRef)context;
|
||||
- (CTFontRef)getFontFromContext;
|
||||
- (CGFloat)getSubtreeTextChunksTotalAdvance;
|
||||
- (RNSVGText*)getTextAnchorRoot;
|
||||
|
||||
@end
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user