4343#define DRAW_ITALIC 0x10 /* draw italic text */
4444#define DRAW_CURSOR 0x20
4545#define DRAW_WIDE 0x80 /* draw wide text */
46+ #define DRAW_COMP 0x100 /* drawing composing char */
4647
4748#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
4849#define kCTFontOrientationDefault kCTFontDefaultOrientation
@@ -1181,7 +1182,7 @@ - (void)batchDrawData:(NSData *)data
11811182 // 2 - full ligatures including rare
11821183 // 1 - basic ligatures
11831184 // 0 - no ligatures
1184- [NSNumber numberWithInteger: ( useLigatures ? 1 : 0 ) ],
1185+ [NSNumber numberWithBool: useLigatures],
11851186 kCTLigatureAttributeName ,
11861187 nil
11871188 ];
@@ -1192,7 +1193,7 @@ - (void)batchDrawData:(NSData *)data
11921193
11931194 static UniCharCount
11941195fetchGlyphsAndAdvances (const CTLineRef line, CGGlyph *glyphs, CGSize *advances,
1195- UniCharCount length)
1196+ CGPoint *positions, UniCharCount length)
11961197{
11971198 NSArray *glyphRuns = (NSArray *)CTLineGetGlyphRuns (line);
11981199
@@ -1211,6 +1212,8 @@ - (void)batchDrawData:(NSData *)data
12111212 CTRunGetGlyphs (run, range, &glyphs[offset]);
12121213 if (advances != NULL )
12131214 CTRunGetAdvances (run, range, &advances[offset]);
1215+ if (positions != NULL )
1216+ CTRunGetPositions (run, range, &positions[offset]);
12141217
12151218 offset += count;
12161219 if (offset >= length)
@@ -1237,97 +1240,41 @@ - (void)batchDrawData:(NSData *)data
12371240}
12381241
12391242 static UniCharCount
1240- ligatureGlyphsForChars (const unichar *chars, CGGlyph *glyphs,
1241- CGPoint *positions, UniCharCount length, CTFontRef font)
1243+ composeGlyphsForChars (const unichar *chars, CGGlyph *glyphs,
1244+ CGPoint *positions, UniCharCount length, CTFontRef font,
1245+ BOOL isComposing, BOOL useLigatures)
12421246{
1243- // CoreText has no simple wait of retrieving a ligature for a set of
1244- // UniChars. The way proposed on the CoreText ML is to convert the text to
1245- // an attributed string, create a CTLine from it and retrieve the Glyphs
1246- // from the CTRuns in it.
1247- CGGlyph refGlyphs[length];
1248- CGPoint refPositions[length];
1249-
1250- memcpy (refGlyphs, glyphs, sizeof (CGGlyph) * length);
1251- memcpy (refPositions, positions, sizeof (CGSize) * length);
1252-
12531247 memset (glyphs, 0 , sizeof (CGGlyph) * length);
12541248
12551249 NSString *plainText = [NSString stringWithCharacters: chars length: length];
1256- CFAttributedStringRef ligatureText = attributedStringForString (plainText,
1257- font, YES );
1258-
1259- CTLineRef ligature = CTLineCreateWithAttributedString (ligatureText);
1260-
1261- CGSize ligatureRanges[length], regularRanges[length];
1262-
1263- // get the (ligature)glyphs and advances for the new text
1264- UniCharCount offset = fetchGlyphsAndAdvances (ligature, glyphs,
1265- ligatureRanges, length);
1266- // fetch the advances for the base text
1267- CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault , refGlyphs,
1268- regularRanges, length);
1269-
1270- CFRelease (ligatureText);
1271- CFRelease (ligature);
1272-
1273- // tricky part: compare both advance ranges and chomp positions which are
1274- // covered by a single ligature while keeping glyphs not in the ligature
1275- // font.
1276- #define fequal (a, b ) (fabs((a) - (b)) < FLT_EPSILON)
1277- #define fless (a, b )((a) - (b) < FLT_EPSILON) && (fabs((a) - (b)) > FLT_EPSILON)
1278-
1279- CFIndex skip = 0 ;
1280- CFIndex i;
1281- for (i = 0 ; i < offset && skip + i < length; ++i) {
1282- memcpy (&positions[i], &refPositions[skip + i], sizeof (CGSize));
1283-
1284- if (fequal (ligatureRanges[i].width , regularRanges[skip + i].width )) {
1285- // [mostly] same width
1286- continue ;
1287- } else if (fless (ligatureRanges[i].width ,
1288- regularRanges[skip + i].width )) {
1289- // original is wider than our result - use the original glyph
1290- // FIXME: this is currently the only way to detect emoji (except
1291- // for 'glyph[i] == 5')
1292- glyphs[i] = refGlyphs[skip + i];
1293- continue ;
1294- }
1250+ CFAttributedStringRef composedText = attributedStringForString (plainText,
1251+ font,
1252+ useLigatures);
12951253
1296- // no, that's a ligature
1297- // count how many positions this glyph would take up in the base text
1298- CFIndex j = 0 ;
1299- float width = ceil (regularRanges[skip + i].width );
1254+ CTLineRef line = CTLineCreateWithAttributedString (composedText);
13001255
1301- while ((int )width < (int )ligatureRanges[i].width
1302- && skip + i + j < length) {
1303- width += ceil (regularRanges[++j + skip + i].width );
1304- }
1305- skip += j;
1306- }
1256+ // get the (composing)glyphs and advances for the new text
1257+ UniCharCount offset = fetchGlyphsAndAdvances (line, glyphs, NULL ,
1258+ isComposing ? positions : NULL ,
1259+ length);
13071260
1308- # undef fless
1309- # undef fequal
1261+ CFRelease (composedText);
1262+ CFRelease (line);
13101263
1311- // as ligatures combine characters it is required to adjust the
1264+ // as ligatures composing characters it is required to adjust the
13121265 // original length value
13131266 return offset;
13141267}
13151268
13161269 static void
13171270recurseDraw (const unichar *chars, CGGlyph *glyphs, CGPoint *positions,
13181271 UniCharCount length, CGContextRef context, CTFontRef fontRef,
1319- NSMutableArray *fontCache, BOOL useLigatures)
1272+ NSMutableArray *fontCache, BOOL isComposing, BOOL useLigatures)
13201273{
13211274 if (CTFontGetGlyphsForCharacters (fontRef, chars, glyphs, length)) {
13221275 // All chars were mapped to glyphs, so draw all at once and return.
1323- if (useLigatures) {
1324- length = ligatureGlyphsForChars (chars, glyphs, positions, length,
1325- fontRef);
1326- } else {
1327- // only fixup surrogate pairs if we're not using ligatures
1328- length = gatherGlyphs (glyphs, length);
1329- }
1330-
1276+ length = composeGlyphsForChars (chars, glyphs, positions, length,
1277+ fontRef, isComposing, useLigatures);
13311278 CTFontDrawGlyphs (fontRef, glyphs, positions, length, context);
13321279 return ;
13331280 }
@@ -1388,7 +1335,7 @@ - (void)batchDrawData:(NSData *)data
13881335 return ;
13891336
13901337 recurseDraw (chars, glyphs, positions, attemptedCount, context,
1391- fallback, fontCache, useLigatures);
1338+ fallback, fontCache, isComposing, useLigatures);
13921339
13931340 // If only a portion of the invalid range was rendered above,
13941341 // the remaining range needs to be attempted by subsequent
@@ -1422,8 +1369,10 @@ - (void)drawString:(const UniChar *)chars length:(UniCharCount)length
14221369 float x = col*cellSize.width + insetSize.width ;
14231370 float y = frame.size .height - insetSize.height - (1 +row)*cellSize.height ;
14241371 float w = cellSize.width ;
1372+ BOOL wide = flags & DRAW_WIDE ? YES : NO ;
1373+ BOOL composing = flags & DRAW_COMP ? YES : NO ;
14251374
1426- if (flags & DRAW_WIDE ) {
1375+ if (wide ) {
14271376 // NOTE: It is assumed that either all characters in 'chars' are wide
14281377 // or all are normal width.
14291378 w *= 2 ;
@@ -1489,7 +1438,7 @@ - (void)drawString:(const UniChar *)chars length:(UniCharCount)length
14891438 if (length > maxlen) {
14901439 if (glyphs) free (glyphs);
14911440 if (positions) free (positions);
1492- glyphs = (CGGlyph*)malloc (length* sizeof (CGGlyph));
1441+ glyphs = (CGGlyph*)calloc (length, sizeof (CGGlyph));
14931442 positions = (CGPoint*)calloc (length, sizeof (CGPoint));
14941443 maxlen = length;
14951444 }
@@ -1500,15 +1449,17 @@ - (void)drawString:(const UniChar *)chars length:(UniCharCount)length
15001449 CGContextSetFontSize (context, [font pointSize ]);
15011450
15021451 // Calculate position of each glyph relative to (x,y).
1503- NSUInteger i;
1504- float xrel = 0 ;
1505- for (i = 0 ; i < length; ++i) {
1506- positions[i].x = xrel;
1507- xrel += w;
1452+ if (!composing) {
1453+ float xrel = 0 ;
1454+ for (unsigned i = 0 ; i < length; ++i) {
1455+ positions[i].x = xrel;
1456+ positions[i].y = .0 ;
1457+ xrel += w;
1458+ }
15081459 }
15091460
1510- CTFontRef fontRef = (CTFontRef)(flags & DRAW_WIDE ? [fontWide retain ]
1511- : [font retain ]);
1461+ CTFontRef fontRef = (CTFontRef)(wide ? [fontWide retain ]
1462+ : [font retain ]);
15121463 unsigned traits = 0 ;
15131464 if (flags & DRAW_ITALIC)
15141465 traits |= kCTFontItalicTrait ;
@@ -1517,15 +1468,16 @@ - (void)drawString:(const UniChar *)chars length:(UniCharCount)length
15171468
15181469 if (traits) {
15191470 CTFontRef fr = CTFontCreateCopyWithSymbolicTraits (fontRef, 0.0 , NULL ,
1520- traits, traits);
1471+ traits, traits);
15211472 if (fr) {
15221473 CFRelease (fontRef);
15231474 fontRef = fr;
15241475 }
15251476 }
15261477
15271478 CGContextSetTextPosition (context, x, y+fontDescent);
1528- recurseDraw (chars, glyphs, positions, length, context, fontRef, fontCache, ligatures);
1479+ recurseDraw (chars, glyphs, positions, length, context, fontRef, fontCache,
1480+ composing, ligatures);
15291481
15301482 CFRelease (fontRef);
15311483 if (thinStrokes)
0 commit comments