// // NSParagraphStyle+ASText.mm // Texture // // Copyright (c) Pinterest, Inc. All rights reserved. // Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 // #import "NSParagraphStyle+ASText.h" #import "Private/TextExperiment/String/ASTextAttribute.h" #import // Dummy class for category @interface NSParagraphStyle_ASText : NSObject @end @implementation NSParagraphStyle_ASText @end @implementation NSParagraphStyle (ASText) + (NSParagraphStyle *)as_styleWithCTStyle:(CTParagraphStyleRef)CTStyle { if (CTStyle == NULL) return nil; NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; #if TARGET_OS_IOS #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" CGFloat lineSpacing; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierLineSpacing, sizeof(CGFloat), &lineSpacing)) { style.lineSpacing = lineSpacing; } #pragma clang diagnostic pop #endif CGFloat paragraphSpacing; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierParagraphSpacing, sizeof(CGFloat), ¶graphSpacing)) { style.paragraphSpacing = paragraphSpacing; } CTTextAlignment alignment; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), &alignment)) { style.alignment = NSTextAlignmentFromCTTextAlignment(alignment); } CGFloat firstLineHeadIndent; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierFirstLineHeadIndent, sizeof(CGFloat), &firstLineHeadIndent)) { style.firstLineHeadIndent = firstLineHeadIndent; } CGFloat headIndent; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierHeadIndent, sizeof(CGFloat), &headIndent)) { style.headIndent = headIndent; } CGFloat tailIndent; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierTailIndent, sizeof(CGFloat), &tailIndent)) { style.tailIndent = tailIndent; } CTLineBreakMode lineBreakMode; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierLineBreakMode, sizeof(CTLineBreakMode), &lineBreakMode)) { style.lineBreakMode = (NSLineBreakMode)lineBreakMode; } CGFloat minimumLineHeight; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierMinimumLineHeight, sizeof(CGFloat), &minimumLineHeight)) { style.minimumLineHeight = minimumLineHeight; } CGFloat maximumLineHeight; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierMaximumLineHeight, sizeof(CGFloat), &maximumLineHeight)) { style.maximumLineHeight = maximumLineHeight; } CTWritingDirection baseWritingDirection; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierBaseWritingDirection, sizeof(CTWritingDirection), &baseWritingDirection)) { style.baseWritingDirection = (NSWritingDirection)baseWritingDirection; } CGFloat lineHeightMultiple; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierLineHeightMultiple, sizeof(CGFloat), &lineHeightMultiple)) { style.lineHeightMultiple = lineHeightMultiple; } CGFloat paragraphSpacingBefore; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierParagraphSpacingBefore, sizeof(CGFloat), ¶graphSpacingBefore)) { style.paragraphSpacingBefore = paragraphSpacingBefore; } CFArrayRef tabStops; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierTabStops, sizeof(CFArrayRef), &tabStops)) { NSMutableArray *tabs = [NSMutableArray new]; [((__bridge NSArray *)(tabStops))enumerateObjectsUsingBlock : ^(id obj, NSUInteger idx, BOOL *stop) { CTTextTabRef ctTab = (__bridge CTTextTabRef)obj; NSTextTab *tab = [[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentFromCTTextAlignment(CTTextTabGetAlignment(ctTab)) location:CTTextTabGetLocation(ctTab) options:(__bridge id)CTTextTabGetOptions(ctTab)]; [tabs addObject:tab]; }]; if (tabs.count) { style.tabStops = tabs; } } CGFloat defaultTabInterval; if (CTParagraphStyleGetValueForSpecifier(CTStyle, kCTParagraphStyleSpecifierDefaultTabInterval, sizeof(CGFloat), &defaultTabInterval)) { style.defaultTabInterval = defaultTabInterval; } return style; } - (CTParagraphStyleRef)as_CTStyle CF_RETURNS_RETAINED { CTParagraphStyleSetting set[kCTParagraphStyleSpecifierCount] = { }; int count = 0; #if TARGET_OS_IOS #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" CGFloat lineSpacing = self.lineSpacing; set[count].spec = kCTParagraphStyleSpecifierLineSpacing; set[count].valueSize = sizeof(CGFloat); set[count].value = &lineSpacing; count++; #pragma clang diagnostic pop #endif CGFloat paragraphSpacing = self.paragraphSpacing; set[count].spec = kCTParagraphStyleSpecifierParagraphSpacing; set[count].valueSize = sizeof(CGFloat); set[count].value = ¶graphSpacing; count++; CTTextAlignment alignment = NSTextAlignmentToCTTextAlignment(self.alignment); set[count].spec = kCTParagraphStyleSpecifierAlignment; set[count].valueSize = sizeof(CTTextAlignment); set[count].value = &alignment; count++; CGFloat firstLineHeadIndent = self.firstLineHeadIndent; set[count].spec = kCTParagraphStyleSpecifierFirstLineHeadIndent; set[count].valueSize = sizeof(CGFloat); set[count].value = &firstLineHeadIndent; count++; CGFloat headIndent = self.headIndent; set[count].spec = kCTParagraphStyleSpecifierHeadIndent; set[count].valueSize = sizeof(CGFloat); set[count].value = &headIndent; count++; CGFloat tailIndent = self.tailIndent; set[count].spec = kCTParagraphStyleSpecifierTailIndent; set[count].valueSize = sizeof(CGFloat); set[count].value = &tailIndent; count++; CTLineBreakMode paraLineBreak = (CTLineBreakMode)self.lineBreakMode; set[count].spec = kCTParagraphStyleSpecifierLineBreakMode; set[count].valueSize = sizeof(CTLineBreakMode); set[count].value = ¶LineBreak; count++; CGFloat minimumLineHeight = self.minimumLineHeight; set[count].spec = kCTParagraphStyleSpecifierMinimumLineHeight; set[count].valueSize = sizeof(CGFloat); set[count].value = &minimumLineHeight; count++; CGFloat maximumLineHeight = self.maximumLineHeight; set[count].spec = kCTParagraphStyleSpecifierMaximumLineHeight; set[count].valueSize = sizeof(CGFloat); set[count].value = &maximumLineHeight; count++; CTWritingDirection paraWritingDirection = (CTWritingDirection)self.baseWritingDirection; set[count].spec = kCTParagraphStyleSpecifierBaseWritingDirection; set[count].valueSize = sizeof(CTWritingDirection); set[count].value = ¶WritingDirection; count++; CGFloat lineHeightMultiple = self.lineHeightMultiple; set[count].spec = kCTParagraphStyleSpecifierLineHeightMultiple; set[count].valueSize = sizeof(CGFloat); set[count].value = &lineHeightMultiple; count++; CGFloat paragraphSpacingBefore = self.paragraphSpacingBefore; set[count].spec = kCTParagraphStyleSpecifierParagraphSpacingBefore; set[count].valueSize = sizeof(CGFloat); set[count].value = ¶graphSpacingBefore; count++; NSMutableArray *tabs = [NSMutableArray array]; NSInteger numTabs = self.tabStops.count; if (numTabs) { [self.tabStops enumerateObjectsUsingBlock: ^(NSTextTab *tab, NSUInteger idx, BOOL *stop) { CTTextTabRef ctTab = CTTextTabCreate(NSTextAlignmentToCTTextAlignment(tab.alignment), tab.location, (__bridge CFDictionaryRef)tab.options); [tabs addObject:(__bridge id)ctTab]; CFRelease(ctTab); }]; CFArrayRef tabStops = (__bridge CFArrayRef)(tabs); set[count].spec = kCTParagraphStyleSpecifierTabStops; set[count].valueSize = sizeof(CFArrayRef); set[count].value = &tabStops; count++; } CGFloat defaultTabInterval = self.defaultTabInterval; set[count].spec = kCTParagraphStyleSpecifierDefaultTabInterval; set[count].valueSize = sizeof(CGFloat); set[count].value = &defaultTabInterval; count++; CTParagraphStyleRef style = CTParagraphStyleCreate(set, count); return style; } @end