Implement the glyph generation backend methods. Implement GSShowGlyphs operator. Handle glyphs properly in FTFontInfo.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/branches/text-system-branch@15060 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Alexander Malmberg 2002-11-23 23:37:29 +00:00
parent 385d843bec
commit 438d0b4474
4 changed files with 663 additions and 38 deletions

View file

@ -1,3 +1,9 @@
2002-11-24 00:35 Alexander Malmberg <alexander@malmberg.org>
* Source/art/ARTContext.m, Source/art/ftfont.h, Source/art/ftfont.m:
Implement the glyph generation backend methods. Implement the
GSShowGlyphs operator. Handle glyphs properly in FTFontInfo.
2002-11-21 Adam Fedor <fedor@gnu.org>
* Version: 0.8.3

View file

@ -28,7 +28,9 @@
#include "ARTGState.h"
#ifndef RDS
#include "x11/XWindowBuffer.h"
#endif
#include "blit.h"
#include "ftfont.h"
@ -295,7 +297,7 @@ very expensive
if (all_clipped)
return;
if ([path isEmpty]) return;
if (!path || [path isEmpty]) return;
p = [path currentPoint];
x = p.x;
@ -311,6 +313,31 @@ very expensive
}
- (void) GSShowGlyphs: (const NSGlyph *)glyphs : (size_t) length
{
NSPoint p;
int x, y;
if (!wi || !wi->data) return;
if (all_clipped)
return;
if (!path || [path isEmpty]) return;
p = [path currentPoint];
x = p.x;
y = wi->sy - p.y;
[(id<FTFontInfo>)font
drawGlyphs: glyphs : length
at: x:y
to: clip_x0:clip_y0:clip_x1:clip_y1 : CLIP_DATA : wi->bytes_per_line
color: fill_color[0]:fill_color[1]:fill_color[2]:fill_color[3]
transform: ctm
drawinfo: &DI];
UPDATE_UNBUFFERED
}
/* ----------------------------------------------------------------------- */
/* Gstate operations */
/* ----------------------------------------------------------------------- */
@ -556,7 +583,9 @@ very expensive
XWindowBuffer *new_wi;
[self setOffset: NSMakePoint(x, y)];
#ifndef RDS
di.drawing_depth = DI.drawing_depth;
#endif
di.bytes_per_pixel = DI.bytes_per_pixel;
di.inline_alpha = DI.inline_alpha;
di.inline_alpha_ofs = DI.inline_alpha_ofs;
@ -622,6 +651,15 @@ very expensive
[gstate DPSsetalpha: 1.0];
[gstate DPSsetlinewidth: 1.0];
#ifdef RDS
{
RDSServer *s=(RDSServer *)server;
int bpp;
int red_mask,green_mask,blue_mask;
[s getPixelFormat: &bpp masks: &red_mask : &green_mask : &blue_mask];
artcontext_setup_draw_info(&DI,red_mask,green_mask,blue_mask,bpp);
}
#else
{
Display *d=[(XGServer *)server xDisplay];
Visual *v=DefaultVisual(d,DefaultScreen(d));
@ -632,6 +670,7 @@ very expensive
artcontext_setup_draw_info(&DI,v->red_mask,v->green_mask,v->blue_mask,bpp);
}
#endif
return self;
}
@ -639,7 +678,9 @@ very expensive
- (void) flushGraphics
{ /* TODO: _really_ flush? (ie. force updates and wait for shm completion?) */
#ifndef RDS
XFlush([(XGServer *)server xDisplay]);
#endif
}
+(void) waitAllContexts
@ -647,6 +688,7 @@ very expensive
}
#ifndef RDS
+(void) _gotShmCompletion: (Drawable)d
{
[XWindowBuffer _gotShmCompletion: d];
@ -656,6 +698,7 @@ very expensive
{
[XWindowBuffer _gotShmCompletion: d];
}
#endif
//
// Read the Color at a Screen Position
@ -668,7 +711,10 @@ very expensive
- (void) beep
{
NSLog(@"ARTContext -beep: why here?");
#ifndef RDS
XBell([(XGServer *)server xDisplay], 50);
#endif
}
/* Private backend methods */

View file

@ -35,6 +35,15 @@
transform: (NSAffineTransform *)transform
drawinfo: (struct draw_info_s *)di;
-(void) drawGlyphs: (const NSGlyph *)glyphs : (int)length
at: (int)x : (int)y
to: (int)x0 : (int)y0 : (int)x1 : (int)y1
: (unsigned char *)buf : (int)bpl
color: (unsigned char)r : (unsigned char)g : (unsigned char)b
: (unsigned char)alpha
transform: (NSAffineTransform *)transform
drawinfo: (struct draw_info_s *)di;
/* TODO: see if this is really necessary */
-(void) drawString: (const char *)s
at: (int)x:(int)y

View file

@ -75,12 +75,17 @@ static BOOL anti_alias_by_default;
@interface FTFontInfo : GSFontInfo <FTFontInfo>
{
@public
const char *filename;
FTC_ImageDesc imgd;
FTC_ImageDesc fallback;
FTFaceInfo *face_info;
/* Glyph generation */
NSGlyph ligature_ff,ligature_fi,ligature_fl,ligature_ffl,ligature_ffi;
}
@end
@ -589,10 +594,10 @@ static FT_Error ft_get_face(FTC_FaceID fid, FT_Library lib, FT_Pointer data, FT_
self = [super init];
NSDebugLLog(@"ftfont", @"[%@ -initWithFontName: %@ matrix: (%g %g %g %g %g %g)]\n",
/* NSDebugLLog(@"ftfont", @"[%@ -initWithFontName: %@ matrix: (%g %g %g %g %g %g)]\n",
self, name,
fmatrix[0], fmatrix[1], fmatrix[2],
fmatrix[3], fmatrix[4], fmatrix[5]);
fmatrix[3], fmatrix[4], fmatrix[5]);*/
font_entry = [fcfg_all_fonts objectForKey: name];
if (!font_entry)
@ -649,20 +654,39 @@ static FT_Error ft_get_face(FTC_FaceID fid, FT_Library lib, FT_Pointer data, FT_
}
// xHeight = size->metrics.height / 64.0;
ascender = fabs(size->metrics.ascender / 64.0);
descender = fabs(size->metrics.descender / 64.0);
/* TODO: these are _really_ messed up when fonts are flipped */
ascender = fabs(((int)size->metrics.ascender) / 64.0);
descender = fabs(((int)size->metrics.descender) / 64.0);
xHeight = ascender + descender; /* TODO */
maximumAdvancement = NSMakeSize((size->metrics.max_advance / 64.0), ascender + descender);
fontBBox = NSMakeRect(0, descender, maximumAdvancement.width, ascender + descender);
descender = -descender;
/* printf("h=%g a=%g d=%g max=(%g %g) (%g %g)+(%g %g)\n",
/* printf("(%@) h=%g a=%g d=%g max=(%g %g) (%g %g)+(%g %g)\n",name,
xHeight, ascender, descender,
maximumAdvancement.width, maximumAdvancement.height,
fontBBox.origin.x, fontBBox.origin.y,
fontBBox.size.width, fontBBox.size.height);*/
{
FTC_CMapDescRec cmap;
cmap.face_id = imgd.font.face_id;
cmap.u.encoding = ft_encoding_unicode;
cmap.type = FTC_CMAP_BY_ENCODING;
ligature_ff = FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, 0xfb00);
ligature_fi = FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, 0xfb01);
ligature_fl = FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, 0xfb02);
ligature_ffi = FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, 0xfb03);
ligature_ffl = FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, 0xfb04);
/* printf("ligatures %04x %04x %04x %04x %04x | %02x %02x %02x for |%@|\n",
ligature_ff,ligature_fi,ligature_fl,ligature_ffi,ligature_ffl,
FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, 'f'),
FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, 'l'),
FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, 'i'),
fontName);*/
}
return self;
}
@ -1084,29 +1108,336 @@ extern void GSToUnicode();
}
- (NSSize) advancementForGlyph: (NSGlyph)aGlyph
-(void) drawGlyphs: (const NSGlyph *)glyphs : (int)length
at: (int)x : (int)y
to: (int)x0 : (int)y0 : (int)x1 : (int)y1
: (unsigned char *)buf : (int)bpl
color: (unsigned char)r : (unsigned char)g : (unsigned char)b
: (unsigned char)alpha
transform: (NSAffineTransform *)transform
drawinfo: (struct draw_info_s *)di
{
FTC_CMapDescRec cmap;
unsigned int glyph;
FT_Glyph g;
int use_sbit;
FTC_ImageDesc *cur;
FTC_SBit sbit;
FTC_ImageDesc cur;
cmap.face_id = imgd.font.face_id;
cmap.u.encoding = ft_encoding_unicode;
cmap.type = FTC_CMAP_BY_ENCODING;
FT_Matrix ftmatrix;
FT_Vector ftdelta;
cur = &imgd;
glyph = FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, aGlyph);
if (!glyph)
if (!alpha)
return;
/* TODO: if we had guaranteed upper bounds on glyph image size we
could do some basic clipping here */
x1 -= x0;
y1 -= y0;
x -= x0;
y -= y0;
/* NSLog(@"[%@ draw using matrix: (%g %g %g %g %g %g)] transform=%@\n",
self,
matrix[0], matrix[1], matrix[2],
matrix[3], matrix[4], matrix[5],
transform
);*/
cur = imgd;
{
float xx, xy, yx, yy;
xx = matrix[0] * transform->matrix.m11 + matrix[1] * transform->matrix.m21;
yx = matrix[0] * transform->matrix.m12 + matrix[1] * transform->matrix.m22;
xy = matrix[2] * transform->matrix.m11 + matrix[3] * transform->matrix.m21;
yy = matrix[2] * transform->matrix.m12 + matrix[3] * transform->matrix.m22;
/* if we're drawing 'normal' text (unscaled, unrotated, reasonable
size), we can and should use the sbit cache */
if (fabs(xx - ((int)xx)) < 0.01 && fabs(yy - ((int)yy)) < 0.01 &&
fabs(xy) < 0.01 && fabs(yx) < 0.01 &&
xx < 72 && yy < 72 && xx > 0.5 && yy > 0.5)
{
use_sbit = 1;
cur.font.pix_width = xx;
cur.font.pix_height = yy;
if (xx == yy && xx < 16 && xx >= 8)
{
int rh = face_info->render_hints_hack;
if (rh & 0x10000)
{
cur.type = ftc_image_grays;
rh = (rh >> 8) & 0xff;
}
else
{
cur.type = ftc_image_mono;
rh = rh & 0xff;
}
if (rh & 1)
cur.type |= ftc_image_flag_autohinted;
if (!(rh & 2))
cur.type |= ftc_image_flag_unhinted;
}
else if (xx < 8)
cur.type = ftc_image_grays | ftc_image_flag_unhinted;
else
cur.type = ftc_image_grays;
}
else
{
float f;
use_sbit = 0;
f = fabs(xx * yy - xy * yx);
if (f > 1)
f = sqrt(f);
else
f = 1.0;
f = (int)f;
cur.font.pix_width = cur.font.pix_height = f;
ftmatrix.xx = xx / f * 65536.0;
ftmatrix.xy = xy / f * 65536.0;
ftmatrix.yx = yx / f * 65536.0;
ftmatrix.yy = yy / f * 65536.0;
ftdelta.x = ftdelta.y = 0;
}
}
/* NSLog(@"drawString: '%s' at: %i:%i to: %i:%i:%i:%i:%p\n",
s, x, y, x0, y0, x1, y1, buf);*/
for (; length; length--, glyphs++)
{
cmap.face_id = fallback.font.face_id;
glyph = FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, aGlyph);
if (glyph)
cur = &fallback;
}
glyph = *glyphs;
if (use_sbit)
{
if (FTC_SBitCache_Lookup(ftc_sbitcache, &cur, glyph, &sbit, NULL))
continue;
if (!sbit->buffer)
{
x += sbit->xadvance;
continue;
}
if (sbit->format == ft_pixel_mode_grays)
{
int gx = x + sbit->left, gy = y - sbit->top;
int sbpl = sbit->pitch;
int sx = sbit->width, sy = sbit->height;
const unsigned char *src = sbit->buffer;
unsigned char *dst = buf;
if (gy < 0)
{
sy += gy;
src -= sbpl * gy;
gy = 0;
}
else if (gy > 0)
{
dst += bpl * gy;
}
sy += gy;
if (sy > y1)
sy = y1;
if (gx < 0)
{
sx += gx;
src -= gx;
gx = 0;
}
else if (gx > 0)
{
dst += DI.bytes_per_pixel * gx;
}
sx += gx;
if (sx > x1)
sx = x1;
sx -= gx;
if (sx > 0)
{
if (alpha >= 255)
for (; gy < sy; gy++, src += sbpl, dst += bpl)
RENDER_BLIT_ALPHA_OPAQUE(dst, src, r, g, b, sx);
else
for (; gy < sy; gy++, src += sbpl, dst += bpl)
RENDER_BLIT_ALPHA(dst, src, r, g, b, alpha, sx);
}
}
else if (sbit->format == ft_pixel_mode_mono)
{
int gx = x + sbit->left, gy = y - sbit->top;
int sbpl = sbit->pitch;
int sx = sbit->width, sy = sbit->height;
const unsigned char *src = sbit->buffer;
unsigned char *dst = buf;
int src_ofs = 0;
if (gy < 0)
{
sy += gy;
src -= sbpl * gy;
gy = 0;
}
else if (gy > 0)
{
dst += bpl * gy;
}
sy += gy;
if (sy > y1)
sy = y1;
if (gx < 0)
{
sx += gx;
src -= gx / 8;
src_ofs = (-gx) & 7;
gx = 0;
}
else if (gx > 0)
{
dst += DI.bytes_per_pixel * gx;
}
sx += gx;
if (sx > x1)
sx = x1;
sx -= gx;
if (sx > 0)
{
if (alpha >= 255)
for (; gy < sy; gy++, src += sbpl, dst += bpl)
RENDER_BLIT_MONO_OPAQUE(dst, src, src_ofs, r, g, b, sx);
else
for (; gy < sy; gy++, src += sbpl, dst += bpl)
RENDER_BLIT_MONO(dst, src, src_ofs, r, g, b, alpha, sx);
}
}
else
{
NSLog(@"unhandled font bitmap format %i", sbit->format);
}
x += sbit->xadvance;
}
else
{
FT_Face face;
FT_Glyph gl;
FT_BitmapGlyph gb;
if (FTC_Manager_Lookup_Size(ftc_manager, &cur.font, &face, 0))
continue;
/* TODO: for rotations of 90, 180, 270, and integer
scales hinting might still be a good idea. */
if (FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP))
continue;
if (FT_Get_Glyph(face->glyph, &gl))
continue;
if (FT_Glyph_Transform(gl, &ftmatrix, &ftdelta))
{
NSLog(@"glyph transformation failed!");
continue;
}
if (FT_Glyph_To_Bitmap(&gl, ft_render_mode_normal, 0, 1))
{
FT_Done_Glyph(gl);
continue;
}
gb = (FT_BitmapGlyph)gl;
if (gb->bitmap.pixel_mode == ft_pixel_mode_grays)
{
int gx = x + gb->left, gy = y - gb->top;
int sbpl = gb->bitmap.pitch;
int sx = gb->bitmap.width, sy = gb->bitmap.rows;
const unsigned char *src = gb->bitmap.buffer;
unsigned char *dst = buf;
if (gy < 0)
{
sy += gy;
src -= sbpl * gy;
gy = 0;
}
else if (gy > 0)
{
dst += bpl * gy;
}
sy += gy;
if (sy > y1)
sy = y1;
if (gx < 0)
{
sx += gx;
src -= gx;
gx = 0;
}
else if (gx > 0)
{
dst += DI.bytes_per_pixel * gx;
}
sx += gx;
if (sx > x1)
sx = x1;
sx -= gx;
if (sx > 0)
{
if (alpha >= 255)
for (; gy < sy; gy++, src += sbpl, dst += bpl)
RENDER_BLIT_ALPHA_OPAQUE(dst, src, r, g, b, sx);
else
for (; gy < sy; gy++, src += sbpl, dst += bpl)
RENDER_BLIT_ALPHA(dst, src, r, g, b, alpha, sx);
}
}
/* TODO: will this case ever appear? */
/* else if (gb->bitmap.pixel_mode==ft_pixel_mode_mono)*/
else
{
NSLog(@"unhandled font bitmap format %i", gb->bitmap.pixel_mode);
}
ftdelta.x += gl->advance.x >> 10;
ftdelta.y += gl->advance.y >> 10;
FT_Done_Glyph(gl);
}
}
}
- (NSSize) advancementForGlyph: (NSGlyph)glyph
{
FT_Glyph g;
FTC_ImageDesc *cur;
/* TODO: this is ugly */
cur = &imgd;
if (FTC_ImageCache_Lookup(ftc_imagecache, cur, glyph, &g, NULL))
{
// NSLog(@"advancementForGlyph: %04x -> %i not found\n", aGlyph, glyph);
@ -1119,29 +1450,14 @@ extern void GSToUnicode();
return NSMakeSize(g->advance.x / 65536.0, g->advance.y / 65536.0);
}
- (NSRect) boundingRectForGlyph: (NSGlyph)aGlyph
- (NSRect) boundingRectForGlyph: (NSGlyph)glyph
{
FTC_CMapDescRec cmap;
FTC_ImageDesc *cur;
unsigned int glyph;
FT_BBox bbox;
FT_Glyph g;
cmap.face_id = imgd.font.face_id;
cmap.u.encoding = ft_encoding_unicode;
cmap.type = FTC_CMAP_BY_ENCODING;
/* TODO: this is ugly */
cur = &imgd;
glyph = FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, aGlyph);
if (!glyph)
{
cmap.face_id = fallback.font.face_id;
glyph = FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, aGlyph);
if (glyph)
cur = &fallback;
}
if (FTC_ImageCache_Lookup(ftc_imagecache, cur, glyph, &g, NULL))
{
// NSLog(@"boundingRectForGlyph: %04x -> %i\n", aGlyph, glyph);
@ -1157,6 +1473,45 @@ extern void GSToUnicode();
(bbox.xMax - bbox.xMin) / 64.0, (bbox.yMax - bbox.yMin) / 64.0);
}
-(NSPoint) positionOfGlyph: (NSGlyph)g
precededByGlyph: (NSGlyph)prev
isNominal: (BOOL *)nominal
{
NSPoint a;
FT_Face face;
FT_Vector vec;
FT_GlyphSlot glyph;
if (nominal)
*nominal = YES;
if (g == NSControlGlyph || prev == NSControlGlyph)
return NSZeroPoint;
if (FTC_Manager_Lookup_Size(ftc_manager, &imgd.font, &face, 0))
return NSZeroPoint;
if (FT_Load_Glyph(face, prev, FT_LOAD_DEFAULT))
return NSZeroPoint;
glyph = face->glyph;
a = NSMakePoint(glyph->advance.x / 64.0, glyph->advance.y / 64.0);
if (FT_Get_Kerning(face, prev, g, ft_kerning_default, &vec))
return a;
if (vec.x == 0 && vec.y == 0)
return a;
if (nominal)
*nominal = NO;
a.x += vec.x / 64.0;
a.y += vec.y / 64.0;
return a;
}
- (float) widthOfString: (NSString*)string
{
unichar ch;
@ -1958,3 +2313,212 @@ static int filters[3][7]=
@end
@interface NSFont (backend)
-(NSGlyph) glyphForCharacter: (unichar)ch;
-(NSString *) nameOfGlyph: (NSGlyph)glyph;
@end
@implementation NSFont (backend)
-(NSGlyph) glyphForCharacter: (unichar)ch
{
FTFontInfo *fi=fontInfo;
FTC_CMapDescRec cmap;
cmap.face_id = fi->imgd.font.face_id;
cmap.u.encoding = ft_encoding_unicode;
cmap.type = FTC_CMAP_BY_ENCODING;
return FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, ch);
}
-(NSString *) nameOfGlyph: (NSGlyph)glyph
{
FTFontInfo *fi=fontInfo;
FT_Face face;
char buf[256];
if (FTC_Manager_Lookup_Size(ftc_manager, &fi->imgd.font, &face, 0))
return nil;
if (FT_Get_Glyph_Name(face,glyph,buf,sizeof(buf)))
return nil;
return [NSString stringWithCString: buf]; /* TODO: really cstring? */
}
@end
/*
GSLayoutManager glyph generation code.
*/
#include <AppKit/GSLayoutManager_internal.h>
#include <AppKit/NSTextStorage.h>
@implementation GSLayoutManager (backend)
/*
This is a fairly simple implementation. It will use "ff", "fl", "fi",
"ffl", and "ffi" ligatures if available. If a glyph for a character isn't
available, it will try to decompose it before giving up.
TODO: how should words like "pfffffffffff" be handled?
0066 'f'
0069 'i'
006c 'l'
fb00 'ff'
fb01 'fi'
fb02 'fl'
fb03 'ffi'
fb04 'ffl'
*/
-(unsigned int) _findSafeBreakMovingBackwardFrom: (unsigned int)ch
{
NSString *str=[_textStorage string];
while (ch>0 && [str characterAtIndex: ch-1]=='f')
ch--;
return ch;
}
-(unsigned int) _findSafeBreakMovingForwardFrom: (unsigned int)ch
{
unsigned int l=[_textStorage length];
NSString *str=[_textStorage string];
while (ch<l && [str characterAtIndex: ch]=='f')
ch++;
if (ch<l && ch>0 && [str characterAtIndex: ch-1]=='f')
ch++;
return ch;
}
-(void) _generateGlyphsForRun: (glyph_run_t *)run at: (unsigned int)pos
{
glyph_t *g;
unsigned int glyph_size;
int i,j;
unichar ch,ch2,ch3;
FTFontInfo *fi=[run->font fontInfo];
FTC_CMapDescRec cmap;
NSCharacterSet *cs=[NSCharacterSet controlCharacterSet];
IMP characterIsMember=[cs methodForSelector: @selector(characterIsMember:)];
unsigned int c=run->head.char_length;
unichar buf[c];
// printf("_generateGlyphsForRun: %p %i+%i\n",run,pos,run->head.char_length);
[[_textStorage string] getCharacters: buf
range: NSMakeRange(pos,c)];
cmap.face_id = fi->imgd.font.face_id;
cmap.u.encoding = ft_encoding_unicode;
cmap.type = FTC_CMAP_BY_ENCODING;
/* first guess */
glyph_size=c;
g=run->glyphs=malloc(sizeof(glyph_t)*glyph_size);
memset(g,0,sizeof(glyph_t)*glyph_size);
for (i=j=0;i<c;i++,g++,j++)
{
ch=buf[i];
ch2=ch3=0;
if (i+1<c)
{
ch2=buf[i+1];
if (i+2<c)
ch3=buf[i+2];
}
g->char_offset=i;
if (characterIsMember(cs,@selector(characterIsMember:),ch))
{
g->g=NSControlGlyph;
continue;
}
if (run->ligature>=1)
{
if (ch=='f' && ch2=='f' && ch3=='l' && fi->ligature_ffl)
{
g->g=fi->ligature_ffl;
i+=2;
continue;
}
if (ch=='f' && ch2=='f' && ch3=='i' && fi->ligature_ffi)
{
g->g=fi->ligature_ffi;
i+=2;
continue;
}
if (ch=='f' && ch2=='f' && fi->ligature_ff)
{
g->g=fi->ligature_ff;
i++;
continue;
}
if (ch=='f' && ch2=='i' && fi->ligature_fi)
{
g->g=fi->ligature_fi;
i++;
continue;
}
if (ch=='f' && ch2=='l' && fi->ligature_fl)
{
g->g=fi->ligature_fl;
i++;
continue;
}
}
g->g=FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, ch);
if (!g->g)
{
unichar *decomp;
decomp=uni_is_decomp(ch);
if (decomp)
{
int c=0;
for (;*decomp;decomp++)
{
glyph_size++;
run->glyphs=realloc(run->glyphs,sizeof(glyph_t)*glyph_size);
g=run->glyphs+j;
memset(&run->glyphs[glyph_size-1],0,sizeof(glyph_t));
g->g=FTC_CMapCache_Lookup(ftc_cmapcache, &cmap, *decomp);
if (!g->g)
break;
c++;
g++;
j++;
g->char_offset=i;
}
if (*decomp)
{
g-=c;
j-=c;
g->g=0;
}
else
{
g--;
j--;
}
}
}
}
/* TODO: shrink if necessary */
run->head.glyph_length=j;
}
@end