📄 ftcommon.c
字号:
*pen_x += x_advance + 1;
return FT_Err_Ok;
}
FT_Error
FTDemo_Draw_Slot( FTDemo_Handle* handle,
FTDemo_Display* display,
FT_GlyphSlot slot,
int* pen_x,
int* pen_y )
{
FT_Glyph glyph;
error = FT_Get_Glyph( slot, &glyph );
if ( error )
return error;
error = FTDemo_Draw_Glyph( handle, display, glyph, pen_x, pen_y );
FT_Done_Glyph( glyph );
return error;
}
void
FTDemo_String_Set( FTDemo_Handle* handle,
const unsigned char* string )
{
const unsigned char* p = string;
unsigned long codepoint;
unsigned char in_code;
int expect;
PGlyph glyph = handle->string;
handle->string_length = 0;
codepoint = expect = 0;
while ( *p )
{
in_code = *p++ ;
if ( in_code >= 0xC0 )
{
if ( in_code < 0xE0 ) /* U+0080 - U+07FF */
{
expect = 1;
codepoint = in_code & 0x1F;
}
else if ( in_code < 0xF0 ) /* U+0800 - U+FFFF */
{
expect = 2;
codepoint = in_code & 0x0F;
}
else if ( in_code < 0xF8 ) /* U+10000 - U+10FFFF */
{
expect = 3;
codepoint = in_code & 0x07;
}
continue;
}
else if ( in_code >= 0x80 )
{
--expect;
if ( expect >= 0 )
{
codepoint <<= 6;
codepoint += in_code & 0x3F;
}
if ( expect > 0 )
continue;
expect = 0;
}
else /* ASCII, U+0000 - U+007F */
codepoint = in_code;
if ( handle->encoding != FT_ENCODING_NONE )
glyph->glyph_index = FTDemo_Get_Index( handle, codepoint );
else
glyph->glyph_index = codepoint;
glyph++;
handle->string_length++;
if ( handle->string_length >= MAX_GLYPHS )
break;
}
handle->string_reload = 1;
}
static FT_Error
string_load( FTDemo_Handle* handle )
{
int n;
FT_Size size;
FT_Face face;
FT_Pos prev_rsb_delta = 0;
error = FTDemo_Get_Size( handle, &size );
if ( error )
return error;
face = size->face;
for ( n = 0; n < handle->string_length; n++ )
{
PGlyph glyph = handle->string + n;
/* clear existing image if there is one */
if ( glyph->image )
{
FT_Done_Glyph( glyph->image );
glyph->image = NULL;
}
/* load the glyph and get the image */
if ( !FT_Load_Glyph( face, glyph->glyph_index,
handle->image_type.flags ) &&
!FT_Get_Glyph( face->glyph, &glyph->image ) )
{
FT_Glyph_Metrics* metrics = &face->glyph->metrics;
/* note that in vertical layout, y-positive goes downwards */
glyph->vvector.x = metrics->vertBearingX - metrics->horiBearingX;
glyph->vvector.y = -metrics->vertBearingY - metrics->horiBearingY;
glyph->vadvance.x = 0;
glyph->vadvance.y = -metrics->vertAdvance;
if ( prev_rsb_delta - face->glyph->lsb_delta >= 32 )
glyph->delta = -1 << 6;
else if ( prev_rsb_delta - face->glyph->lsb_delta < -32 )
glyph->delta = 1 << 6;
else
glyph->delta = 0;
}
}
return FT_Err_Ok;
}
FT_Error
string_render_prepare( FTDemo_Handle* handle,
FTDemo_String_Context* sc,
FT_Vector* advances )
{
FT_Face face;
FT_Size size;
PGlyph glyph;
FT_Pos track_kern = 0;
FT_UInt prev_index = 0;
FT_Vector* prev_advance = NULL;
FT_Vector extent = {0, 0};
FT_Int i;
error = FTDemo_Get_Size( handle, &size );
if ( error )
return error;
face = size->face;
if ( !sc->vertical && sc->kerning_degree )
{
FT_Fixed ptsize;
ptsize = FT_MulFix( face->units_per_EM, face->size->metrics.x_scale );
if ( FT_Get_Track_Kerning( face, ptsize << 10,
-sc->kerning_degree,
&track_kern ) )
track_kern = 0;
else
track_kern >>= 10;
}
for ( i = 0; i < handle->string_length; i++ )
{
glyph = handle->string + i;
if ( !glyph->image )
continue;
if ( sc->vertical )
advances[i] = glyph->vadvance;
else
{
advances[i] = glyph->image->advance;
advances[i].x >>= 10;
advances[i].y >>= 10;
if ( prev_advance )
{
prev_advance->x += track_kern;
if ( sc->kerning_mode )
{
FT_Vector kern;
FT_Get_Kerning( face, prev_index, glyph->glyph_index,
FT_KERNING_UNFITTED, &kern );
prev_advance->x += kern.x;
prev_advance->y += kern.y;
if ( sc->kerning_mode > KERNING_MODE_NORMAL )
prev_advance->x += glyph->delta;
}
}
}
if ( prev_advance )
{
if ( handle->hinted )
{
prev_advance->x = ROUND( prev_advance->x );
prev_advance->y = ROUND( prev_advance->y );
}
extent.x += prev_advance->x;
extent.y += prev_advance->y;
}
prev_index = glyph->glyph_index;
prev_advance = advances + i;
}
if ( prev_advance )
{
if ( handle->hinted )
{
prev_advance->x = ROUND( prev_advance->x );
prev_advance->y = ROUND( prev_advance->y );
}
extent.x += prev_advance->x;
extent.y += prev_advance->y;
/*store the extent in the last slot */
i = handle->string_length - 1;
advances[i] = extent;
}
return FT_Err_Ok;
}
static void
gamma_ramp_apply( FT_Byte gamma_ramp[256],
grBitmap* bitmap )
{
int i, j;
FT_Byte* p = (FT_Byte*)bitmap->buffer;
if ( bitmap->pitch < 0 )
p += -bitmap->pitch * ( bitmap->rows - 1 );
for ( i = 0; i < bitmap->rows; i++ )
{
for ( j = 0; j < bitmap->width; j++ )
p[j] = gamma_ramp[p[j]];
p += bitmap->pitch;
}
}
FT_Error
FTDemo_String_Draw( FTDemo_Handle* handle,
FTDemo_Display* display,
FTDemo_String_Context* sc,
int x,
int y )
{
int n;
FT_Vector pen, advances[MAX_GLYPHS];
FT_Size size;
FT_Face face;
if ( !sc ||
x < 0 ||
y < 0 ||
x > display->bitmap->width ||
y > display->bitmap->rows )
return FT_Err_Invalid_Argument;
error = FTDemo_Get_Size( handle, &size );
if ( error )
return error;
face = size->face;
if ( handle->string_reload )
{
error = string_load( handle );
if ( error )
return error;
handle->string_reload = 0;
}
error = string_render_prepare( handle, sc, advances );
if ( error )
return error;
/* change to Cartesian coordinates */
y = display->bitmap->rows - y;
/* get the extent, which we store in the last slot */
pen = advances[handle->string_length - 1];
pen.x = FT_MulFix( pen.x, sc->center );
pen.y = FT_MulFix( pen.y, sc->center );
/* XXX sbits */
/* get pen position */
if ( sc->matrix && FT_IS_SCALABLE( face ) )
{
FT_Vector_Transform( &pen, sc->matrix );
pen.x = ( x << 6 ) - pen.x;
pen.y = ( y << 6 ) - pen.y;
}
else
{
pen.x = ROUND( ( x << 6 ) - pen.x );
pen.y = ROUND( ( y << 6 ) - pen.y );
}
for ( n = 0; n < handle->string_length; n++ )
{
PGlyph glyph = handle->string + n;
FT_Glyph image;
FT_BBox bbox;
if ( !glyph->image )
continue;
/* copy image */
error = FT_Glyph_Copy( glyph->image, &image );
if ( error )
continue;
if ( image->format != FT_GLYPH_FORMAT_BITMAP )
{
if ( sc->vertical )
error = FT_Glyph_Transform( image, NULL, &glyph->vvector );
if ( !error )
error = FT_Glyph_Transform( image, sc->matrix, &pen );
if ( error )
{
FT_Done_Glyph( image );
continue;
}
}
else
{
FT_BitmapGlyph bitmap = (FT_BitmapGlyph)image;
if ( sc->vertical )
{
bitmap->left += ( glyph->vvector.x + pen.x ) >> 6;
bitmap->top += ( glyph->vvector.x + pen.y ) >> 6;
}
else
{
bitmap->left += pen.x >> 6;
bitmap->top += pen.y >> 6;
}
}
if ( sc->matrix )
FT_Vector_Transform( advances + n, sc->matrix );
pen.x += advances[n].x;
pen.y += advances[n].y;
FT_Glyph_Get_CBox( image, FT_GLYPH_BBOX_PIXELS, &bbox );
#if 0
if ( n == 0 )
{
fprintf( stderr, "bbox = [%ld %ld %ld %ld]\n",
bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax );
}
#endif
/* check bounding box; if it is completely outside the */
/* display surface, we don't need to render it */
if ( bbox.xMax > 0 &&
bbox.yMax > 0 &&
bbox.xMin < display->bitmap->width &&
bbox.yMin < display->bitmap->rows )
{
int left, top, dummy1, dummy2;
grBitmap bit3;
FT_Glyph glyf;
error = FTDemo_Glyph_To_Bitmap( handle, image, &bit3, &left, &top,
&dummy1, &dummy2, &glyf );
if ( !error )
{
if ( sc->gamma_ramp )
gamma_ramp_apply( sc->gamma_ramp, &bit3 );
/* change back to the usual coordinates */
top = display->bitmap->rows - top;
/* now render the bitmap into the display surface */
grBlitGlyphToBitmap( display->bitmap, &bit3, left, top,
display->fore_color );
if ( glyf )
FT_Done_Glyph( glyf );
}
}
FT_Done_Glyph( image );
}
return error;
}
FT_Encoding
FTDemo_Make_Encoding_Tag( const char* s )
{
int i;
unsigned long l = 0;
for ( i = 0; i < 4; i++ )
{
if ( !s[i] )
break;
l <<= 8;
l += (unsigned long)s[i];
}
return (FT_Encoding)l;
}
/* End */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -