瀏覽代碼

workaround for CoreText's bug in iOS7

ibireme 9 年之前
父節點
當前提交
922592d6c4
共有 2 個文件被更改,包括 28 次插入22 次删除
  1. 2 3
      README.md
  2. 26 19
      YYText/Component/YYTextLayout.m

+ 2 - 3
README.md

@@ -1061,10 +1061,9 @@ YYText 和 TextKit 架构对比
 已知问题
 ==============
 * YYText 并不能支持所有 CoreText/TextKit 的属性,比如 NSBackgroundColor、NSStrikethrough、NSUnderline、NSAttachment、NSLink 等,但 YYText 中基本都有对应属性作为替代。详情见上方表格。
-* YYTextView 目前还未实现局部刷新,所以在输入和编辑大量的文本(比如超过5K个汉字、10K个英文字符)时会出现较明显的卡顿现象。
+* YYTextView 未实现局部刷新,所以在输入和编辑大量的文本(比如超过大概五千个汉字、或大概一万个英文字符)时会出现较明显的卡顿现象。
 * 竖排版时,添加 exclusionPaths 在少数情况下可能会导致文本显示空白。
-* 当添加了非矩形的 textContainerPath 时,并且有嵌入大于文本排版方向宽度的 RunDelegate 时,RunDelegate 后面的文字会无法显示。这是 CoreText 的 Bug(也可能是 Feature)。
-* 在 iOS 7 的某些版本中,竖排版的中文字符可能会无法绘制,这可能是 CoreText 的 Bug,但还需要进一步的验证。
+* 当添加了非矩形的 textContainerPath 时,并且有嵌入大于文本排版方向宽度的 RunDelegate 时,RunDelegate 后面的文字会无法显示。这是 CoreText 的 Bug(或者说是 Feature)。
 
 许可证
 ==============

+ 26 - 19
YYText/Component/YYTextLayout.m

@@ -37,6 +37,23 @@ static inline UIEdgeInsets UIEdgeInsetRotateVertical(UIEdgeInsets insets) {
     return one;
 }
 
+/**
+ Sometimes CoreText may convert CGColor to UIColor for `kCTForegroundColorAttributeName`
+ attribute in iOS7. This should be a bug of CoreText, and may cause crash. Here's a workaround.
+ */
+static CGColorRef YYTextGetCGColor(CGColorRef color) {
+    static UIColor *defaultColor;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        defaultColor = [UIColor blackColor];
+    });
+    if (!color) return defaultColor.CGColor;
+    if ([((__bridge NSObject *)color) respondsToSelector:@selector(CGColor)]) {
+        return ((__bridge UIColor *)color).CGColor;
+    }
+    return color;
+}
+
 @implementation YYTextLinePositionSimpleModifier
 - (void)modifyLines:(NSArray *)lines fromText:(NSAttributedString *)text inContainer:(YYTextContainer *)container {
     if (container.verticalForm) {
@@ -2193,7 +2210,7 @@ static void YYTextDrawRun(YYTextLine *line, CTRunRef run, CGContextRef context,
         CTRunGetPositions(run, CFRangeMake(0, 0), glyphPositions);
         
         CGColorRef fillColor = (CGColorRef)CFDictionaryGetValue(runAttrs, kCTForegroundColorAttributeName);
-        if (!fillColor) fillColor = [UIColor blackColor].CGColor;
+        fillColor = YYTextGetCGColor(fillColor);
         NSNumber *strokeWidth = CFDictionaryGetValue(runAttrs, kCTStrokeWidthAttributeName);
         
         CGContextSaveGState(context); {
@@ -2793,20 +2810,6 @@ static void YYTextDrawDecoration(YYTextLayout *layout, CGContextRef context, CGS
             if (glyphCount == 0) continue;
             
             NSDictionary *attrs = (id)CTRunGetAttributes(run);
-            
-            /*
-             Sometimes CoreText may convert CGColor to UIColor for `kCTForegroundColorAttributeName`
-             attribute in iOS7. This should be a bug of CoreText, and may cause crash. Here's a workaround.
-             */
-            NSObject *tmpColor = attrs[(id)kCTForegroundColorAttributeName];
-            if ([tmpColor respondsToSelector:@selector(CGColor)]) {
-                CGColorRef cgColor = ((UIColor *)tmpColor).CGColor;
-                if (!cgColor) cgColor = [UIColor blackColor].CGColor;
-                NSMutableDictionary *tmpAttrs = attrs.mutableCopy;
-                tmpAttrs[(id)kCTForegroundColorAttributeName] = (__bridge id)(cgColor);
-                attrs = tmpAttrs;
-            }
-            
             YYTextDecoration *underline = attrs[YYTextUnderlineAttributeName];
             YYTextDecoration *strikethrough = attrs[YYTextStrikethroughAttributeName];
             
@@ -2852,8 +2855,10 @@ static void YYTextDrawDecoration(YYTextLayout *layout, CGContextRef context, CGS
             
             if (needDrawUnderline) {
                 CGColorRef color = underline.color.CGColor;
-                if (!color) color = (__bridge CGColorRef)(attrs[(id)kCTForegroundColorAttributeName]);
-                if (!color) color = [UIColor blackColor].CGColor;
+                if (!color) {
+                    color = (__bridge CGColorRef)(attrs[(id)kCTForegroundColorAttributeName]);
+                    color = YYTextGetCGColor(color);
+                }
                 CGFloat thickness = underline.width ? underline.width.floatValue : lineThickness;
                 YYTextShadow *shadow = underline.shadow;
                 while (shadow) {
@@ -2879,8 +2884,10 @@ static void YYTextDrawDecoration(YYTextLayout *layout, CGContextRef context, CGS
             
             if (needDrawStrikethrough) {
                 CGColorRef color = strikethrough.color.CGColor;
-                if (!color) color = (__bridge CGColorRef)(attrs[(id)kCTForegroundColorAttributeName]);
-                if (!color) color = [UIColor blackColor].CGColor;
+                if (!color) {
+                    color = (__bridge CGColorRef)(attrs[(id)kCTForegroundColorAttributeName]);
+                    color = YYTextGetCGColor(color);
+                }
                 CGFloat thickness = strikethrough.width ? strikethrough.width.floatValue : lineThickness;
                 YYTextShadow *shadow = underline.shadow;
                 while (shadow) {