mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-21 06:15:15 +00:00
175 lines
6.9 KiB
Objective-C
175 lines
6.9 KiB
Objective-C
/*
|
|
|
|
Erica Sadun, http://ericasadun.com
|
|
|
|
*/
|
|
|
|
#import "Drawing-Text.h"
|
|
#import "Utility.h"
|
|
|
|
#pragma mark - Drawing
|
|
|
|
void DrawStringInRect(NSString *string, CGRect rect, UIFont *font, NSTextAlignment alignment, UIColor *color)
|
|
{
|
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
if (context == NULL) return;
|
|
|
|
NSRange range = NSMakeRange(0, string.length);
|
|
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string];
|
|
|
|
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
|
|
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
|
style.alignment = alignment;
|
|
style.lineBreakMode = NSLineBreakByWordWrapping;
|
|
attributes[NSFontAttributeName] = font;
|
|
attributes[NSForegroundColorAttributeName] = color;
|
|
attributes[NSParagraphStyleAttributeName] = style;
|
|
[attributedString addAttributes:attributes range:range];
|
|
|
|
CGRect destRect = [string boundingRectWithSize:CGSizeMake(rect.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil];
|
|
CGRect outputRect = RectCenteredInRect(destRect, rect);
|
|
[attributedString drawInRect:outputRect];
|
|
}
|
|
|
|
#pragma mark - Unwrapped
|
|
UIFont *FontForUnwrappedString(NSString *string, NSString *fontFace, CGRect rect)
|
|
{
|
|
CGFloat fontSize = 1;
|
|
UIFont *font = [UIFont fontWithName:fontFace size:fontSize];
|
|
CGSize destSize = [string sizeWithAttributes:@{NSFontAttributeName:font}];
|
|
|
|
while ((destSize.width < rect.size.width) && (destSize.height < rect.size.height))
|
|
{
|
|
fontSize++;
|
|
UIFont *proposedFont = [UIFont fontWithName:fontFace size:fontSize];
|
|
destSize = [string sizeWithAttributes:@{NSFontAttributeName:proposedFont}];
|
|
if ((destSize.height > rect.size.height) || (destSize.width > rect.size.width))
|
|
return font;
|
|
|
|
font = proposedFont;
|
|
}
|
|
|
|
return font;
|
|
}
|
|
|
|
void DrawUnwrappedStringInRect(NSString *string, CGRect rect, NSString *fontFace, NSTextAlignment alignment, UIColor *color)
|
|
{
|
|
UIFont *font = FontForUnwrappedString(string, fontFace, rect);
|
|
DrawStringInRect(string, rect, font, alignment, color);
|
|
}
|
|
|
|
void DrawStringCenteredInRect(NSString *string, UIFont *font, CGRect rect)
|
|
{
|
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
if (context == NULL) COMPLAIN_AND_BAIL(@"No context to draw into", nil);
|
|
|
|
// Calculate string size
|
|
CGSize stringSize = [string sizeWithAttributes:@{NSFontAttributeName:font}];
|
|
|
|
// Find the target rectangle
|
|
CGRect target = RectAroundCenter(RectGetCenter(rect), stringSize);
|
|
|
|
// Draw the string
|
|
[string drawInRect:target withAttributes:@{NSFontAttributeName:font}];
|
|
}
|
|
|
|
|
|
#pragma mark - Wrapping
|
|
|
|
UIFont *FontForWrappedString(NSString *string, NSString *fontFace, CGRect rect, CGFloat tolerance)
|
|
{
|
|
if (rect.size.height < 1.0f) return nil;
|
|
|
|
CGFloat adjustedWidth = tolerance * rect.size.width;
|
|
CGSize measureSize = CGSizeMake(adjustedWidth, CGFLOAT_MAX);
|
|
|
|
// Initialize the proposed font
|
|
CGFloat fontSize = 1;
|
|
UIFont *proposedFont = [UIFont fontWithName:fontFace size:fontSize];
|
|
|
|
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
|
|
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
|
|
|
|
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
|
|
attributes[NSParagraphStyleAttributeName] = paragraphStyle;
|
|
attributes[NSFontAttributeName] = proposedFont;
|
|
|
|
// Measure the target
|
|
CGSize targetSize = [string boundingRectWithSize:measureSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;
|
|
|
|
// Double until the size is exceeded
|
|
while (targetSize.height <= rect.size.height)
|
|
{
|
|
// Establish a new proposed font
|
|
fontSize *= 2;
|
|
proposedFont = [UIFont fontWithName:fontFace size:fontSize];
|
|
|
|
// Measure the target
|
|
attributes[NSFontAttributeName] = proposedFont;
|
|
targetSize = [string boundingRectWithSize:measureSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;
|
|
|
|
// Break when the calculated height is too much
|
|
if (targetSize.height > rect.size.height)
|
|
break;
|
|
}
|
|
|
|
// Search between the previous and current font sizes
|
|
CGFloat minFontSize = fontSize / 2;
|
|
CGFloat maxFontSize = fontSize;
|
|
while (1)
|
|
{
|
|
// Get the midpoint between the two
|
|
CGFloat midPoint = (minFontSize + (maxFontSize - minFontSize) / 2);
|
|
proposedFont = [UIFont fontWithName:fontFace size:midPoint];
|
|
attributes[NSFontAttributeName] = proposedFont;
|
|
targetSize = [string boundingRectWithSize:measureSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;
|
|
|
|
// Look up one font size
|
|
UIFont *nextFont = [UIFont fontWithName:fontFace size:midPoint + 1];
|
|
attributes[NSFontAttributeName] = nextFont;
|
|
CGSize nextTargetSize = [string boundingRectWithSize:measureSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;;
|
|
|
|
// Test both fonts
|
|
CGFloat tooBig = targetSize.height > rect.size.height;
|
|
CGFloat nextIsTooBig = nextTargetSize.height > rect.size.height;
|
|
|
|
// If the current is sized right but the next is too big, win
|
|
if (!tooBig && nextIsTooBig)
|
|
return [UIFont fontWithName:fontFace size:midPoint];
|
|
|
|
// Adjust the search space
|
|
if (tooBig)
|
|
maxFontSize = midPoint;
|
|
else
|
|
minFontSize = midPoint;
|
|
}
|
|
|
|
// Should never get here
|
|
return [UIFont fontWithName:fontFace size:fontSize / 2];
|
|
}
|
|
|
|
CGSize AttributedStringSize(NSAttributedString *string, CGSize constrainedSize)
|
|
{
|
|
return [string boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size;
|
|
}
|
|
|
|
void DrawWrappedStringInRect(NSString *string, CGRect rect, NSString *fontFace, NSTextAlignment alignment, UIColor *color)
|
|
{
|
|
|
|
UIFont *font = FontForWrappedString(string, fontFace, rect, 0.95);
|
|
|
|
NSMutableAttributedString *s = [[NSMutableAttributedString alloc] initWithString:string];
|
|
NSRange r = NSMakeRange(0, string.length);
|
|
[s addAttribute:NSFontAttributeName value:font range:r];
|
|
[s addAttribute:NSForegroundColorAttributeName value:color range:r];
|
|
NSMutableParagraphStyle *p = [NSParagraphStyle defaultParagraphStyle].mutableCopy;
|
|
p.hyphenationFactor = 0.25f;
|
|
p.alignment = alignment;
|
|
[s addAttribute:NSParagraphStyleAttributeName value:p range:r];
|
|
|
|
CGRect stringBounds = SizeMakeRect(AttributedStringSize(s, rect.size));
|
|
stringBounds.size.width = fminf(rect.size.width, stringBounds.size.width);
|
|
CGRect dest = RectCenteredInRect(stringBounds, rect);
|
|
dest.size.height = CGFLOAT_MAX;
|
|
[s drawInRect:dest];
|
|
} |