/* transform a given glyph image */ static FT_Error ft_raster1_transform(FT_Renderer render, FT_GlyphSlot slot, FT_Matrix *matrix, FT_Vector *delta) { FT_Error error = FT_Err_Ok; if(slot->format != render->glyph_format) { error = FT_Err_Invalid_Argument; goto Exit; } if(matrix) { FT_Outline_Transform(&slot->outline, matrix); } if(delta) { FT_Outline_Translate(&slot->outline, delta->x, delta->y); } Exit: return error; }
static void ft_outline_glyph_transform( FT_OutlineGlyph glyph, FT_Matrix* matrix, FT_Vector* delta ) { if ( matrix ) FT_Outline_Transform( &glyph->outline, matrix ); if ( delta ) FT_Outline_Translate( &glyph->outline, delta->x, delta->y ); }
static FT_Error LoadTrueTypeChar(Font *fnt, int idx, Boolean hint, Boolean quiet) { FT_Error error; int flags; flags = FT_LOAD_DEFAULT; if (hint) flags |= FT_LOAD_FORCE_AUTOHINT; error = FT_Load_Glyph(face, idx, flags); if (!error) { if (fnt->efactor != 1.0 || fnt->slant != 0.0 ) FT_Outline_Transform(&face->glyph->outline, &matrix1); if (fnt->rotate) { FT_Outline_Transform(&face->glyph->outline, &matrix2); error = FT_Outline_Get_BBox(&face->glyph->outline, &bbox); /* we need the non- grid-fitted bbox */ if (!error) FT_Outline_Translate(&face->glyph->outline, face->glyph->metrics.vertBearingY - bbox.xMin, -fnt->y_offset * ppem * 64); } } if (!error) error = FT_Outline_Get_BBox(&face->glyph->outline, &bbox); if (!error) { FT_Outline_Get_CBox(&face->glyph->outline, &bbox); /* for the case of BBox != CBox */ SetRasterArea(quiet); } return error; }
ft_outline_glyph_transform( FT_Glyph outline_glyph, const FT_Matrix* matrix, const FT_Vector* delta ) { FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; if ( matrix ) FT_Outline_Transform( &glyph->outline, matrix ); if ( delta ) FT_Outline_Translate( &glyph->outline, delta->x, delta->y ); }
void FT_ITALIC(FT_GlyphSlot slot) { FT_Matrix transform; FT_Outline* outline = &slot->outline; /* only oblique outline glyphs */ if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) return; /* we don't touch the advance width */ /* For italic, simply apply a shear transform, with an angle */ /* of about 12 degrees. */ transform.xx = 0x10000L; transform.yx = 0x00000L; transform.xy = 0x03000L; transform.yy = 0x10000L; FT_Outline_Transform( outline, &transform ); }
const bool GDI2FT_RENDERER::generate_outline_glyph( FT_Glyph* glyph, WORD glyph_index, const FTC_Scaler scaler, FT_F26Dot6 embolden, bool is_italic ) const /* -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- */ { FT_Glyph cached_glyph; { GDI2FT_MUTEX mutex( GDI2FT_MUTEX::MUTEX_FREETYPE ); if( FTC_ImageCache_LookupScaler( ft_glyph_cache, scaler, FT_LOAD_NO_BITMAP | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_CROP_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_TARGET_LIGHT, glyph_index, &cached_glyph, NULL ) != 0 ) return NULL; } if( cached_glyph->format != FT_GLYPH_FORMAT_OUTLINE ) return NULL; const bool oblique = ( ( context->outline_metrics->otmTextMetrics.tmItalic != 0 ) && !is_italic ); if( oblique || embolden ) { FT_Glyph_Copy( cached_glyph, glyph ); FT_Outline* glyph_outline = &( reinterpret_cast<FT_OutlineGlyph>( *glyph )->outline ); if( oblique ) { FT_Matrix oblique_mat = { static_cast<FT_Pos>( 65536 ), static_cast<FT_Pos>( 19661 ), 0, static_cast<FT_Pos>( 65536 ) }; FT_Outline_Transform( glyph_outline, &oblique_mat ); } if( embolden ) FT_Outline_Embolden( glyph_outline, embolden ); return true; } else *glyph = cached_glyph; return false; }
static PyObject* Py_Outline_transform(Py_Outline* self, PyObject* args, PyObject* kwds) { double xx, xy, yx, yy; FT_Matrix matrix; const char* keywords[] = {"xOffset", "yOffset", NULL}; if (!PyArg_ParseTupleAndKeywords( args, kwds, "((dd)(dd)):transform", (char **)keywords, &xx, &xy, &yx, &yy)) { return NULL; } matrix.xx = TO_FT_FIXED(xx); matrix.xy = TO_FT_FIXED(xy); matrix.yx = TO_FT_FIXED(yx); matrix.yy = TO_FT_FIXED(yy); FT_Outline_Transform(&self->x, &matrix); Py_RETURN_NONE; };
/* transform a given glyph image */ static FT_Error ft_smooth_transform( FT_Renderer render, FT_GlyphSlot slot, const FT_Matrix* matrix, const FT_Vector* delta ) { FT_Error error = FT_Err_Ok; if ( slot->format != render->glyph_format ) { error = FT_THROW( Invalid_Argument ); goto Exit; } if ( matrix ) FT_Outline_Transform( &slot->outline, matrix ); if ( delta ) FT_Outline_Translate( &slot->outline, delta->x, delta->y ); Exit: return error; }
static FT_Error af_loader_load_g( AF_Loader loader, AF_Scaler scaler, FT_UInt glyph_index, FT_Int32 load_flags, FT_UInt depth ) { FT_Error error; FT_Face face = loader->face; FT_GlyphLoader gloader = loader->gloader; AF_ScriptMetrics metrics = loader->metrics; AF_GlyphHints hints = &loader->hints; FT_GlyphSlot slot = face->glyph; FT_Slot_Internal internal = slot->internal; FT_Int32 flags; flags = load_flags | FT_LOAD_LINEAR_DESIGN; error = FT_Load_Glyph( face, glyph_index, flags ); if ( error ) goto Exit; loader->transformed = internal->glyph_transformed; if ( loader->transformed ) { FT_Matrix inverse; loader->trans_matrix = internal->glyph_matrix; loader->trans_delta = internal->glyph_delta; inverse = loader->trans_matrix; FT_Matrix_Invert( &inverse ); FT_Vector_Transform( &loader->trans_delta, &inverse ); } switch ( slot->format ) { case FT_GLYPH_FORMAT_OUTLINE: /* translate the loaded glyph when an internal transform is needed */ if ( loader->transformed ) FT_Outline_Translate( &slot->outline, loader->trans_delta.x, loader->trans_delta.y ); /* copy the outline points in the loader's current */ /* extra points which are used to keep original glyph coordinates */ error = FT_GLYPHLOADER_CHECK_POINTS( gloader, slot->outline.n_points + 4, slot->outline.n_contours ); if ( error ) goto Exit; FT_ARRAY_COPY( gloader->current.outline.points, slot->outline.points, slot->outline.n_points ); FT_ARRAY_COPY( gloader->current.outline.contours, slot->outline.contours, slot->outline.n_contours ); FT_ARRAY_COPY( gloader->current.outline.tags, slot->outline.tags, slot->outline.n_points ); gloader->current.outline.n_points = slot->outline.n_points; gloader->current.outline.n_contours = slot->outline.n_contours; /* compute original horizontal phantom points (and ignore */ /* vertical ones) */ loader->pp1.x = hints->x_delta; loader->pp1.y = hints->y_delta; loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, hints->x_scale ) + hints->x_delta; loader->pp2.y = hints->y_delta; /* be sure to check for spacing glyphs */ if ( slot->outline.n_points == 0 ) goto Hint_Metrics; /* now load the slot image into the auto-outline and run the */ /* automatic hinting process */ if ( metrics->clazz->script_hints_apply ) metrics->clazz->script_hints_apply( hints, &gloader->current.outline, metrics ); /* we now need to adjust the metrics according to the change in */ /* width/positioning that occurred during the hinting process */ if ( scaler->render_mode != FT_RENDER_MODE_LIGHT ) { FT_Pos old_rsb, old_lsb, new_lsb; FT_Pos pp1x_uh, pp2x_uh; AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ]; AF_Edge edge1 = axis->edges; /* leftmost edge */ AF_Edge edge2 = edge1 + axis->num_edges - 1; /* rightmost edge */ if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) { old_rsb = loader->pp2.x - edge2->opos; old_lsb = edge1->opos; new_lsb = edge1->pos; /* remember unhinted values to later account */ /* for rounding errors */ pp1x_uh = new_lsb - old_lsb; pp2x_uh = edge2->pos + old_rsb; /* prefer too much space over too little space */ /* for very small sizes */ if ( old_lsb < 24 ) pp1x_uh -= 8; if ( old_rsb < 24 ) pp2x_uh += 8; loader->pp1.x = FT_PIX_ROUND( pp1x_uh ); loader->pp2.x = FT_PIX_ROUND( pp2x_uh ); if ( loader->pp1.x >= new_lsb && old_lsb > 0 ) loader->pp1.x -= 64; if ( loader->pp2.x <= edge2->pos && old_rsb > 0 ) loader->pp2.x += 64; slot->lsb_delta = loader->pp1.x - pp1x_uh; slot->rsb_delta = loader->pp2.x - pp2x_uh; } else { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; loader->pp1.x = FT_PIX_ROUND( pp1x ); loader->pp2.x = FT_PIX_ROUND( pp2x ); slot->lsb_delta = loader->pp1.x - pp1x; slot->rsb_delta = loader->pp2.x - pp2x; } } else { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta ); loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta ); slot->lsb_delta = loader->pp1.x - pp1x; slot->rsb_delta = loader->pp2.x - pp2x; } /* good, we simply add the glyph to our loader's base */ FT_GlyphLoader_Add( gloader ); break; case FT_GLYPH_FORMAT_COMPOSITE: { FT_UInt nn, num_subglyphs = slot->num_subglyphs; FT_UInt num_base_subgs, start_point; FT_SubGlyph subglyph; start_point = gloader->base.outline.n_points; /* first of all, copy the subglyph descriptors in the glyph loader */ error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs ); if ( error ) goto Exit; FT_ARRAY_COPY( gloader->current.subglyphs, slot->subglyphs, num_subglyphs ); gloader->current.num_subglyphs = num_subglyphs; num_base_subgs = gloader->base.num_subglyphs; /* now read each subglyph independently */ for ( nn = 0; nn < num_subglyphs; nn++ ) { FT_Vector pp1, pp2; FT_Pos x, y; FT_UInt num_points, num_new_points, num_base_points; /* gloader.current.subglyphs can change during glyph loading due */ /* to re-allocation -- we must recompute the current subglyph on */ /* each iteration */ subglyph = gloader->base.subglyphs + num_base_subgs + nn; pp1 = loader->pp1; pp2 = loader->pp2; num_base_points = gloader->base.outline.n_points; error = af_loader_load_g( loader, scaler, subglyph->index, load_flags, depth + 1 ); if ( error ) goto Exit; /* recompute subglyph pointer */ subglyph = gloader->base.subglyphs + num_base_subgs + nn; if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS ) { pp1 = loader->pp1; pp2 = loader->pp2; } else { loader->pp1 = pp1; loader->pp2 = pp2; } num_points = gloader->base.outline.n_points; num_new_points = num_points - num_base_points; /* now perform the transformation required for this subglyph */ if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE | FT_SUBGLYPH_FLAG_XY_SCALE | FT_SUBGLYPH_FLAG_2X2 ) ) { FT_Vector* cur = gloader->base.outline.points + num_base_points; FT_Vector* limit = cur + num_new_points; for ( ; cur < limit; cur++ ) FT_Vector_Transform( cur, &subglyph->transform ); } /* apply offset */ if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) ) { FT_Int k = subglyph->arg1; FT_UInt l = subglyph->arg2; FT_Vector* p1; FT_Vector* p2; if ( start_point + k >= num_base_points || l >= (FT_UInt)num_new_points ) { error = AF_Err_Invalid_Composite; goto Exit; } l += num_base_points; /* for now, only use the current point coordinates; */ /* we eventually may consider another approach */ p1 = gloader->base.outline.points + start_point + k; p2 = gloader->base.outline.points + start_point + l; x = p1->x - p2->x; y = p1->y - p2->y; } else { x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta; y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta; x = FT_PIX_ROUND( x ); y = FT_PIX_ROUND( y ); } { FT_Outline dummy = gloader->base.outline; dummy.points += num_base_points; dummy.n_points = (short)num_new_points; FT_Outline_Translate( &dummy, x, y ); } } } break; default: /* we don't support other formats (yet?) */ error = AF_Err_Unimplemented_Feature; } Hint_Metrics: if ( depth == 0 ) { FT_BBox bbox; FT_Vector vvector; vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX; vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY; vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale ); vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale ); /* transform the hinted outline if needed */ if ( loader->transformed ) { FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix ); FT_Vector_Transform( &vvector, &loader->trans_matrix ); } #if 1 /* we must translate our final outline by -pp1.x and compute */ /* the new metrics */ if ( loader->pp1.x ) FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 ); #endif FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); bbox.xMax = FT_PIX_CEIL( bbox.xMax ); bbox.yMax = FT_PIX_CEIL( bbox.yMax ); slot->metrics.width = bbox.xMax - bbox.xMin; slot->metrics.height = bbox.yMax - bbox.yMin; slot->metrics.horiBearingX = bbox.xMin; slot->metrics.horiBearingY = bbox.yMax; slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x ); slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y ); /* for mono-width fonts (like Andale, Courier, etc.) we need */ /* to keep the original rounded advance width; ditto for */ /* digits if all have the same advance width */ #if 0 if ( !FT_IS_FIXED_WIDTH( slot->face ) ) slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; else slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, x_scale ); #else if ( scaler->render_mode != FT_RENDER_MODE_LIGHT && ( FT_IS_FIXED_WIDTH( slot->face ) || ( af_face_globals_is_digit( loader->globals, glyph_index ) && metrics->digits_have_same_width ) ) ) { slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, metrics->scaler.x_scale ); /* Set delta values to 0. Otherwise code that uses them is */ /* going to ruin the fixed advance width. */ slot->lsb_delta = 0; slot->rsb_delta = 0; } else { /* non-spacing glyphs must stay as-is */ if ( slot->metrics.horiAdvance ) slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; } #endif slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance, metrics->scaler.y_scale ); slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance ); /* now copy outline into glyph slot */ FT_GlyphLoader_Rewind( internal->loader ); error = FT_GlyphLoader_CopyPoints( internal->loader, gloader ); if ( error ) goto Exit; /* reassign all outline fields except flags to protect them */ slot->outline.n_contours = internal->loader->base.outline.n_contours; slot->outline.n_points = internal->loader->base.outline.n_points; slot->outline.points = internal->loader->base.outline.points; slot->outline.tags = internal->loader->base.outline.tags; slot->outline.contours = internal->loader->base.outline.contours; slot->format = FT_GLYPH_FORMAT_OUTLINE; } Exit: return error; }
static FT_Error Load_Glyph( TTF_Font* font, Uint16 ch, c_glyph* cached, int want ) { FT_Face face; FT_Error error; FT_GlyphSlot glyph; FT_Glyph_Metrics* metrics; FT_Outline* outline; if ( !font || !font->face ) { return FT_Err_Invalid_Handle; } face = font->face; /* Load the glyph */ if ( ! cached->index ) { cached->index = FT_Get_Char_Index( face, ch ); } error = FT_Load_Glyph( face, cached->index, FT_LOAD_DEFAULT ); if( error ) { return error; } /* Get our glyph shortcuts */ glyph = face->glyph; metrics = &glyph->metrics; outline = &glyph->outline; /* Get the glyph metrics if desired */ if ( (want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS) ) { if ( FT_IS_SCALABLE( face ) ) { /* Get the bounding box */ cached->minx = FT_FLOOR(metrics->horiBearingX); cached->maxx = cached->minx + FT_CEIL(metrics->width); cached->maxy = FT_FLOOR(metrics->horiBearingY); cached->miny = cached->maxy - FT_CEIL(metrics->height); cached->yoffset = font->ascent - cached->maxy; cached->advance = FT_CEIL(metrics->horiAdvance); } else { /* Get the bounding box for non-scalable format. * Again, freetype2 fills in many of the font metrics * with the value of 0, so some of the values we * need must be calculated differently with certain * assumptions about non-scalable formats. * */ cached->minx = FT_FLOOR(metrics->horiBearingX); cached->maxx = cached->minx + FT_CEIL(metrics->horiAdvance); cached->maxy = FT_FLOOR(metrics->horiBearingY); cached->miny = cached->maxy - FT_CEIL(face->available_sizes[font->font_size_family].height); cached->yoffset = 0; cached->advance = FT_CEIL(metrics->horiAdvance); } /* Adjust for bold and italic text */ if( font->style & TTF_STYLE_BOLD ) { cached->maxx += font->glyph_overhang; } if( font->style & TTF_STYLE_ITALIC ) { cached->maxx += (int)ceil(font->glyph_italics); } cached->stored |= CACHED_METRICS; } if ( ((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) || ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)) ) { int mono = (want & CACHED_BITMAP); int i; FT_Bitmap* src; FT_Bitmap* dst; /* Handle the italic style */ if( font->style & TTF_STYLE_ITALIC ) { FT_Matrix shear; shear.xx = 1 << 16; shear.xy = (int) ( font->glyph_italics * ( 1 << 16 ) ) / font->height; shear.yx = 0; shear.yy = 1 << 16; FT_Outline_Transform( outline, &shear ); } /* Render the glyph */ if ( mono ) { error = FT_Render_Glyph( glyph, ft_render_mode_mono ); } else { error = FT_Render_Glyph( glyph, ft_render_mode_normal ); } if( error ) { return error; } /* Copy over information to cache */ src = &glyph->bitmap; if ( mono ) { dst = &cached->bitmap; } else { dst = &cached->pixmap; } memcpy( dst, src, sizeof( *dst ) ); /* FT_Render_Glyph() and .fon fonts always generate a * two-color (black and white) glyphslot surface, even * when rendered in ft_render_mode_normal. */ /* FT_IS_SCALABLE() means that the font is in outline format, * but does not imply that outline is rendered as 8-bit * grayscale, because embedded bitmap/graymap is preferred * (see FT_LOAD_DEFAULT section of FreeType2 API Reference). * FT_Render_Glyph() canreturn two-color bitmap or 4/16/256- * color graymap according to the format of embedded bitmap/ * graymap. */ if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ) { dst->pitch *= 8; } else if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY2 ) { dst->pitch *= 4; } else if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY4 ) { dst->pitch *= 2; } /* Adjust for bold and italic text */ if( font->style & TTF_STYLE_BOLD ) { int bump = font->glyph_overhang; dst->pitch += bump; dst->width += bump; } if( font->style & TTF_STYLE_ITALIC ) { int bump = (int)ceil(font->glyph_italics); dst->pitch += bump; dst->width += bump; } if (dst->rows != 0) { dst->buffer = (unsigned char *)malloc( dst->pitch * dst->rows ); if( !dst->buffer ) { return FT_Err_Out_Of_Memory; } memset( dst->buffer, 0, dst->pitch * dst->rows ); for( i = 0; i < src->rows; i++ ) { int soffset = i * src->pitch; int doffset = i * dst->pitch; if ( mono ) { unsigned char *srcp = src->buffer + soffset; unsigned char *dstp = dst->buffer + doffset; int j; if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ) { for ( j = 0; j < src->width; j += 8 ) { unsigned char ch = *srcp++; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; } } else if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY2 ) { for ( j = 0; j < src->width; j += 4 ) { unsigned char ch = *srcp++; *dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0; ch <<= 2; *dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0; ch <<= 2; *dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0; ch <<= 2; *dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0; } } else if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY4 ) { for ( j = 0; j < src->width; j += 2 ) { unsigned char ch = *srcp++; *dstp++ = (((ch&0xF0) >> 4) >= 0x8) ? 1 : 0; ch <<= 4; *dstp++ = (((ch&0xF0) >> 4) >= 0x8) ? 1 : 0; } } else { for ( j = 0; j < src->width; j++ ) {
FT_LOCAL_DEF FT_Error CID_Load_Glyph( CID_GlyphSlot glyph, CID_Size size, FT_Int glyph_index, FT_Int load_flags ) { FT_Error error; T1_Decoder decoder; CID_Face face = (CID_Face)glyph->root.face; FT_Bool hinting; PSAux_Interface* psaux = (PSAux_Interface*)face->psaux; FT_Matrix font_matrix; FT_Vector font_offset; if ( load_flags & FT_LOAD_NO_RECURSE ) load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; glyph->x_scale = size->root.metrics.x_scale; glyph->y_scale = size->root.metrics.y_scale; glyph->root.outline.n_points = 0; glyph->root.outline.n_contours = 0; hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 && ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); glyph->root.format = ft_glyph_format_outline; { error = psaux->t1_decoder_funcs->init( &decoder, (FT_Face)face, (FT_Size)size, (FT_GlyphSlot)glyph, 0, /* glyph names -- XXX */ 0, /* blend == 0 */ hinting, cid_load_glyph ); /* set up the decoder */ decoder.builder.no_recurse = FT_BOOL( ( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ) ); error = cid_load_glyph( &decoder, glyph_index ); font_matrix = decoder.font_matrix; font_offset = decoder.font_offset; /* save new glyph tables */ psaux->t1_decoder_funcs->done( &decoder ); } /* now, set the metrics -- this is rather simple, as */ /* the left side bearing is the xMin, and the top side */ /* bearing the yMax */ if ( !error ) { glyph->root.outline.flags &= ft_outline_owner; glyph->root.outline.flags |= ft_outline_reverse_fill; /* for composite glyphs, return only left side bearing and */ /* advance width */ if ( load_flags & FT_LOAD_NO_RECURSE ) { FT_Slot_Internal internal = glyph->root.internal; glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; glyph->root.metrics.horiAdvance = decoder.builder.advance.x; internal->glyph_matrix = font_matrix; internal->glyph_delta = font_offset; internal->glyph_transformed = 1; } else { FT_BBox cbox; FT_Glyph_Metrics* metrics = &glyph->root.metrics; /* copy the _unscaled_ advance width */ metrics->horiAdvance = decoder.builder.advance.x; glyph->root.linearHoriAdvance = decoder.builder.advance.x; glyph->root.internal->glyph_transformed = 0; /* make up vertical metrics */ metrics->vertBearingX = 0; metrics->vertBearingY = 0; metrics->vertAdvance = 0; glyph->root.linearVertAdvance = 0; glyph->root.format = ft_glyph_format_outline; if ( size && size->root.metrics.y_ppem < 24 ) glyph->root.outline.flags |= ft_outline_high_precision; /* apply the font matrix */ FT_Outline_Transform( &glyph->root.outline, &font_matrix ); FT_Outline_Translate( &glyph->root.outline, font_offset.x, font_offset.y ); if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) { /* scale the outline and the metrics */ FT_Int n; FT_Outline* cur = decoder.builder.base; FT_Vector* vec = cur->points; FT_Fixed x_scale = glyph->x_scale; FT_Fixed y_scale = glyph->y_scale; /* First of all, scale the points */ if ( !hinting ) for ( n = cur->n_points; n > 0; n--, vec++ ) { vec->x = FT_MulFix( vec->x, x_scale ); vec->y = FT_MulFix( vec->y, y_scale ); } FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); /* Then scale the metrics */ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale ); metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale ); if ( hinting ) { metrics->horiAdvance = ( metrics->horiAdvance + 32 ) & -64; metrics->vertAdvance = ( metrics->vertAdvance + 32 ) & -64; metrics->vertBearingX = ( metrics->vertBearingX + 32 ) & -64; metrics->vertBearingY = ( metrics->vertBearingY + 32 ) & -64; } } /* compute the other metrics */ FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); /* grid fit the bounding box if necessary */ if ( hinting ) { cbox.xMin &= -64; cbox.yMin &= -64; cbox.xMax = ( cbox.xMax + 63 ) & -64; cbox.yMax = ( cbox.yMax + 63 ) & -64; } metrics->width = cbox.xMax - cbox.xMin; metrics->height = cbox.yMax - cbox.yMin; metrics->horiBearingX = cbox.xMin; metrics->horiBearingY = cbox.yMax; } } return error; }
/* * Class: FreetypeFont * Method: loadGlyph0 * Signature: (JI)V */ JNIEXPORT void JNICALL Java_sage_FreetypeFont_loadGlyph0 (JNIEnv *env, jobject jo, jlong fontPtr, jint glyphCode) { //FT_Face face = (FT_Face) facePtr; FTDataStruct* fontData = (FTDataStruct*)(intptr_t) fontPtr; FT_Activate_Size(fontData->sizePtr); int error = FT_Load_Glyph(fontData->facePtr, glyphCode, FT_LOAD_FORCE_AUTOHINT); if ((fontData->style & FT_STYLE_FLAG_BOLD) != 0) { // Apply bold effect if (fontData->facePtr->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { /* some reasonable strength */ FT_Pos strength = FT_MulFix(fontData->facePtr->units_per_EM, fontData->facePtr->size->metrics.y_scale ) / 42; FT_BBox bbox_before, bbox_after; // The bounding box code was what XBMC was using to do this calculation; but the // examples in the freetype library use the *4 math below which then doesn't clip // the text when we render it. // FT_Outline_Get_CBox(&fontData->facePtr->glyph->outline, &bbox_before); FT_Outline_Embolden(&fontData->facePtr->glyph->outline, strength); // ignore error // FT_Outline_Get_CBox(&fontData->facePtr->glyph->outline, &bbox_after); // FT_Pos dx = bbox_after.xMax - bbox_before.xMax; // FT_Pos dy = bbox_after.yMax - bbox_before.yMax; FT_Pos dx = strength * 4; FT_Pos dy = dx; if (fontData->facePtr->glyph->advance.x) fontData->facePtr->glyph->advance.x += dx; if (fontData->facePtr->glyph->advance.y) fontData->facePtr->glyph->advance.y += dy; fontData->facePtr->glyph->metrics.width += dx; fontData->facePtr->glyph->metrics.height += dy; fontData->facePtr->glyph->metrics.horiBearingY += dy; fontData->facePtr->glyph->metrics.horiAdvance += dx; fontData->facePtr->glyph->metrics.vertBearingX -= dx / 2; fontData->facePtr->glyph->metrics.vertBearingY += dy; fontData->facePtr->glyph->metrics.vertAdvance += dy; } } if ((fontData->style & FT_STYLE_FLAG_ITALIC) != 0) { // Apply italics effect if (fontData->facePtr->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { /* For italic, simply apply a shear transform, with an angle */ /* of about 12 degrees. */ FT_Matrix transform; transform.xx = 0x10000L; transform.yx = 0x00000L; transform.xy = 0x06000L; transform.yy = 0x10000L; FT_BBox bbox_before, bbox_after; FT_Outline_Get_CBox(&fontData->facePtr->glyph->outline, &bbox_before); FT_Outline_Transform(&fontData->facePtr->glyph->outline, &transform); FT_Outline_Get_CBox(&fontData->facePtr->glyph->outline, &bbox_after); FT_Pos dx = bbox_after.xMax - bbox_before.xMax; FT_Pos dy = bbox_after.yMax - bbox_before.yMax; fontData->facePtr->glyph->metrics.width += dx; fontData->facePtr->glyph->metrics.height += dy; } } }
cid_slot_load_glyph( FT_GlyphSlot cidglyph, /* CID_GlyphSlot */ FT_Size cidsize, /* CID_Size */ FT_UInt glyph_index, FT_Int32 load_flags ) { CID_GlyphSlot glyph = (CID_GlyphSlot)cidglyph; FT_Error error; T1_DecoderRec decoder; CID_Face face = (CID_Face)cidglyph->face; FT_Bool hinting; PSAux_Service psaux = (PSAux_Service)face->psaux; FT_Matrix font_matrix; FT_Vector font_offset; if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) { error = CID_Err_Invalid_Argument; goto Exit; } if ( load_flags & FT_LOAD_NO_RECURSE ) load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; glyph->x_scale = cidsize->metrics.x_scale; glyph->y_scale = cidsize->metrics.y_scale; cidglyph->outline.n_points = 0; cidglyph->outline.n_contours = 0; hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 && ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; error = psaux->t1_decoder_funcs->init( &decoder, cidglyph->face, cidsize, cidglyph, 0, /* glyph names -- XXX */ 0, /* blend == 0 */ hinting, FT_LOAD_TARGET_MODE( load_flags ), cid_load_glyph ); if ( error ) goto Exit; /* TODO: initialize decoder.len_buildchar and decoder.buildchar */ /* if we ever support CID-keyed multiple master fonts */ /* set up the decoder */ decoder.builder.no_recurse = FT_BOOL( ( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ) ); error = cid_load_glyph( &decoder, glyph_index ); if ( error ) goto Exit; font_matrix = decoder.font_matrix; font_offset = decoder.font_offset; /* save new glyph tables */ psaux->t1_decoder_funcs->done( &decoder ); /* now set the metrics -- this is rather simple, as */ /* the left side bearing is the xMin, and the top side */ /* bearing the yMax */ cidglyph->outline.flags &= FT_OUTLINE_OWNER; cidglyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; /* for composite glyphs, return only left side bearing and */ /* advance width */ if ( load_flags & FT_LOAD_NO_RECURSE ) { FT_Slot_Internal internal = cidglyph->internal; cidglyph->metrics.horiBearingX = FIXED_TO_INT( decoder.builder.left_bearing.x ); cidglyph->metrics.horiAdvance = FIXED_TO_INT( decoder.builder.advance.x ); internal->glyph_matrix = font_matrix; internal->glyph_delta = font_offset; internal->glyph_transformed = 1; } else { FT_BBox cbox; FT_Glyph_Metrics* metrics = &cidglyph->metrics; FT_Vector advance; /* copy the _unscaled_ advance width */ metrics->horiAdvance = FIXED_TO_INT( decoder.builder.advance.x ); cidglyph->linearHoriAdvance = FIXED_TO_INT( decoder.builder.advance.x ); cidglyph->internal->glyph_transformed = 0; /* make up vertical ones */ metrics->vertAdvance = ( face->cid.font_bbox.yMax - face->cid.font_bbox.yMin ) >> 16; cidglyph->linearVertAdvance = metrics->vertAdvance; cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; if ( cidsize->metrics.y_ppem < 24 ) cidglyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; /* apply the font matrix */ FT_Outline_Transform( &cidglyph->outline, &font_matrix ); FT_Outline_Translate( &cidglyph->outline, font_offset.x, font_offset.y ); advance.x = metrics->horiAdvance; advance.y = 0; FT_Vector_Transform( &advance, &font_matrix ); metrics->horiAdvance = advance.x + font_offset.x; advance.x = 0; advance.y = metrics->vertAdvance; FT_Vector_Transform( &advance, &font_matrix ); metrics->vertAdvance = advance.y + font_offset.y; if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) { /* scale the outline and the metrics */ FT_Int n; FT_Outline* cur = decoder.builder.base; FT_Vector* vec = cur->points; FT_Fixed x_scale = glyph->x_scale; FT_Fixed y_scale = glyph->y_scale; /* First of all, scale the points */ if ( !hinting || !decoder.builder.hints_funcs ) for ( n = cur->n_points; n > 0; n--, vec++ ) { vec->x = FT_MulFix( vec->x, x_scale ); vec->y = FT_MulFix( vec->y, y_scale ); } /* Then scale the metrics */ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); } /* compute the other metrics */ FT_Outline_Get_CBox( &cidglyph->outline, &cbox ); metrics->width = cbox.xMax - cbox.xMin; metrics->height = cbox.yMax - cbox.yMin; metrics->horiBearingX = cbox.xMin; metrics->horiBearingY = cbox.yMax; if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) { /* make up vertical ones */ ft_synthesize_vertical_metrics( metrics, metrics->vertAdvance ); } } Exit: return error; }
/** * Renders or Measures some Text * * @param aContext void context * @param aBitmap pointer to bitmap ( if not provided will just measure ) * @param aBitmapWidth width of the provided bitmap * @param aBitmapHeight height of the provided bitmap * @param aHarfBuzz Harfbuzz structure containing glyph indices * @param aIndex start with this character index * @param aCount render / measure aCount characters * @param aPen_x pointer to pen position that will be updated ( optional ) * @param aPen_y pointer to pen position that will be updated ( optional ) * @param aBBox pointer to Bounding Box that will be updated ( optional ) * @param resetBox if non-zero´Bounding Box will be reset before accumulating * @param isArabic if non-zero will treat as right to left * @param outlineStage 0 = draw ouside, 1 = draw inside of synth outline style */ static int PalFont_RenderHarfBuzz( void *aContext, unsigned int *aBitmap, int aBitmapWidth, int aBitmapHeight, HarfBuzz_t *aHarfBuzz, int aIndex, int aLength, int *aPen_x, int *aPen_y, PalFont_BBox_t*aBBox, int resetBox, int isArabic, int outlineStage ) { printf("PalFont_RenderHarfBuzz: context is %p\n", aContext); ft_Context_t *ftContext = FT_CONTEXT( aContext ); FT_GlyphSlot slot; PalFont_BBox_t theBBox; unsigned int i, j = outlineStage, k; int thePen_x = 0; int thePen_y = 0; FT_UInt aGlyphIndex = 0; FT_UInt aPrevGlyphIndex = 0; if ( ftContext == NULL ) { return -1; } if ( aPen_x != NULL ) { thePen_x = *aPen_x; } if ( aPen_y != NULL ) { thePen_y = *aPen_y; } slot = ftContext->m_face->glyph; if ( resetBox != 0 ) { /* make an invalid bounding box to start with */ theBBox.xMin = INT_MAX; theBBox.yMin = INT_MAX; theBBox.xMax = INT_MIN; theBBox.yMax = INT_MIN; } for ( i = 0; i < aHarfBuzz->n_Chars; thePen_x += ( int )( ( ( double )ftContext->m_Matrix.xx * ( double )slot->advance.x + ( double )ftContext->m_Matrix.xy * ( double )slot->advance.y ) / 65536.0 ), thePen_y += ( int )( ( ( double )ftContext->m_Matrix.yy * ( double )slot->advance.y + ( double )ftContext->m_Matrix.yx * ( double )slot->advance.x ) / 65536.0 ), aPrevGlyphIndex = aGlyphIndex, i++ ) { FT_Glyph aGlyph; int y; int x; k = isArabic ? ( aHarfBuzz->n_Chars - i - 1 ) : i; aGlyphIndex = aHarfBuzz->out_glyphs[ k ]; /* apply kerning if there is any */ if ( aPrevGlyphIndex != 0 && aGlyphIndex != 0 ) { FT_Vector delta; /* ignore errors */ if ( FT_Get_Kerning( ftContext->m_face, aPrevGlyphIndex, aGlyphIndex, FT_KERNING_DEFAULT, &delta ) == 0 ) { thePen_x += ( int )( ( ( double )ftContext->m_Matrix.xx * ( double )delta.x ) / ( 65536.0 ) ); } } /* load glyph image into the slot (erase previous one) */ if ( FT_Load_Glyph( ftContext->m_face, aGlyphIndex, FT_LOAD_DEFAULT ) != 0 ) { continue; /* ignore errors */ } // if we are synthesising italic then shear outline if ( ftContext->m_Synth & SynthItalic ) { FT_Matrix m; m.xx = 65536; m.yy = 65536; m.xy = 19660; m.yx = 0; FT_Outline_Transform( &slot->outline, &m ); } /* if we are doing first pass of two color then fatten */ if ( ( ftContext->m_Synth & SynthTwoColor ) && j == 0 ) { if ( FT_Outline_Embolden( &slot->outline, ftContext->m_StrokeWidth << 2 ) != 0 ) { continue; } } // if we are doing second pass of two color then translate if ( ( ftContext->m_Synth & SynthTwoColor ) && j == 1 ) { FT_Outline_Translate( &slot->outline, ftContext->m_StrokeWidth * 2, ftContext->m_StrokeWidth * 2 ); } /* if we are synthesising bold then perform fattening operation */ if ( ftContext->m_Synth & SynthBold ) { if ( FT_Outline_Embolden( &slot->outline, ftContext->m_Boldness << 1 ) != 0 ) { continue; } } /* if we are synthesising stroke font then stroke it */ if ( ftContext->m_Synth & SynthStroke ) { if ( ft_OutlineStroke( ftContext->m_library, &slot->outline, ftContext->m_StrokeWidth ) != 0 ) { continue; } } FT_Outline_Transform( &slot->outline, &ftContext->m_Matrix ); /* if bounding box is supplied then accumulate the glyphs bounding boxes */ if ( aBBox != NULL ) { FT_BBox theCBox; FT_Outline_Get_CBox( &slot->outline, &theCBox ); theCBox.xMin += thePen_x; theCBox.xMax += thePen_x; theCBox.yMin += thePen_y; theCBox.yMax += thePen_y; if ( theCBox.xMin < theBBox.xMin ) { theBBox.xMin = theCBox.xMin; } if ( theCBox.yMin < theBBox.yMin ) { theBBox.yMin = theCBox.yMin; } if ( theCBox.xMax > theBBox.xMax ) { theBBox.xMax = theCBox.xMax; } if ( theCBox.yMax > theBBox.yMax ) { theBBox.yMax = theCBox.yMax; } } /* if bitmap is supplied then draw into it */ if ( aBitmap == NULL ) { continue; } /* convert to an anti-aliased bitmap */ if ( FT_Render_Glyph( slot, FT_RENDER_MODE_NORMAL ) != 0 ) continue; /* render the bitmap... */ for ( y = 0; y < slot->bitmap.rows; y++ ) { for ( x = 0; x < slot->bitmap.width; x++ ) { unsigned int by = (-(thePen_y>>6)-slot->bitmap_top+y+aBitmapHeight); unsigned int bx = (thePen_x>>6)+slot->bitmap_left+x; if ( bx < aBitmapWidth && by < aBitmapHeight ) { unsigned int *pixel = &aBitmap[ by * aBitmapWidth + bx ]; *pixel = blend( *pixel, j ? ftContext->m_fontColor : ftContext->m_fontColorTwo, slot->bitmap.buffer[y*slot->bitmap.pitch+x], j ? ftContext->m_Alpha1 : ftContext->m_Alpha2 ); } } } } if ( aBBox != NULL ) { *aBBox = theBBox; } if ( aPen_x != NULL ) { *aPen_x = thePen_x; } if ( aPen_y != NULL ) { *aPen_y = thePen_y; } return 0; }
T1_Load_Glyph( T1_GlyphSlot glyph, T1_Size size, FT_UInt glyph_index, FT_Int32 load_flags ) { FT_Error error; T1_DecoderRec decoder; T1_Face face = (T1_Face)glyph->root.face; FT_Bool hinting; T1_Font type1 = &face->type1; PSAux_Service psaux = (PSAux_Service)face->psaux; const T1_Decoder_Funcs decoder_funcs = psaux->t1_decoder_funcs; FT_Matrix font_matrix; FT_Vector font_offset; FT_Data glyph_data; FT_Bool glyph_data_loaded = 0; if ( load_flags & FT_LOAD_NO_RECURSE ) load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; glyph->x_scale = size->root.metrics.x_scale; glyph->y_scale = size->root.metrics.y_scale; glyph->root.outline.n_points = 0; glyph->root.outline.n_contours = 0; hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 && ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; error = decoder_funcs->init( &decoder, (FT_Face)face, (FT_Size)size, (FT_GlyphSlot)glyph, (FT_Byte**)type1->glyph_names, face->blend, FT_BOOL( hinting ), FT_LOAD_TARGET_MODE(load_flags), T1_Parse_Glyph ); if ( error ) goto Exit; decoder.builder.no_recurse = FT_BOOL( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ); decoder.num_subrs = type1->num_subrs; decoder.subrs = type1->subrs; decoder.subrs_len = type1->subrs_len; /* now load the unscaled outline */ error = T1_Parse_Glyph_And_Get_Char_String( &decoder, glyph_index, &glyph_data ); if ( error ) goto Exit; glyph_data_loaded = 1; FT_UNUSED( glyph_data_loaded ); font_matrix = decoder.font_matrix; font_offset = decoder.font_offset; /* save new glyph tables */ decoder_funcs->done( &decoder ); /* now, set the metrics -- this is rather simple, as */ /* the left side bearing is the xMin, and the top side */ /* bearing the yMax */ if ( !error ) { glyph->root.outline.flags &= FT_OUTLINE_OWNER; glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL; /* for composite glyphs, return only left side bearing and */ /* advance width */ if ( load_flags & FT_LOAD_NO_RECURSE ) { FT_Slot_Internal internal = glyph->root.internal; glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; glyph->root.metrics.horiAdvance = decoder.builder.advance.x; internal->glyph_matrix = font_matrix; internal->glyph_delta = font_offset; internal->glyph_transformed = 1; } else { FT_BBox cbox; FT_Glyph_Metrics* metrics = &glyph->root.metrics; /* copy the _unscaled_ advance width */ metrics->horiAdvance = decoder.builder.advance.x; glyph->root.linearHoriAdvance = decoder.builder.advance.x; glyph->root.internal->glyph_transformed = 0; /* make up vertical metrics */ metrics->vertBearingX = 0; metrics->vertBearingY = 0; metrics->vertAdvance = 0; glyph->root.linearVertAdvance = 0; glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; if ( size && size->root.metrics.y_ppem < 24 ) glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION; #if 1 /* apply the font matrix, if any */ FT_Outline_Transform( &glyph->root.outline, &font_matrix ); FT_Outline_Translate( &glyph->root.outline, font_offset.x, font_offset.y ); #endif if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) { /* scale the outline and the metrics */ FT_Int n; FT_Outline* cur = decoder.builder.base; FT_Vector* vec = cur->points; FT_Fixed x_scale = glyph->x_scale; FT_Fixed y_scale = glyph->y_scale; /* First of all, scale the points, if we are not hinting */ if ( !hinting ) for ( n = cur->n_points; n > 0; n--, vec++ ) { vec->x = FT_MulFix( vec->x, x_scale ); vec->y = FT_MulFix( vec->y, y_scale ); } FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); /* Then scale the metrics */ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale ); metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale ); if ( hinting ) { metrics->horiAdvance = ( metrics->horiAdvance + 32 ) & -64; metrics->vertAdvance = ( metrics->vertAdvance + 32 ) & -64; metrics->vertBearingX = ( metrics->vertBearingX + 32 ) & -64; metrics->vertBearingY = ( metrics->vertBearingY + 32 ) & -64; } } /* compute the other metrics */ FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); /* grid fit the bounding box if necessary */ if ( hinting ) { cbox.xMin &= -64; cbox.yMin &= -64; cbox.xMax = ( cbox.xMax+63 ) & -64; cbox.yMax = ( cbox.yMax+63 ) & -64; } metrics->width = cbox.xMax - cbox.xMin; metrics->height = cbox.yMax - cbox.yMin; metrics->horiBearingX = cbox.xMin; metrics->horiBearingY = cbox.yMax; } /* Set control data to the glyph charstrings. Note that this is */ /* _not_ zero-terminated. */ glyph->root.control_data = (FT_Byte*)glyph_data.pointer; glyph->root.control_len = glyph_data.length; } Exit: #ifdef FT_CONFIG_OPTION_INCREMENTAL if ( glyph_data_loaded && face->root.internal->incremental_interface ) { face->root.internal->incremental_interface->funcs->free_glyph_data( face->root.internal->incremental_interface->object, &glyph_data ); /* Set the control data to null - it is no longer available if */ /* loaded incrementally. */ glyph->root.control_data = 0; glyph->root.control_len = 0; } #endif return error; }
void readttf(Font *fnt, Boolean quiet, Boolean only_range) { FT_Error error; ttfinfo *ti, *Ti; long Num, index; unsigned int i, j; long k, max_k; int index_array[257]; static Boolean initialized = False; /* * We allocate a placeholder boundary and the `.notdef' character. */ if (!only_range) { ti = newchar(fnt); ti->charcode = -1; ti->adobename = ".notdef"; ti = newchar(fnt); ti->charcode = -1; ti->adobename = "||"; /* boundary character name */ } /* * Initialize FreeType engine. */ if (!initialized) { /* * We use a dummy glyph size of 10pt. */ dpi = 92; ptsize = 10 * 64; real_ttfname = TeX_search_ttf_file(&(fnt->ttfname)); if (!real_ttfname) oops("Cannot find `%s'.", fnt->ttfname); FTopen(real_ttfname, fnt, True, True); initialized = True; } if (!quiet) { if (only_range) printf("\n\n%s:\n", fnt->fullname); printf("\n"); printf("Glyph Code Glyph Name "); printf("Width llx lly urx ury\n"); printf("----------------------------------------"); printf("---------------------------------\n"); } /* * We load only glyphs with a valid cmap entry. Nevertheless, for * the default mapping, we use the first 256 glyphs addressed by * ascending code points, followed by glyphs not in the cmap. * * If we compute a range, we take the character codes given in * the fnt->sf_code array. * * If the -N flag is set, no cmap is used at all. Instead, the * first 256 glyphs (with a valid PS name) are used for the default * mapping. */ if (!only_range) for (i = 0; i < 257; i++) index_array[i] = 0; else for (i = 0; i < 256; i++) fnt->inencptrs[i] = 0; j = 0; if (fnt->PSnames == Only) max_k = face->num_glyphs - 1; else max_k = only_range ? 0xFF : 0x16FFFF; for (k = 0; k <= max_k; k++) { char buff[128]; const char *an; if (fnt->PSnames != Only) { if (only_range) { index = fnt->sf_code[k]; if (index < 0) continue; j = k; } else index = k; Num = FT_Get_Char_Index(face, index); /* now we try to get a vertical glyph form */ if (has_gsub) Num = Get_Vert(Num); if (Num < 0) oops("Failure on cmap mapping from %s.", fnt->ttfname); if (Num == 0) continue; if (!only_range) if (Num <= 256) index_array[Num] = 1; } else { Num = k; index = 0; } error = FT_Load_Glyph(face, Num, flags); if (!error) { if (fnt->efactor != 1.0 || fnt->slant != 0.0 ) FT_Outline_Transform(&face->glyph->outline, &matrix1); if (fnt->rotate) FT_Outline_Transform(&face->glyph->outline, &matrix2); error = FT_Outline_Get_BBox(&face->glyph->outline, &bbox); /* we need the non- grid-fitted bbox */ } if (!error) { if (fnt->PSnames) { (void)FT_Get_Glyph_Name(face, Num, buff, 128); an = newstring(buff); } else an = code_to_adobename(index); /* ignore characters not usable for typesetting with TeX */ if (strcmp(an, ".notdef") == 0) continue; if (strcmp(an, ".null") == 0) continue; if (strcmp(an, "nonmarkingreturn") == 0) continue; ti = newchar(fnt); ti->charcode = index; ti->glyphindex = Num; ti->adobename = an; ti->llx = bbox.xMin * 1000 / fnt->units_per_em; ti->lly = bbox.yMin * 1000 / fnt->units_per_em; ti->urx = bbox.xMax * 1000 / fnt->units_per_em; ti->ury = bbox.yMax * 1000 / fnt->units_per_em; ti->fntnum = fnt->subfont_num; /* * We must now shift the rotated character both horizontally * and vertically. The vertical amount is 25% by default. */ if (fnt->rotate) { ti->llx += (face->glyph->metrics.vertBearingY - bbox.xMin) * 1000 / fnt->units_per_em; ti->lly -= 1000 * fnt->y_offset; ti->urx += (face->glyph->metrics.vertBearingY - bbox.xMin) * 1000 / fnt->units_per_em; ti->ury -= 1000 * fnt->y_offset; } /* * We need to avoid negative heights or depths. They break accents * in math mode, among other things. */ if (ti->lly > 0) ti->lly = 0; if (ti->ury < 0) ti->ury = 0; if (fnt->rotate) ti->width = face->glyph->metrics.vertAdvance * 1000 / fnt->units_per_em; else ti->width = transform(face->glyph->metrics.horiAdvance * 1000 / fnt->units_per_em, 0, fnt->efactor, fnt->slant); if (!quiet) printf("%5ld %05lx %-25s %5d % 5d,% 5d -- % 5d,% 5d\n", Num, index, ti->adobename, ti->width, ti->llx, ti->lly, ti->urx, ti->ury); if (j < 256) { fnt->inencptrs[j] = ti; ti->incode = j; } j++; } } /* * Now we load glyphs without a cmap entry, provided some slots are * still free -- we skip this if we have to compute a range or use * PS names. */ if (!only_range && !fnt->PSnames) { for (i = 1; i <= face->num_glyphs; i++) { const char *an; if (index_array[i] == 0) { error = FT_Load_Glyph(face, i, flags); if (!error) error = FT_Outline_Get_BBox(&face->glyph->outline, &bbox); if (!error) { an = code_to_adobename(i | 0x1000000); ti = newchar(fnt); ti->charcode = i | 0x1000000; ti->glyphindex = i; ti->adobename = an; ti->llx = bbox.xMin * 1000 / fnt->units_per_em; ti->lly = bbox.yMin * 1000 / fnt->units_per_em; ti->urx = bbox.xMax * 1000 / fnt->units_per_em; ti->ury = bbox.yMax * 1000 / fnt->units_per_em; if (ti->lly > 0) ti->lly = 0; if (ti->ury < 0) ti->ury = 0; ti->width = transform(face->glyph->metrics.horiAdvance*1000 / fnt->units_per_em, 0, fnt->efactor, fnt->slant); if (!quiet) printf("%5d %-25s %5d % 5d,% 5d -- % 5d,% 5d\n", i, ti->adobename, ti->width, ti->llx, ti->lly, ti->urx, ti->ury); if (j < 256) { fnt->inencptrs[j] = ti; ti->incode = j; } else break; j++; } } } } /* Finally, we construct a `Germandbls' glyph if necessary */ if (!only_range) { if (NULL == findadobe("Germandbls", fnt->charlist) && NULL != (Ti = findadobe("S", fnt->charlist))) { pcc *np, *nq; ti = newchar(fnt); ti->charcode = face->num_glyphs | 0x1000000; ti->glyphindex = face->num_glyphs; ti->adobename = "Germandbls"; ti->width = Ti->width << 1; ti->llx = Ti->llx; ti->lly = Ti->lly; ti->urx = Ti->width + Ti->urx; ti->ury = Ti->ury; ti->kerns = Ti->kerns; np = newpcc(); np->partname = "S"; nq = newpcc(); nq->partname = "S"; nq->xoffset = Ti->width; np->next = nq; ti->pccs = np; ti->constructed = True; if (!quiet) printf("* %-25s %5d % 5d,% 5d -- % 5d,% 5d\n", ti->adobename, ti->width, ti->llx, ti->lly, ti->urx, ti->ury); } } /* kerning between subfonts isn't available */ if (!only_range) readttf_kern(fnt); }
cff_slot_load( CFF_GlyphSlot glyph, CFF_Size size, FT_UInt glyph_index, FT_Int32 load_flags ) { FT_Error error; CFF_Decoder decoder; PS_Decoder psdecoder; TT_Face face = (TT_Face)glyph->root.face; FT_Bool hinting, scaled, force_scaling; CFF_Font cff = (CFF_Font)face->extra.data; PSAux_Service psaux = (PSAux_Service)face->psaux; const CFF_Decoder_Funcs decoder_funcs = psaux->cff_decoder_funcs; FT_Matrix font_matrix; FT_Vector font_offset; force_scaling = FALSE; /* in a CID-keyed font, consider `glyph_index' as a CID and map */ /* it immediately to the real glyph_index -- if it isn't a */ /* subsetted font, glyph_indices and CIDs are identical, though */ if ( cff->top_font.font_dict.cid_registry != 0xFFFFU && cff->charset.cids ) { /* don't handle CID 0 (.notdef) which is directly mapped to GID 0 */ if ( glyph_index != 0 ) { glyph_index = cff_charset_cid_to_gindex( &cff->charset, glyph_index ); if ( glyph_index == 0 ) return FT_THROW( Invalid_Argument ); } } else if ( glyph_index >= cff->num_glyphs ) return FT_THROW( Invalid_Argument ); if ( load_flags & FT_LOAD_NO_RECURSE ) load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; glyph->x_scale = 0x10000L; glyph->y_scale = 0x10000L; if ( size ) { glyph->x_scale = size->root.metrics.x_scale; glyph->y_scale = size->root.metrics.y_scale; } #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* try to load embedded bitmap if any */ /* */ /* XXX: The convention should be emphasized in */ /* the documents because it can be confusing. */ if ( size ) { CFF_Face cff_face = (CFF_Face)size->root.face; SFNT_Service sfnt = (SFNT_Service)cff_face->sfnt; FT_Stream stream = cff_face->root.stream; if ( size->strike_index != 0xFFFFFFFFUL && sfnt->load_eblc && ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) { TT_SBit_MetricsRec metrics; error = sfnt->load_sbit_image( face, size->strike_index, glyph_index, (FT_UInt)load_flags, stream, &glyph->root.bitmap, &metrics ); if ( !error ) { FT_Bool has_vertical_info; FT_UShort advance; FT_Short dummy; glyph->root.outline.n_points = 0; glyph->root.outline.n_contours = 0; glyph->root.metrics.width = (FT_Pos)metrics.width << 6; glyph->root.metrics.height = (FT_Pos)metrics.height << 6; glyph->root.metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6; glyph->root.metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6; glyph->root.metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6; glyph->root.metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6; glyph->root.metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6; glyph->root.metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6; glyph->root.format = FT_GLYPH_FORMAT_BITMAP; if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) { glyph->root.bitmap_left = metrics.vertBearingX; glyph->root.bitmap_top = metrics.vertBearingY; } else { glyph->root.bitmap_left = metrics.horiBearingX; glyph->root.bitmap_top = metrics.horiBearingY; } /* compute linear advance widths */ (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 0, glyph_index, &dummy, &advance ); glyph->root.linearHoriAdvance = advance; has_vertical_info = FT_BOOL( face->vertical_info && face->vertical.number_Of_VMetrics > 0 ); /* get the vertical metrics from the vmtx table if we have one */ if ( has_vertical_info ) { (void)( (SFNT_Service)face->sfnt )->get_metrics( face, 1, glyph_index, &dummy, &advance ); glyph->root.linearVertAdvance = advance; } else { /* make up vertical ones */ if ( face->os2.version != 0xFFFFU ) glyph->root.linearVertAdvance = (FT_Pos) ( face->os2.sTypoAscender - face->os2.sTypoDescender ); else glyph->root.linearVertAdvance = (FT_Pos) ( face->horizontal.Ascender - face->horizontal.Descender ); } return error; } } } #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ /* return immediately if we only want the embedded bitmaps */ if ( load_flags & FT_LOAD_SBITS_ONLY ) return FT_THROW( Invalid_Argument ); /* if we have a CID subfont, use its matrix (which has already */ /* been multiplied with the root matrix) */ /* this scaling is only relevant if the PS hinter isn't active */ if ( cff->num_subfonts ) { FT_Long top_upm, sub_upm; FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, glyph_index ); if ( fd_index >= cff->num_subfonts ) fd_index = (FT_Byte)( cff->num_subfonts - 1 ); top_upm = (FT_Long)cff->top_font.font_dict.units_per_em; sub_upm = (FT_Long)cff->subfonts[fd_index]->font_dict.units_per_em; font_matrix = cff->subfonts[fd_index]->font_dict.font_matrix; font_offset = cff->subfonts[fd_index]->font_dict.font_offset; if ( top_upm != sub_upm ) { glyph->x_scale = FT_MulDiv( glyph->x_scale, top_upm, sub_upm ); glyph->y_scale = FT_MulDiv( glyph->y_scale, top_upm, sub_upm ); force_scaling = TRUE; } } else { font_matrix = cff->top_font.font_dict.font_matrix; font_offset = cff->top_font.font_dict.font_offset; } glyph->root.outline.n_points = 0; glyph->root.outline.n_contours = 0; /* top-level code ensures that FT_LOAD_NO_HINTING is set */ /* if FT_LOAD_NO_SCALE is active */ hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); glyph->hint = hinting; glyph->scaled = scaled; glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; /* by default */ { #ifdef CFF_CONFIG_OPTION_OLD_ENGINE PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( face ); #endif FT_Byte* charstring; FT_ULong charstring_len; decoder_funcs->init( &decoder, face, size, glyph, hinting, FT_LOAD_TARGET_MODE( load_flags ), cff_get_glyph_data, cff_free_glyph_data ); /* this is for pure CFFs */ if ( load_flags & FT_LOAD_ADVANCE_ONLY ) decoder.width_only = TRUE; decoder.builder.no_recurse = (FT_Bool)( load_flags & FT_LOAD_NO_RECURSE ); /* now load the unscaled outline */ error = cff_get_glyph_data( face, glyph_index, &charstring, &charstring_len ); if ( error ) goto Glyph_Build_Finished; error = decoder_funcs->prepare( &decoder, size, glyph_index ); if ( error ) goto Glyph_Build_Finished; #ifdef CFF_CONFIG_OPTION_OLD_ENGINE /* choose which CFF renderer to use */ if ( driver->hinting_engine == FT_HINTING_FREETYPE ) error = decoder_funcs->parse_charstrings_old( &decoder, charstring, charstring_len, 0 ); else #endif { psaux->ps_decoder_init( &psdecoder, &decoder, FALSE ); error = decoder_funcs->parse_charstrings( &psdecoder, charstring, charstring_len ); /* Adobe's engine uses 16.16 numbers everywhere; */ /* as a consequence, glyphs larger than 2000ppem get rejected */ if ( FT_ERR_EQ( error, Glyph_Too_Big ) ) { /* this time, we retry unhinted and scale up the glyph later on */ /* (the engine uses and sets the hardcoded value 0x10000 / 64 = */ /* 0x400 for both `x_scale' and `y_scale' in this case) */ hinting = FALSE; force_scaling = TRUE; glyph->hint = hinting; error = decoder_funcs->parse_charstrings( &psdecoder, charstring, charstring_len ); } } cff_free_glyph_data( face, &charstring, charstring_len ); if ( error ) goto Glyph_Build_Finished; #ifdef FT_CONFIG_OPTION_INCREMENTAL /* Control data and length may not be available for incremental */ /* fonts. */ if ( face->root.internal->incremental_interface ) { glyph->root.control_data = NULL; glyph->root.control_len = 0; } else #endif /* FT_CONFIG_OPTION_INCREMENTAL */ /* We set control_data and control_len if charstrings is loaded. */ /* See how charstring loads at cff_index_access_element() in */ /* cffload.c. */ { CFF_Index csindex = &cff->charstrings_index; if ( csindex->offsets ) { glyph->root.control_data = csindex->bytes + csindex->offsets[glyph_index] - 1; glyph->root.control_len = (FT_Long)charstring_len; } } Glyph_Build_Finished: /* save new glyph tables, if no error */ if ( !error ) decoder.builder.funcs.done( &decoder.builder ); /* XXX: anything to do for broken glyph entry? */ } #ifdef FT_CONFIG_OPTION_INCREMENTAL /* Incremental fonts can optionally override the metrics. */ if ( !error && face->root.internal->incremental_interface && face->root.internal->incremental_interface->funcs->get_glyph_metrics ) { FT_Incremental_MetricsRec metrics; metrics.bearing_x = decoder.builder.left_bearing.x; metrics.bearing_y = 0; metrics.advance = decoder.builder.advance.x; metrics.advance_v = decoder.builder.advance.y; error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( face->root.internal->incremental_interface->object, glyph_index, FALSE, &metrics ); decoder.builder.left_bearing.x = metrics.bearing_x; decoder.builder.advance.x = metrics.advance; decoder.builder.advance.y = metrics.advance_v; } #endif /* FT_CONFIG_OPTION_INCREMENTAL */ if ( !error ) { /* Now, set the metrics -- this is rather simple, as */ /* the left side bearing is the xMin, and the top side */ /* bearing the yMax. */ /* For composite glyphs, return only left side bearing and */ /* advance width. */ if ( load_flags & FT_LOAD_NO_RECURSE ) { FT_Slot_Internal internal = glyph->root.internal; glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; glyph->root.metrics.horiAdvance = decoder.glyph_width; internal->glyph_matrix = font_matrix; internal->glyph_delta = font_offset; internal->glyph_transformed = 1; } else { FT_BBox cbox; FT_Glyph_Metrics* metrics = &glyph->root.metrics; FT_Bool has_vertical_info; if ( face->horizontal.number_Of_HMetrics ) { FT_Short horiBearingX = 0; FT_UShort horiAdvance = 0; ( (SFNT_Service)face->sfnt )->get_metrics( face, 0, glyph_index, &horiBearingX, &horiAdvance ); metrics->horiAdvance = horiAdvance; metrics->horiBearingX = horiBearingX; glyph->root.linearHoriAdvance = horiAdvance; } else { /* copy the _unscaled_ advance width */ metrics->horiAdvance = decoder.glyph_width; glyph->root.linearHoriAdvance = decoder.glyph_width; } glyph->root.internal->glyph_transformed = 0; has_vertical_info = FT_BOOL( face->vertical_info && face->vertical.number_Of_VMetrics > 0 ); /* get the vertical metrics from the vmtx table if we have one */ if ( has_vertical_info ) { FT_Short vertBearingY = 0; FT_UShort vertAdvance = 0; ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, glyph_index, &vertBearingY, &vertAdvance ); metrics->vertBearingY = vertBearingY; metrics->vertAdvance = vertAdvance; } else { /* make up vertical ones */ if ( face->os2.version != 0xFFFFU ) metrics->vertAdvance = (FT_Pos)( face->os2.sTypoAscender - face->os2.sTypoDescender ); else metrics->vertAdvance = (FT_Pos)( face->horizontal.Ascender - face->horizontal.Descender ); } glyph->root.linearVertAdvance = metrics->vertAdvance; glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; glyph->root.outline.flags = 0; if ( size && size->root.metrics.y_ppem < 24 ) glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION; glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL; /* apply the font matrix, if any */ if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || font_matrix.xy != 0 || font_matrix.yx != 0 ) { FT_Outline_Transform( &glyph->root.outline, &font_matrix ); metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, font_matrix.xx ); metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, font_matrix.yy ); } if ( font_offset.x || font_offset.y ) { FT_Outline_Translate( &glyph->root.outline, font_offset.x, font_offset.y ); metrics->horiAdvance += font_offset.x; metrics->vertAdvance += font_offset.y; } if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling ) { /* scale the outline and the metrics */ FT_Int n; FT_Outline* cur = &glyph->root.outline; FT_Vector* vec = cur->points; FT_Fixed x_scale = glyph->x_scale; FT_Fixed y_scale = glyph->y_scale; /* First of all, scale the points */ if ( !hinting || !decoder.builder.hints_funcs ) for ( n = cur->n_points; n > 0; n--, vec++ ) { vec->x = FT_MulFix( vec->x, x_scale ); vec->y = FT_MulFix( vec->y, y_scale ); } /* Then scale the metrics */ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); } /* compute the other metrics */ FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); metrics->width = cbox.xMax - cbox.xMin; metrics->height = cbox.yMax - cbox.yMin; metrics->horiBearingX = cbox.xMin; metrics->horiBearingY = cbox.yMax; if ( has_vertical_info ) metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2; else { if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) ft_synthesize_vertical_metrics( metrics, metrics->vertAdvance ); } } } return error; }
af_loader_load_glyph( AF_Loader loader, AF_Module module, FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags ) { FT_Error error; FT_Size size = face->size; FT_Size_Internal size_internal = size->internal; FT_GlyphSlot slot = face->glyph; FT_Slot_Internal slot_internal = slot->internal; FT_GlyphLoader gloader = slot_internal->loader; AF_GlyphHints hints = loader->hints; AF_ScalerRec scaler; AF_StyleMetrics style_metrics; FT_UInt style_options = AF_STYLE_NONE_DFLT; AF_StyleClass style_class; AF_WritingSystemClass writing_system_class; if ( !size ) return FT_THROW( Invalid_Size_Handle ); FT_ZERO( &scaler ); if ( !size_internal->autohint_metrics.x_scale || size_internal->autohint_mode != FT_LOAD_TARGET_MODE( load_flags ) ) { /* switching between hinting modes usually means different scaling */ /* values; this later on enforces recomputation of everything */ /* related to the current size */ size_internal->autohint_mode = FT_LOAD_TARGET_MODE( load_flags ); size_internal->autohint_metrics = size->metrics; #ifdef AF_CONFIG_OPTION_TT_SIZE_METRICS { FT_Size_Metrics* size_metrics = &size_internal->autohint_metrics; /* set metrics to integer values and adjust scaling accordingly; */ /* this is the same setup as with TrueType fonts, cf. function */ /* `tt_size_reset' in file `ttobjs.c' */ size_metrics->ascender = FT_PIX_ROUND( FT_MulFix( face->ascender, size_metrics->y_scale ) ); size_metrics->descender = FT_PIX_ROUND( FT_MulFix( face->descender, size_metrics->y_scale ) ); size_metrics->height = FT_PIX_ROUND( FT_MulFix( face->height, size_metrics->y_scale ) ); size_metrics->x_scale = FT_DivFix( size_metrics->x_ppem << 6, face->units_per_EM ); size_metrics->y_scale = FT_DivFix( size_metrics->y_ppem << 6, face->units_per_EM ); size_metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width, size_metrics->x_scale ) ); } #endif /* AF_CONFIG_OPTION_TT_SIZE_METRICS */ } /* * TODO: This code currently doesn't support fractional advance widths, * i.e., placing hinted glyphs at anything other than integer * x-positions. This is only relevant for the warper code, which * scales and shifts glyphs to optimize blackness of stems (hinting on * the x-axis by nature places things on pixel integers, hinting on the * y-axis only, i.e., LIGHT mode, doesn't touch the x-axis). The delta * values of the scaler would need to be adjusted. */ scaler.face = face; scaler.x_scale = size_internal->autohint_metrics.x_scale; scaler.x_delta = 0; scaler.y_scale = size_internal->autohint_metrics.y_scale; scaler.y_delta = 0; scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); scaler.flags = 0; /* note that the fallback style can't be changed anymore */ /* after the first call of `af_loader_load_glyph' */ error = af_loader_reset( loader, module, face ); if ( error ) goto Exit; #ifdef FT_OPTION_AUTOFIT2 /* XXX: undocumented hook to activate the latin2 writing system. */ if ( load_flags & ( 1UL << 20 ) ) style_options = AF_STYLE_LTN2_DFLT; #endif /* * Glyphs (really code points) are assigned to scripts. Script * analysis is done lazily: For each glyph that passes through here, * the corresponding script analyzer is called, but returns immediately * if it has been run already. */ error = af_face_globals_get_metrics( loader->globals, glyph_index, style_options, &style_metrics ); if ( error ) goto Exit; style_class = style_metrics->style_class; writing_system_class = af_writing_system_classes[style_class->writing_system]; loader->metrics = style_metrics; if ( writing_system_class->style_metrics_scale ) writing_system_class->style_metrics_scale( style_metrics, &scaler ); else style_metrics->scaler = scaler; if ( writing_system_class->style_hints_init ) { error = writing_system_class->style_hints_init( hints, style_metrics ); if ( error ) goto Exit; } /* * Do the main work of `af_loader_load_glyph'. Note that we never have * to deal with composite glyphs as those get loaded into * FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function. * In the rare cases where FT_LOAD_NO_RECURSE is set, it implies * FT_LOAD_NO_SCALE and as such the auto-hinter is never called. */ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_LINEAR_DESIGN; load_flags &= ~FT_LOAD_RENDER; error = FT_Load_Glyph( face, glyph_index, load_flags ); if ( error ) goto Exit; /* * Apply stem darkening (emboldening) here before hints are applied to * the outline. Glyphs are scaled down proportionally to the * emboldening so that curve points don't fall outside their * precomputed blue zones. * * Any emboldening done by the font driver (e.g., the CFF driver) * doesn't reach here because the autohinter loads the unprocessed * glyphs in font units for analysis (functions `af_*_metrics_init_*') * and then above to prepare it for the rasterizers by itself, * independently of the font driver. So emboldening must be done here, * within the autohinter. * * All glyphs to be autohinted pass through here one by one. The * standard widths can therefore change from one glyph to the next, * depending on what script a glyph is assigned to (each script has its * own set of standard widths and other metrics). The darkening amount * must therefore be recomputed for each size and * `standard_{vertical,horizontal}_width' change. * * Ignore errors and carry on without emboldening. * */ /* stem darkening only works well in `light' mode */ if ( scaler.render_mode == FT_RENDER_MODE_LIGHT && ( !face->internal->no_stem_darkening || ( face->internal->no_stem_darkening < 0 && !module->no_stem_darkening ) ) ) af_loader_embolden_glyph_in_slot( loader, face, style_metrics ); loader->transformed = slot_internal->glyph_transformed; if ( loader->transformed ) { FT_Matrix inverse; loader->trans_matrix = slot_internal->glyph_matrix; loader->trans_delta = slot_internal->glyph_delta; inverse = loader->trans_matrix; if ( !FT_Matrix_Invert( &inverse ) ) FT_Vector_Transform( &loader->trans_delta, &inverse ); } switch ( slot->format ) { case FT_GLYPH_FORMAT_OUTLINE: /* translate the loaded glyph when an internal transform is needed */ if ( loader->transformed ) FT_Outline_Translate( &slot->outline, loader->trans_delta.x, loader->trans_delta.y ); /* compute original horizontal phantom points */ /* (and ignore vertical ones) */ loader->pp1.x = hints->x_delta; loader->pp1.y = hints->y_delta; loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, hints->x_scale ) + hints->x_delta; loader->pp2.y = hints->y_delta; /* be sure to check for spacing glyphs */ if ( slot->outline.n_points == 0 ) goto Hint_Metrics; /* now load the slot image into the auto-outline */ /* and run the automatic hinting process */ if ( writing_system_class->style_hints_apply ) { error = writing_system_class->style_hints_apply( glyph_index, hints, &gloader->base.outline, style_metrics ); if ( error ) goto Exit; } /* we now need to adjust the metrics according to the change in */ /* width/positioning that occurred during the hinting process */ if ( scaler.render_mode != FT_RENDER_MODE_LIGHT ) { AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ]; if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) { AF_Edge edge1 = axis->edges; /* leftmost edge */ AF_Edge edge2 = edge1 + axis->num_edges - 1; /* rightmost edge */ FT_Pos old_rsb = loader->pp2.x - edge2->opos; /* loader->pp1.x is always zero at this point of time */ FT_Pos old_lsb = edge1->opos; /* - loader->pp1.x */ FT_Pos new_lsb = edge1->pos; /* remember unhinted values to later account */ /* for rounding errors */ FT_Pos pp1x_uh = new_lsb - old_lsb; FT_Pos pp2x_uh = edge2->pos + old_rsb; /* prefer too much space over too little space */ /* for very small sizes */ if ( old_lsb < 24 ) pp1x_uh -= 8; if ( old_rsb < 24 ) pp2x_uh += 8; loader->pp1.x = FT_PIX_ROUND( pp1x_uh ); loader->pp2.x = FT_PIX_ROUND( pp2x_uh ); if ( loader->pp1.x >= new_lsb && old_lsb > 0 ) loader->pp1.x -= 64; if ( loader->pp2.x <= edge2->pos && old_rsb > 0 ) loader->pp2.x += 64; slot->lsb_delta = loader->pp1.x - pp1x_uh; slot->rsb_delta = loader->pp2.x - pp2x_uh; } else { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta ); loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta ); slot->lsb_delta = loader->pp1.x - pp1x; slot->rsb_delta = loader->pp2.x - pp2x; } } /* `light' mode uses integer advance widths */ /* but sets `lsb_delta' and `rsb_delta' */ else { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; loader->pp1.x = FT_PIX_ROUND( pp1x ); loader->pp2.x = FT_PIX_ROUND( pp2x ); slot->lsb_delta = loader->pp1.x - pp1x; slot->rsb_delta = loader->pp2.x - pp2x; } break; default: /* we don't support other formats (yet?) */ error = FT_THROW( Unimplemented_Feature ); } Hint_Metrics: { FT_BBox bbox; FT_Vector vvector; vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX; vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY; vvector.x = FT_MulFix( vvector.x, style_metrics->scaler.x_scale ); vvector.y = FT_MulFix( vvector.y, style_metrics->scaler.y_scale ); /* transform the hinted outline if needed */ if ( loader->transformed ) { FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix ); FT_Vector_Transform( &vvector, &loader->trans_matrix ); } /* we must translate our final outline by -pp1.x and compute */ /* the new metrics */ if ( loader->pp1.x ) FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 ); FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); bbox.xMax = FT_PIX_CEIL( bbox.xMax ); bbox.yMax = FT_PIX_CEIL( bbox.yMax ); slot->metrics.width = bbox.xMax - bbox.xMin; slot->metrics.height = bbox.yMax - bbox.yMin; slot->metrics.horiBearingX = bbox.xMin; slot->metrics.horiBearingY = bbox.yMax; slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x ); slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y ); /* for mono-width fonts (like Andale, Courier, etc.) we need */ /* to keep the original rounded advance width; ditto for */ /* digits if all have the same advance width */ if ( scaler.render_mode != FT_RENDER_MODE_LIGHT && ( FT_IS_FIXED_WIDTH( slot->face ) || ( af_face_globals_is_digit( loader->globals, glyph_index ) && style_metrics->digits_have_same_width ) ) ) { slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, style_metrics->scaler.x_scale ); /* Set delta values to 0. Otherwise code that uses them is */ /* going to ruin the fixed advance width. */ slot->lsb_delta = 0; slot->rsb_delta = 0; } else { /* non-spacing glyphs must stay as-is */ if ( slot->metrics.horiAdvance ) slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; } slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance, style_metrics->scaler.y_scale ); slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance ); slot->format = FT_GLYPH_FORMAT_OUTLINE; } Exit: return error; }
FT_LOCAL_DEF FT_Error T1_Load_Glyph( T1_GlyphSlot glyph, T1_Size size, FT_Int glyph_index, FT_Int load_flags ) { FT_Error error; T1_Decoder decoder; T1_Face face = (T1_Face)glyph->root.face; FT_Bool hinting; T1_Font* type1 = &face->type1; PSAux_Interface* psaux = (PSAux_Interface*)face->psaux; const T1_Decoder_Funcs* decoder_funcs = psaux->t1_decoder_funcs; FT_Matrix font_matrix; FT_Vector font_offset; if ( load_flags & FT_LOAD_NO_RECURSE ) load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; glyph->x_scale = size->root.metrics.x_scale; glyph->y_scale = size->root.metrics.y_scale; glyph->root.outline.n_points = 0; glyph->root.outline.n_contours = 0; hinting = ( load_flags & FT_LOAD_NO_SCALE ) == 0 && ( load_flags & FT_LOAD_NO_HINTING ) == 0; glyph->root.format = ft_glyph_format_outline; error = decoder_funcs->init( &decoder, (FT_Face)face, (FT_Size)size, (FT_GlyphSlot)glyph, (FT_Byte**)type1->glyph_names, face->blend, T1_Parse_Glyph ); if ( error ) goto Exit; decoder.builder.no_recurse = ( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ); decoder.num_subrs = type1->num_subrs; decoder.subrs = type1->subrs; decoder.subrs_len = type1->subrs_len; /* now load the unscaled outline */ error = T1_Parse_Glyph( &decoder, glyph_index ); if ( error ) goto Exit; font_matrix = decoder.font_matrix; font_offset = decoder.font_offset; /* save new glyph tables */ decoder_funcs->done( &decoder ); /* now, set the metrics -- this is rather simple, as */ /* the left side bearing is the xMin, and the top side */ /* bearing the yMax */ if ( !error ) { glyph->root.outline.flags &= ft_outline_owner; glyph->root.outline.flags |= ft_outline_reverse_fill; /* for composite glyphs, return only left side bearing and */ /* advance width */ if ( load_flags & FT_LOAD_NO_RECURSE ) { FT_Slot_Internal internal = glyph->root.internal; glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; glyph->root.metrics.horiAdvance = decoder.builder.advance.x; internal->glyph_matrix = font_matrix; internal->glyph_delta = font_offset; internal->glyph_transformed = 1; } else { FT_BBox cbox; FT_Glyph_Metrics* metrics = &glyph->root.metrics; /* copy the _unscaled_ advance width */ metrics->horiAdvance = decoder.builder.advance.x; glyph->root.linearHoriAdvance = decoder.builder.advance.x; glyph->root.internal->glyph_transformed = 0; /* make up vertical metrics */ metrics->vertBearingX = 0; metrics->vertBearingY = 0; metrics->vertAdvance = 0; glyph->root.linearVertAdvance = 0; glyph->root.format = ft_glyph_format_outline; if ( size && size->root.metrics.y_ppem < 24 ) glyph->root.outline.flags |= ft_outline_high_precision; /* apply the font matrix */ FT_Outline_Transform( &glyph->root.outline, &font_matrix ); FT_Outline_Translate( &glyph->root.outline, font_offset.x, font_offset.y ); #if 0 glyph->root.outline.second_pass = TRUE; glyph->root.outline.high_precision = size->root.metrics.y_ppem < 24; glyph->root.outline.dropout_mode = 2; #endif /* 0 */ if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) { /* scale the outline and the metrics */ FT_Int n; FT_Outline* cur = decoder.builder.base; FT_Vector* vec = cur->points; FT_Fixed x_scale = glyph->x_scale; FT_Fixed y_scale = glyph->y_scale; /* First of all, scale the points */ for ( n = cur->n_points; n > 0; n--, vec++ ) { vec->x = FT_MulFix( vec->x, x_scale ); vec->y = FT_MulFix( vec->y, y_scale ); } FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); /* Then scale the metrics */ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale ); metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale ); } /* compute the other metrics */ FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); /* grid fit the bounding box if necessary */ if ( hinting ) { cbox.xMin &= -64; cbox.yMin &= -64; cbox.xMax = ( cbox.xMax+63 ) & -64; cbox.yMax = ( cbox.yMax+63 ) & -64; } metrics->width = cbox.xMax - cbox.xMin; metrics->height = cbox.yMax - cbox.yMin; metrics->horiBearingX = cbox.xMin; metrics->horiBearingY = cbox.yMax; } } Exit: return error; }
static FT_Error af_loader_load_g( AF_Loader loader, AF_Scaler scaler, FT_UInt glyph_index, FT_Int32 load_flags ) { FT_Error error; FT_Face face = loader->face; AF_StyleMetrics metrics = loader->metrics; AF_GlyphHints hints = loader->hints; FT_GlyphSlot slot = face->glyph; FT_Slot_Internal internal = slot->internal; FT_GlyphLoader gloader = internal->loader; FT_Int32 flags; flags = load_flags | FT_LOAD_LINEAR_DESIGN; error = FT_Load_Glyph( face, glyph_index, flags ); if ( error ) goto Exit; loader->transformed = internal->glyph_transformed; if ( loader->transformed ) { FT_Matrix inverse; loader->trans_matrix = internal->glyph_matrix; loader->trans_delta = internal->glyph_delta; inverse = loader->trans_matrix; if ( !FT_Matrix_Invert( &inverse ) ) FT_Vector_Transform( &loader->trans_delta, &inverse ); } switch ( slot->format ) { case FT_GLYPH_FORMAT_OUTLINE: /* translate the loaded glyph when an internal transform is needed */ if ( loader->transformed ) FT_Outline_Translate( &slot->outline, loader->trans_delta.x, loader->trans_delta.y ); /* compute original horizontal phantom points (and ignore */ /* vertical ones) */ loader->pp1.x = hints->x_delta; loader->pp1.y = hints->y_delta; loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, hints->x_scale ) + hints->x_delta; loader->pp2.y = hints->y_delta; /* be sure to check for spacing glyphs */ if ( slot->outline.n_points == 0 ) goto Hint_Metrics; /* now load the slot image into the auto-outline and run the */ /* automatic hinting process */ { #ifdef FT_CONFIG_OPTION_PIC AF_FaceGlobals globals = loader->globals; #endif AF_StyleClass style_class = metrics->style_class; AF_WritingSystemClass writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; if ( writing_system_class->style_hints_apply ) writing_system_class->style_hints_apply( hints, &gloader->base.outline, metrics ); } /* we now need to adjust the metrics according to the change in */ /* width/positioning that occurred during the hinting process */ if ( scaler->render_mode != FT_RENDER_MODE_LIGHT ) { FT_Pos old_rsb, old_lsb, new_lsb; FT_Pos pp1x_uh, pp2x_uh; AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ]; AF_Edge edge1 = axis->edges; /* leftmost edge */ AF_Edge edge2 = edge1 + axis->num_edges - 1; /* rightmost edge */ if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) { old_rsb = loader->pp2.x - edge2->opos; old_lsb = edge1->opos; new_lsb = edge1->pos; /* remember unhinted values to later account */ /* for rounding errors */ pp1x_uh = new_lsb - old_lsb; pp2x_uh = edge2->pos + old_rsb; /* prefer too much space over too little space */ /* for very small sizes */ if ( old_lsb < 24 ) pp1x_uh -= 8; if ( old_rsb < 24 ) pp2x_uh += 8; loader->pp1.x = FT_PIX_ROUND( pp1x_uh ); loader->pp2.x = FT_PIX_ROUND( pp2x_uh ); if ( loader->pp1.x >= new_lsb && old_lsb > 0 ) loader->pp1.x -= 64; if ( loader->pp2.x <= edge2->pos && old_rsb > 0 ) loader->pp2.x += 64; slot->lsb_delta = loader->pp1.x - pp1x_uh; slot->rsb_delta = loader->pp2.x - pp2x_uh; } else { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; loader->pp1.x = FT_PIX_ROUND( pp1x ); loader->pp2.x = FT_PIX_ROUND( pp2x ); slot->lsb_delta = loader->pp1.x - pp1x; slot->rsb_delta = loader->pp2.x - pp2x; } } else { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta ); loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta ); slot->lsb_delta = loader->pp1.x - pp1x; slot->rsb_delta = loader->pp2.x - pp2x; } break; default: /* we don't support other formats (yet?) */ error = FT_THROW( Unimplemented_Feature ); } Hint_Metrics: { FT_BBox bbox; FT_Vector vvector; vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX; vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY; vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale ); vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale ); /* transform the hinted outline if needed */ if ( loader->transformed ) { FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix ); FT_Vector_Transform( &vvector, &loader->trans_matrix ); } #if 1 /* we must translate our final outline by -pp1.x and compute */ /* the new metrics */ if ( loader->pp1.x ) FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 ); #endif FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); bbox.xMax = FT_PIX_CEIL( bbox.xMax ); bbox.yMax = FT_PIX_CEIL( bbox.yMax ); slot->metrics.width = bbox.xMax - bbox.xMin; slot->metrics.height = bbox.yMax - bbox.yMin; slot->metrics.horiBearingX = bbox.xMin; slot->metrics.horiBearingY = bbox.yMax; slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x ); slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y ); /* for mono-width fonts (like Andale, Courier, etc.) we need */ /* to keep the original rounded advance width; ditto for */ /* digits if all have the same advance width */ #if 0 if ( !FT_IS_FIXED_WIDTH( slot->face ) ) slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; else slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, x_scale ); #else if ( scaler->render_mode != FT_RENDER_MODE_LIGHT && ( FT_IS_FIXED_WIDTH( slot->face ) || ( af_face_globals_is_digit( loader->globals, glyph_index ) && metrics->digits_have_same_width ) ) ) { slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, metrics->scaler.x_scale ); /* Set delta values to 0. Otherwise code that uses them is */ /* going to ruin the fixed advance width. */ slot->lsb_delta = 0; slot->rsb_delta = 0; } else { /* non-spacing glyphs must stay as-is */ if ( slot->metrics.horiAdvance ) slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; } #endif slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance, metrics->scaler.y_scale ); slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance ); #if 0 /* reassign all outline fields except flags to protect them */ slot->outline.n_contours = internal->loader->base.outline.n_contours; slot->outline.n_points = internal->loader->base.outline.n_points; slot->outline.points = internal->loader->base.outline.points; slot->outline.tags = internal->loader->base.outline.tags; slot->outline.contours = internal->loader->base.outline.contours; #endif slot->format = FT_GLYPH_FORMAT_OUTLINE; } Exit: return error; }
static FT_Error af_loader_load_g( AF_Loader loader, AF_Scaler scaler, FT_UInt glyph_index, FT_Int32 load_flags, FT_UInt depth ) { FT_Error error = 0; FT_Face face = loader->face; FT_GlyphLoader gloader = loader->gloader; AF_ScriptMetrics metrics = loader->metrics; AF_GlyphHints hints = &loader->hints; FT_GlyphSlot slot = face->glyph; FT_Slot_Internal internal = slot->internal; error = FT_Load_Glyph( face, glyph_index, load_flags ); if ( error ) goto Exit; loader->transformed = internal->glyph_transformed; if ( loader->transformed ) { FT_Matrix inverse; loader->trans_matrix = internal->glyph_matrix; loader->trans_delta = internal->glyph_delta; inverse = loader->trans_matrix; FT_Matrix_Invert( &inverse ); FT_Vector_Transform( &loader->trans_delta, &inverse ); } /* set linear metrics */ slot->linearHoriAdvance = slot->metrics.horiAdvance; slot->linearVertAdvance = slot->metrics.vertAdvance; switch ( slot->format ) { case FT_GLYPH_FORMAT_OUTLINE: /* translate the loaded glyph when an internal transform * is needed */ if ( loader->transformed ) FT_Outline_Translate( &slot->outline, loader->trans_delta.x, loader->trans_delta.y ); /* copy the outline points in the loader's current */ /* extra points which is used to keep original glyph coordinates */ error = FT_GlyphLoader_CheckPoints( gloader, slot->outline.n_points + 4, slot->outline.n_contours ); if ( error ) goto Exit; FT_ARRAY_COPY( gloader->current.outline.points, slot->outline.points, slot->outline.n_points ); FT_ARRAY_COPY( gloader->current.extra_points, slot->outline.points, slot->outline.n_points ); FT_ARRAY_COPY( gloader->current.outline.contours, slot->outline.contours, slot->outline.n_contours ); FT_ARRAY_COPY( gloader->current.outline.tags, slot->outline.tags, slot->outline.n_points ); gloader->current.outline.n_points = slot->outline.n_points; gloader->current.outline.n_contours = slot->outline.n_contours; /* compute original horizontal phantom points (and ignore */ /* vertical ones) */ loader->pp1.x = hints->x_delta; loader->pp1.y = hints->y_delta; loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, hints->x_scale ) + hints->x_delta; loader->pp2.y = hints->y_delta; /* be sure to check for spacing glyphs */ if ( slot->outline.n_points == 0 ) goto Hint_Metrics; /* now load the slot image into the auto-outline and run the */ /* automatic hinting process */ metrics->clazz->script_hints_apply( hints, &gloader->current.outline, metrics ); /* we now need to hint the metrics according to the change in */ /* width/positioning that occured during the hinting process */ { FT_Pos old_advance, old_rsb, old_lsb, new_lsb; FT_Pos pp1x_uh, pp2x_uh; AF_AxisHints axis = &hints->axis[ AF_DIMENSION_HORZ ]; AF_Edge edge1 = axis->edges; /* leftmost edge */ AF_Edge edge2 = edge1 + axis->num_edges - 1; /* rightmost edge */ if ( edge2 > edge1 ) { old_advance = loader->pp2.x; old_rsb = old_advance - edge2->opos; old_lsb = edge1->opos; new_lsb = edge1->pos; /* remember unhinted values to later account */ /* for rounding errors */ pp1x_uh = new_lsb - old_lsb; pp2x_uh = edge2->pos + old_rsb; /* prefer too much space over too little space */ /* for very small sizes */ if ( old_lsb < 24 ) pp1x_uh -= 5; if ( old_rsb < 24 ) pp2x_uh += 5; loader->pp1.x = FT_PIX_ROUND( pp1x_uh ); loader->pp2.x = FT_PIX_ROUND( pp2x_uh ); slot->lsb_delta = loader->pp1.x - pp1x_uh; slot->rsb_delta = loader->pp2.x - pp2x_uh; #if 0 /* try to fix certain bad advance computations */ if ( loader->pp2.x + loader->pp1.x == edge2->pos && old_rsb > 4 ) loader->pp2.x += 64; #endif } else { loader->pp1.x = FT_PIX_ROUND( loader->pp1.x ); loader->pp2.x = FT_PIX_ROUND( loader->pp2.x ); } } /* good, we simply add the glyph to our loader's base */ FT_GlyphLoader_Add( gloader ); break; case FT_GLYPH_FORMAT_COMPOSITE: { FT_UInt nn, num_subglyphs = slot->num_subglyphs; FT_UInt num_base_subgs, start_point; FT_SubGlyph subglyph; start_point = gloader->base.outline.n_points; /* first of all, copy the subglyph descriptors in the glyph loader */ error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs ); if ( error ) goto Exit; FT_ARRAY_COPY( gloader->current.subglyphs, slot->subglyphs, num_subglyphs ); gloader->current.num_subglyphs = num_subglyphs; num_base_subgs = gloader->base.num_subglyphs; /* now, read each subglyph independently */ for ( nn = 0; nn < num_subglyphs; nn++ ) { FT_Vector pp1, pp2; FT_Pos x, y; FT_UInt num_points, num_new_points, num_base_points; /* gloader.current.subglyphs can change during glyph loading due */ /* to re-allocation -- we must recompute the current subglyph on */ /* each iteration */ subglyph = gloader->base.subglyphs + num_base_subgs + nn; pp1 = loader->pp1; pp2 = loader->pp2; num_base_points = gloader->base.outline.n_points; error = af_loader_load_g( loader, scaler, subglyph->index, load_flags, depth + 1 ); if ( error ) goto Exit; /* recompute subglyph pointer */ subglyph = gloader->base.subglyphs + num_base_subgs + nn; if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS ) { pp1 = loader->pp1; pp2 = loader->pp2; } else { loader->pp1 = pp1; loader->pp2 = pp2; } num_points = gloader->base.outline.n_points; num_new_points = num_points - num_base_points; /* now perform the transform required for this subglyph */ if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE | FT_SUBGLYPH_FLAG_XY_SCALE | FT_SUBGLYPH_FLAG_2X2 ) ) { FT_Vector* cur = gloader->base.outline.points + num_base_points; FT_Vector* org = gloader->base.extra_points + num_base_points; FT_Vector* limit = cur + num_new_points; for ( ; cur < limit; cur++, org++ ) { FT_Vector_Transform( cur, &subglyph->transform ); FT_Vector_Transform( org, &subglyph->transform ); } } /* apply offset */ if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) ) { FT_Int k = subglyph->arg1; FT_UInt l = subglyph->arg2; FT_Vector* p1; FT_Vector* p2; if ( start_point + k >= num_base_points || l >= (FT_UInt)num_new_points ) { error = FT_Err_Invalid_Composite; goto Exit; } l += num_base_points; /* for now, only use the current point coordinates; */ /* we may consider another approach in the near future */ p1 = gloader->base.outline.points + start_point + k; p2 = gloader->base.outline.points + start_point + l; x = p1->x - p2->x; y = p1->y - p2->y; } else { x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta; y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta; x = FT_PIX_ROUND(x); y = FT_PIX_ROUND(y); } { FT_Outline dummy = gloader->base.outline; dummy.points += num_base_points; dummy.n_points = (short)num_new_points; FT_Outline_Translate( &dummy, x, y ); } } } break; default: /* we don't support other formats (yet?) */ error = FT_Err_Unimplemented_Feature; } Hint_Metrics: if ( depth == 0 ) { FT_BBox bbox; /* transform the hinted outline if needed */ if ( loader->transformed ) FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix ); /* we must translate our final outline by -pp1.x and compute */ /* the new metrics */ if ( loader->pp1.x ) FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 ); FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); bbox.xMax = FT_PIX_CEIL( bbox.xMax ); bbox.yMax = FT_PIX_CEIL( bbox.yMax ); slot->metrics.width = bbox.xMax - bbox.xMin; slot->metrics.height = bbox.yMax - bbox.yMin; slot->metrics.horiBearingX = bbox.xMin; slot->metrics.horiBearingY = bbox.yMax; /* for mono-width fonts (like Andale, Courier, etc.) we need */ /* to keep the original rounded advance width */ #if 0 if ( !FT_IS_FIXED_WIDTH( slot->face ) ) slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; else slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, x_scale ); #else /* for mono-width fonts (like Andale, Courier, etc.) we need */ /* to keep the original rounded advance width */ if ( !FT_IS_FIXED_WIDTH( slot->face ) ) slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; else slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, metrics->scaler.x_scale ); #endif slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); /* now copy outline into glyph slot */ FT_GlyphLoader_Rewind( internal->loader ); error = FT_GlyphLoader_CopyPoints( internal->loader, gloader ); if ( error ) goto Exit; slot->outline = internal->loader->base.outline; slot->format = FT_GLYPH_FORMAT_OUTLINE; } #ifdef DEBUG_HINTER af_debug_hinter = hinter; #endif Exit: return error; }
static FT_Error Load_Glyph(TTF_Font * font, Uint16 ch, c_glyph * cached, int want) { FT_Face face; FT_Error error; FT_GlyphSlot glyph; FT_Glyph_Metrics *metrics; FT_Outline *outline; if(!font || !font->face) { return FT_Err_Invalid_Handle; } face = font->face; /* Load the glyph */ if(!cached->index) { cached->index = FT_Get_Char_Index(face, ch); } error = FT_Load_Glyph(face, cached->index, FT_LOAD_DEFAULT); if(error) { return error; } /* Get our glyph shortcuts */ glyph = face->glyph; metrics = &glyph->metrics; outline = &glyph->outline; /* Get the glyph metrics if desired */ if((want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS)) { if(FT_IS_SCALABLE(face)) { /* Get the bounding box */ cached->minx = FT_FLOOR(metrics->horiBearingX); cached->maxx = cached->minx + FT_CEIL(metrics->width); cached->maxy = FT_FLOOR(metrics->horiBearingY); cached->miny = cached->maxy - FT_CEIL(metrics->height); cached->yoffset = font->ascent - cached->maxy; cached->advance = FT_CEIL(metrics->horiAdvance); } else { /* Get the bounding box for non-scalable format. * Again, freetype2 fills in many of the font metrics * with the value of 0, so some of the values we * need must be calculated differently with certain * assumptions about non-scalable formats. * */ cached->minx = FT_FLOOR(metrics->horiBearingX); cached->maxx = cached->minx + FT_CEIL(metrics->horiAdvance); cached->maxy = FT_FLOOR(metrics->horiBearingY); cached->miny = cached->maxy - FT_CEIL(face->available_sizes[font->font_size_family].height); cached->yoffset = 0; cached->advance = FT_CEIL(metrics->horiAdvance); } /* Adjust for bold and italic text */ if(font->style & TTF_STYLE_BOLD) { cached->maxx += font->glyph_overhang; } if(font->style & TTF_STYLE_ITALIC) { cached->maxx += (int) ceil(font->glyph_italics); } cached->stored |= CACHED_METRICS; } if(((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) || ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP))) { int mono = (want & CACHED_BITMAP); int i; FT_Bitmap *src; FT_Bitmap *dst; /* Handle the italic style */ if(font->style & TTF_STYLE_ITALIC) { FT_Matrix shear; shear.xx = 1 << 16; shear.xy = (int) (font->glyph_italics * (1 << 16)) / font->height; shear.yx = 0; shear.yy = 1 << 16; FT_Outline_Transform(outline, &shear); } /* Render the glyph */ if(mono) { error = FT_Render_Glyph(glyph, ft_render_mode_mono); } else { error = FT_Render_Glyph(glyph, ft_render_mode_normal); } if(error) { return error; } /* Copy over information to cache */ src = &glyph->bitmap; if(mono) { dst = &cached->bitmap; } else { dst = &cached->pixmap; } memcpy(dst, src, sizeof(*dst)); /* FT_Render_Glyph() and .fon fonts always generate a * two-color (black and white) glyphslot surface, even * when rendered in ft_render_mode_normal. This is probably * a freetype2 bug because it is inconsistent with the * freetype2 documentation under FT_Render_Mode section. * */ if(mono || !FT_IS_SCALABLE(face)) { dst->pitch *= 8; } /* Adjust for bold and italic text */ if(font->style & TTF_STYLE_BOLD) { int bump = font->glyph_overhang; dst->pitch += bump; dst->width += bump; } if(font->style & TTF_STYLE_ITALIC) { int bump = (int) ceil(font->glyph_italics); dst->pitch += bump; dst->width += bump; } if(dst->rows != 0) { dst->buffer = (unsigned char *) malloc(dst->pitch * dst->rows); if(!dst->buffer) { return FT_Err_Out_Of_Memory; } memset(dst->buffer, 0, dst->pitch * dst->rows); for(i = 0; i < src->rows; i++) { int soffset = i * src->pitch; int doffset = i * dst->pitch; if(mono) { unsigned char *srcp = src->buffer + soffset; unsigned char *dstp = dst->buffer + doffset; int j; for(j = 0; j < src->width; j += 8) { unsigned char ch = *srcp++; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; ch <<= 1; *dstp++ = (ch & 0x80) >> 7; } } else if(!FT_IS_SCALABLE(face)) { /* This special case wouldn't * be here if the FT_Render_Glyph() * function wasn't buggy when it tried * to render a .fon font with 256 * shades of gray. Instead, it * returns a black and white surface * and we have to translate it back * to a 256 gray shaded surface. * */ unsigned char *srcp = src->buffer + soffset; unsigned char *dstp = dst->buffer + doffset; unsigned char ch; int j, k; for(j = 0; j < src->width; j += 8) { ch = *srcp++; for(k = 0; k < 8; ++k) { if((ch & 0x80) >> 7) { *dstp++ = NUM_GRAYS - 1; } else { *dstp++ = 0x00; } ch <<= 1; } }
T1_Load_Glyph( T1_GlyphSlot glyph, T1_Size size, FT_UInt glyph_index, FT_Int32 load_flags ) { FT_Error error; T1_DecoderRec decoder; T1_Face face = (T1_Face)glyph->root.face; FT_Bool hinting; T1_Font type1 = &face->type1; PSAux_Service psaux = (PSAux_Service)face->psaux; const T1_Decoder_Funcs decoder_funcs = psaux->t1_decoder_funcs; FT_Matrix font_matrix; FT_Vector font_offset; FT_Data glyph_data; FT_Bool must_finish_decoder = FALSE; #ifdef FT_CONFIG_OPTION_INCREMENTAL FT_Bool glyph_data_loaded = 0; #endif if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) { error = T1_Err_Invalid_Argument; goto Exit; } FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); if ( load_flags & FT_LOAD_NO_RECURSE ) load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; if ( size ) { glyph->x_scale = size->root.metrics.x_scale; glyph->y_scale = size->root.metrics.y_scale; } else { glyph->x_scale = 0x10000L; glyph->y_scale = 0x10000L; } glyph->root.outline.n_points = 0; glyph->root.outline.n_contours = 0; hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 && ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; error = decoder_funcs->init( &decoder, (FT_Face)face, (FT_Size)size, (FT_GlyphSlot)glyph, (FT_Byte**)type1->glyph_names, face->blend, FT_BOOL( hinting ), FT_LOAD_TARGET_MODE( load_flags ), T1_Parse_Glyph ); if ( error ) goto Exit; must_finish_decoder = TRUE; decoder.builder.no_recurse = FT_BOOL( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ); decoder.num_subrs = type1->num_subrs; decoder.subrs = type1->subrs; decoder.subrs_len = type1->subrs_len; decoder.buildchar = face->buildchar; decoder.len_buildchar = face->len_buildchar; /* now load the unscaled outline */ error = T1_Parse_Glyph_And_Get_Char_String( &decoder, glyph_index, &glyph_data ); if ( error ) goto Exit; #ifdef FT_CONFIG_OPTION_INCREMENTAL glyph_data_loaded = 1; #endif font_matrix = decoder.font_matrix; font_offset = decoder.font_offset; /* save new glyph tables */ decoder_funcs->done( &decoder ); must_finish_decoder = FALSE; /* now, set the metrics -- this is rather simple, as */ /* the left side bearing is the xMin, and the top side */ /* bearing the yMax */ if ( !error ) { glyph->root.outline.flags &= FT_OUTLINE_OWNER; glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL; /* for composite glyphs, return only left side bearing and */ /* advance width */ if ( load_flags & FT_LOAD_NO_RECURSE ) { FT_Slot_Internal internal = glyph->root.internal; glyph->root.metrics.horiBearingX = FIXED_TO_INT( decoder.builder.left_bearing.x ); glyph->root.metrics.horiAdvance = FIXED_TO_INT( decoder.builder.advance.x ); internal->glyph_matrix = font_matrix; internal->glyph_delta = font_offset; internal->glyph_transformed = 1; } else { FT_BBox cbox; FT_Glyph_Metrics* metrics = &glyph->root.metrics; FT_Vector advance; /* copy the _unscaled_ advance width */ metrics->horiAdvance = FIXED_TO_INT( decoder.builder.advance.x ); glyph->root.linearHoriAdvance = FIXED_TO_INT( decoder.builder.advance.x ); glyph->root.internal->glyph_transformed = 0; /* make up vertical ones */ metrics->vertAdvance = ( face->type1.font_bbox.yMax - face->type1.font_bbox.yMin ) >> 16; glyph->root.linearVertAdvance = metrics->vertAdvance; glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; if ( size && size->root.metrics.y_ppem < 24 ) glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION; #if 1 /* apply the font matrix, if any */ if ( font_matrix.xx != 0x10000L || font_matrix.yy != font_matrix.xx || font_matrix.xy != 0 || font_matrix.yx != 0 ) FT_Outline_Transform( &glyph->root.outline, &font_matrix ); if ( font_offset.x || font_offset.y ) FT_Outline_Translate( &glyph->root.outline, font_offset.x, font_offset.y ); advance.x = metrics->horiAdvance; advance.y = 0; FT_Vector_Transform( &advance, &font_matrix ); metrics->horiAdvance = advance.x + font_offset.x; advance.x = 0; advance.y = metrics->vertAdvance; FT_Vector_Transform( &advance, &font_matrix ); metrics->vertAdvance = advance.y + font_offset.y; #endif if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) { /* scale the outline and the metrics */ FT_Int n; FT_Outline* cur = decoder.builder.base; FT_Vector* vec = cur->points; FT_Fixed x_scale = glyph->x_scale; FT_Fixed y_scale = glyph->y_scale; /* First of all, scale the points, if we are not hinting */ if ( !hinting || ! decoder.builder.hints_funcs ) for ( n = cur->n_points; n > 0; n--, vec++ ) { vec->x = FT_MulFix( vec->x, x_scale ); vec->y = FT_MulFix( vec->y, y_scale ); } /* Then scale the metrics */ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); } /* compute the other metrics */ FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); metrics->width = cbox.xMax - cbox.xMin; metrics->height = cbox.yMax - cbox.yMin; metrics->horiBearingX = cbox.xMin; metrics->horiBearingY = cbox.yMax; /* make up vertical ones */ ft_synthesize_vertical_metrics( metrics, metrics->vertAdvance ); } /* Set control data to the glyph charstrings. Note that this is */ /* _not_ zero-terminated. */ glyph->root.control_data = (FT_Byte*)glyph_data.pointer; glyph->root.control_len = glyph_data.length; }
static void loadglyph(font_t *f, glui32 cid) { FT_Vector v; int err; glui32 gid; int x; bitmap_t glyphs[GLI_SUBPIX]; int adv; gid = FT_Get_Char_Index(f->face, cid); if (gid == 0) gid = FT_Get_Char_Index(f->face, '?'); for (x = 0; x < GLI_SUBPIX; x++) { v.x = (x * 64) / GLI_SUBPIX; v.y = 0; FT_Set_Transform(f->face, 0, &v); err = FT_Load_Glyph(f->face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); if (err) winabort("FT_Load_Glyph"); if (f->make_bold) FT_Outline_Embolden(&f->face->glyph->outline, FT_MulFix(f->face->units_per_EM, f->face->size->metrics.y_scale) / 24); if (f->make_oblique) FT_Outline_Transform(&f->face->glyph->outline, &ftmat); if (gli_conf_lcd) err = FT_Render_Glyph(f->face->glyph, FT_RENDER_MODE_LCD); else err = FT_Render_Glyph(f->face->glyph, FT_RENDER_MODE_LIGHT); if (err) winabort("FT_Render_Glyph"); adv = (f->face->glyph->advance.x * GLI_SUBPIX + 32) / 64; glyphs[x].lsb = f->face->glyph->bitmap_left; glyphs[x].top = f->face->glyph->bitmap_top; glyphs[x].w = f->face->glyph->bitmap.width; glyphs[x].h = f->face->glyph->bitmap.rows; glyphs[x].pitch = f->face->glyph->bitmap.pitch; glyphs[x].data = malloc(glyphs[x].pitch * glyphs[x].h); if (gli_conf_lcd) gammacopy_lcd(glyphs[x].data, f->face->glyph->bitmap.buffer, glyphs[x].w, glyphs[x].h, glyphs[x].pitch); else gammacopy(glyphs[x].data, f->face->glyph->bitmap.buffer, glyphs[x].pitch * glyphs[x].h); } if (cid < 256) { f->lowloaded[cid/8] |= (1 << (cid%8)); f->lowadvs[cid] = adv; memcpy(f->lowglyphs[cid], glyphs, sizeof glyphs); } else { int idx = findhighglyph(cid, f->highentries, f->num_highentries); if (idx < 0) { idx = ~idx; /* make room if needed */ if (f->alloced_highentries == f->num_highentries) { fentry_t *newentries; int newsize = f->alloced_highentries * 2; if (!newsize) newsize = 2; newentries = malloc(newsize * sizeof(fentry_t)); if (!newentries) return; if (f->highentries) { memcpy(newentries, f->highentries, f->num_highentries * sizeof(fentry_t)); free(f->highentries); } f->highentries = newentries; f->alloced_highentries = newsize; } /* insert new glyph */ memmove(&f->highentries[idx+1], &f->highentries[idx], (f->num_highentries - idx) * sizeof(fentry_t)); f->highentries[idx].cid = cid; f->highentries[idx].adv = adv; memcpy(f->highentries[idx].glyph, glyphs, sizeof glyphs); f->num_highentries++; } } }
static FT_Error af_loader_embolden_glyph_in_slot( AF_Loader loader, FT_Face face, AF_StyleMetrics style_metrics ) { FT_Error error = FT_Err_Ok; FT_GlyphSlot slot = face->glyph; AF_FaceGlobals globals = loader->globals; AF_WritingSystemClass writing_system_class; FT_Size_Metrics* size_metrics = &face->size->internal->autohint_metrics; FT_Pos stdVW = 0; FT_Pos stdHW = 0; FT_Bool size_changed = size_metrics->x_ppem != globals->stem_darkening_for_ppem; FT_Fixed em_size = af_intToFixed( face->units_per_EM ); FT_Fixed em_ratio = FT_DivFix( af_intToFixed( 1000 ), em_size ); FT_Matrix scale_down_matrix = { 0x10000L, 0, 0, 0x10000L }; /* Skip stem darkening for broken fonts. */ if ( !face->units_per_EM ) { error = FT_ERR( Corrupted_Font_Header ); goto Exit; } /* * We depend on the writing system (script analyzers) to supply * standard widths for the script of the glyph we are looking at. If * it can't deliver, stem darkening is disabled. */ writing_system_class = af_writing_system_classes[style_metrics->style_class->writing_system]; if ( writing_system_class->style_metrics_getstdw ) writing_system_class->style_metrics_getstdw( style_metrics, &stdHW, &stdVW ); else { error = FT_ERR( Unimplemented_Feature ); goto Exit; } if ( size_changed || ( stdVW > 0 && stdVW != globals->standard_vertical_width ) ) { FT_Fixed darken_by_font_units_x, darken_x; darken_by_font_units_x = af_intToFixed( af_loader_compute_darkening( loader, face, stdVW ) ); darken_x = FT_DivFix( FT_MulFix( darken_by_font_units_x, size_metrics->x_scale ), em_ratio ); globals->standard_vertical_width = stdVW; globals->stem_darkening_for_ppem = size_metrics->x_ppem; globals->darken_x = af_fixedToInt( darken_x ); } if ( size_changed || ( stdHW > 0 && stdHW != globals->standard_horizontal_width ) ) { FT_Fixed darken_by_font_units_y, darken_y; darken_by_font_units_y = af_intToFixed( af_loader_compute_darkening( loader, face, stdHW ) ); darken_y = FT_DivFix( FT_MulFix( darken_by_font_units_y, size_metrics->y_scale ), em_ratio ); globals->standard_horizontal_width = stdHW; globals->stem_darkening_for_ppem = size_metrics->x_ppem; globals->darken_y = af_fixedToInt( darken_y ); /* * Scale outlines down on the Y-axis to keep them inside their blue * zones. The stronger the emboldening, the stronger the downscaling * (plus heuristical padding to prevent outlines still falling out * their zones due to rounding). * * Reason: `FT_Outline_Embolden' works by shifting the rightmost * points of stems farther to the right, and topmost points farther * up. This positions points on the Y-axis outside their * pre-computed blue zones and leads to distortion when applying the * hints in the code further below. Code outside this emboldening * block doesn't know we are presenting it with modified outlines the * analyzer didn't see! * * An unfortunate side effect of downscaling is that the emboldening * effect is slightly decreased. The loss becomes more pronounced * versus the CFF driver at smaller sizes, e.g., at 9ppem and below. */ globals->scale_down_factor = FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ), em_size ); } FT_Outline_EmboldenXY( &slot->outline, globals->darken_x, globals->darken_y ); scale_down_matrix.yy = globals->scale_down_factor; FT_Outline_Transform( &slot->outline, &scale_down_matrix ); Exit: return error; }
static FT_Error Load_Glyph( TTF_Font* font, unsigned short ch, c_glyph* cached, int want) { FT_Face face; FT_Error error; FT_GlyphSlot glyph; FT_Glyph_Metrics* metrics; FT_Outline* outline; assert( font ); assert( font->face ); face = font->face; /* Load the glyph */ if ( ! cached->index ) { cached->index = FT_Get_Char_Index( face, ch ); } error = FT_Load_Glyph( face, cached->index, FT_LOAD_DEFAULT ); if( error ) { return error; } /* Get our glyph shortcuts */ glyph = face->glyph; metrics = &glyph->metrics; outline = &glyph->outline; /* Get the glyph metrics if desired */ if ( (want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS) ) { /* Get the bounding box */ cached->minx = FT_FLOOR(metrics->horiBearingX); cached->maxx = cached->minx + FT_CEIL(metrics->width); cached->maxy = FT_FLOOR(metrics->horiBearingY); cached->miny = cached->maxy - FT_CEIL(metrics->height); cached->yoffset = font->ascent - cached->maxy; cached->advance = FT_CEIL(metrics->horiAdvance); /* Adjust for bold and italic text */ if( font->style & TTF_STYLE_BOLD ) { cached->maxx += font->glyph_overhang; } if( font->style & TTF_STYLE_ITALIC ) { cached->maxx += (int)ceil(font->glyph_italics); } cached->stored |= CACHED_METRICS; } if ( ((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) || ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)) ) { int mono = (want & CACHED_BITMAP); int i; FT_Bitmap* src; FT_Bitmap* dst; /* Handle the italic style */ if( font->style & TTF_STYLE_ITALIC ) { FT_Matrix shear; shear.xx = 1 << 16; shear.xy = (int) ( font->glyph_italics * ( 1 << 16 ) )/ font->height; shear.yx = 0; shear.yy = 1 << 16; FT_Outline_Transform( outline, &shear ); } /* Render the glyph */ if ( mono ) { error = FT_Render_Glyph( glyph, ft_render_mode_mono ); } else { error = FT_Render_Glyph( glyph, ft_render_mode_normal ); } if( error ) { return error; } /* Copy over information to cache */ src = &glyph->bitmap; if ( mono ) { dst = &cached->bitmap; } else { dst = &cached->pixmap; } memcpy( dst, src, sizeof( *dst ) ); if ( mono ) { dst->pitch *= 8; } /* Adjust for bold and italic text */ if( font->style & TTF_STYLE_BOLD ) { int bump = font->glyph_overhang; dst->pitch += bump; dst->width += bump; } if( font->style & TTF_STYLE_ITALIC ) { int bump = (int)ceil(font->glyph_italics); dst->pitch += bump; dst->width += bump; } if (dst->rows != 0) { dst->buffer = malloc( dst->pitch * dst->rows ); if( !dst->buffer ) { return FT_Err_Out_Of_Memory; } memset( dst->buffer, 0, dst->pitch * dst->rows ); for( i = 0; i < src->rows; i++ ) { int soffset = i * src->pitch; int doffset = i * dst->pitch; if ( mono ) { unsigned char *srcp = src->buffer + soffset; unsigned char *dstp = dst->buffer + doffset; int j; for ( j = 0; j < src->width; j += 8 ) { unsigned char ch = *srcp++; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; ch <<= 1; *dstp++ = (ch&0x80) >> 7; } } else { memcpy(dst->buffer+doffset, src->buffer+soffset,src->pitch); } }
pfr_slot_load( FT_GlyphSlot pfrslot, /* PFR_Slot */ FT_Size pfrsize, /* PFR_Size */ FT_UInt gindex, FT_Int32 load_flags ) { PFR_Slot slot = (PFR_Slot)pfrslot; PFR_Size size = (PFR_Size)pfrsize; FT_Error error; PFR_Face face = (PFR_Face)pfrslot->face; PFR_Char gchar; FT_Outline* outline = &pfrslot->outline; FT_ULong gps_offset; if ( gindex > 0 ) gindex--; /* check that the glyph index is correct */ FT_ASSERT( gindex < face->phy_font.num_chars ); /* try to load an embedded bitmap */ if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 ) { error = pfr_slot_load_bitmap( slot, size, gindex ); if ( error == 0 ) goto Exit; } if ( load_flags & FT_LOAD_SBITS_ONLY ) { error = PFR_Err_Invalid_Argument; goto Exit; } gchar = face->phy_font.chars + gindex; pfrslot->format = FT_GLYPH_FORMAT_OUTLINE; outline->n_points = 0; outline->n_contours = 0; gps_offset = face->header.gps_section_offset; /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */ error = pfr_glyph_load( &slot->glyph, face->root.stream, gps_offset, gchar->gps_offset, gchar->gps_size ); if ( !error ) { FT_BBox cbox; FT_Glyph_Metrics* metrics = &pfrslot->metrics; FT_Pos advance; FT_Int em_metrics, em_outline; FT_Bool scaling; scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); /* copy outline data */ *outline = slot->glyph.loader->base.outline; outline->flags &= ~FT_OUTLINE_OWNER; outline->flags |= FT_OUTLINE_REVERSE_FILL; if ( size && pfrsize->metrics.y_ppem < 24 ) outline->flags |= FT_OUTLINE_HIGH_PRECISION; /* compute the advance vector */ metrics->horiAdvance = 0; metrics->vertAdvance = 0; advance = gchar->advance; em_metrics = face->phy_font.metrics_resolution; em_outline = face->phy_font.outline_resolution; if ( em_metrics != em_outline ) advance = FT_MulDiv( advance, em_outline, em_metrics ); if ( face->phy_font.flags & PFR_PHY_VERTICAL ) metrics->vertAdvance = advance; else metrics->horiAdvance = advance; pfrslot->linearHoriAdvance = metrics->horiAdvance; pfrslot->linearVertAdvance = metrics->vertAdvance; /* make-up vertical metrics(?) */ metrics->vertBearingX = 0; metrics->vertBearingY = 0; /* Apply the font matrix, if any. */ /* TODO: Test existing fonts with unusual matrix */ /* whether we have to adjust Units per EM. */ { FT_Matrix font_matrix; font_matrix.xx = face->log_font.matrix[0] << 8; font_matrix.yx = face->log_font.matrix[1] << 8; font_matrix.xy = face->log_font.matrix[2] << 8; font_matrix.yy = face->log_font.matrix[3] << 8; FT_Outline_Transform( outline, &font_matrix ); } /* scale when needed */ if ( scaling ) { FT_Int n; FT_Fixed x_scale = pfrsize->metrics.x_scale; FT_Fixed y_scale = pfrsize->metrics.y_scale; FT_Vector* vec = outline->points; /* scale outline points */ for ( n = 0; n < outline->n_points; n++, vec++ ) { vec->x = FT_MulFix( vec->x, x_scale ); vec->y = FT_MulFix( vec->y, y_scale ); } /* scale the advance */ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); } /* compute the rest of the metrics */ FT_Outline_Get_CBox( outline, &cbox ); metrics->width = cbox.xMax - cbox.xMin; metrics->height = cbox.yMax - cbox.yMin; metrics->horiBearingX = cbox.xMin; metrics->horiBearingY = cbox.yMax - metrics->height; } Exit: return error; }
static FT_Error Render_Slanted( int num_indices, int first_index ) { int start_x, start_y, step_y, x, y; int i; FT_Size size; FT_Face face; FT_GlyphSlot slot; FT_Matrix shear; error = FTDemo_Get_Size( handle, &size ); if ( error ) { /* probably a non-existent bitmap font size */ return error; } INIT_SIZE( size, start_x, start_y, step_y, x, y ); face = size->face; slot = face->glyph; /***************************************************************/ /* */ /* 2*2 affine transformation matrix, 16.16 fixed float format */ /* */ /* Shear matrix: */ /* */ /* | x' | | 1 k | | x | x' = x + ky */ /* | | = | | * | | <==> */ /* | y' | | 0 1 | | y | y' = y */ /* */ /* outline' shear outline */ /* */ /***************************************************************/ shear.xx = 1 << 16; shear.xy = (FT_Fixed)( status.slant * ( 1 << 16 ) ); shear.yx = 0; shear.yy = 1 << 16; for ( i = first_index; i < num_indices; i++ ) { int gindex; if ( handle->encoding == FT_ENCODING_NONE ) gindex = i; else gindex = FTDemo_Get_Index( handle, i ); error = FT_Load_Glyph( face, gindex, handle->load_flags ); if ( !error ) { FT_Outline_Transform( &slot->outline, &shear ); error = FTDemo_Draw_Slot( handle, display, slot, &x, &y ); if ( error ) goto Next; else if ( X_TOO_LONG( x, size, display ) ) { x = start_x; y += step_y; if ( Y_TOO_LONG( y, size, display ) ) break; } } else Next: status.Fail++; } return error; }
T1_Load_Glyph( FT_GlyphSlot t1glyph, /* T1_GlyphSlot */ FT_Size t1size, /* T1_Size */ FT_UInt glyph_index, FT_Int32 load_flags ) { T1_GlyphSlot glyph = (T1_GlyphSlot)t1glyph; FT_Error error; #ifdef __REACTOS__ T1_DecoderRec *decoder = malloc(sizeof(T1_DecoderRec)); if (!decoder) return FT_THROW( Out_Of_Memory ); /* Ugly but it allows us to reduce the diff */ #define decoder (*decoder) { #else T1_DecoderRec decoder; #endif T1_Face face = (T1_Face)t1glyph->face; FT_Bool hinting; FT_Bool scaled; FT_Bool force_scaling = FALSE; T1_Font type1 = &face->type1; PSAux_Service psaux = (PSAux_Service)face->psaux; const T1_Decoder_Funcs decoder_funcs = psaux->t1_decoder_funcs; FT_Matrix font_matrix; FT_Vector font_offset; FT_Data glyph_data; FT_Bool must_finish_decoder = FALSE; #ifdef FT_CONFIG_OPTION_INCREMENTAL FT_Bool glyph_data_loaded = 0; #endif #ifdef FT_CONFIG_OPTION_INCREMENTAL if ( glyph_index >= (FT_UInt)face->root.num_glyphs && !face->root.internal->incremental_interface ) #else if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) #endif /* FT_CONFIG_OPTION_INCREMENTAL */ { error = FT_THROW( Invalid_Argument ); goto Exit; } FT_TRACE1(( "T1_Load_Glyph: glyph index %d\n", glyph_index )); FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); if ( load_flags & FT_LOAD_NO_RECURSE ) load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; if ( t1size ) { glyph->x_scale = t1size->metrics.x_scale; glyph->y_scale = t1size->metrics.y_scale; } else { glyph->x_scale = 0x10000L; glyph->y_scale = 0x10000L; } t1glyph->outline.n_points = 0; t1glyph->outline.n_contours = 0; hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 && ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); glyph->hint = hinting; glyph->scaled = scaled; t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; error = decoder_funcs->init( &decoder, t1glyph->face, t1size, t1glyph, (FT_Byte**)type1->glyph_names, face->blend, FT_BOOL( hinting ), FT_LOAD_TARGET_MODE( load_flags ), T1_Parse_Glyph ); if ( error ) goto Exit; must_finish_decoder = TRUE; decoder.builder.no_recurse = FT_BOOL( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ); decoder.num_subrs = type1->num_subrs; decoder.subrs = type1->subrs; decoder.subrs_len = type1->subrs_len; decoder.subrs_hash = type1->subrs_hash; decoder.buildchar = face->buildchar; decoder.len_buildchar = face->len_buildchar; /* now load the unscaled outline */ error = T1_Parse_Glyph_And_Get_Char_String( &decoder, glyph_index, &glyph_data, &force_scaling ); if ( error ) goto Exit; #ifdef FT_CONFIG_OPTION_INCREMENTAL glyph_data_loaded = 1; #endif hinting = glyph->hint; font_matrix = decoder.font_matrix; font_offset = decoder.font_offset; /* save new glyph tables */ decoder_funcs->done( &decoder ); must_finish_decoder = FALSE; /* now, set the metrics -- this is rather simple, as */ /* the left side bearing is the xMin, and the top side */ /* bearing the yMax */ if ( !error ) { t1glyph->outline.flags &= FT_OUTLINE_OWNER; t1glyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; /* for composite glyphs, return only left side bearing and */ /* advance width */ if ( load_flags & FT_LOAD_NO_RECURSE ) { FT_Slot_Internal internal = t1glyph->internal; t1glyph->metrics.horiBearingX = FIXED_TO_INT( decoder.builder.left_bearing.x ); t1glyph->metrics.horiAdvance = FIXED_TO_INT( decoder.builder.advance.x ); internal->glyph_matrix = font_matrix; internal->glyph_delta = font_offset; internal->glyph_transformed = 1; } else { FT_BBox cbox; FT_Glyph_Metrics* metrics = &t1glyph->metrics; /* copy the _unscaled_ advance width */ metrics->horiAdvance = FIXED_TO_INT( decoder.builder.advance.x ); t1glyph->linearHoriAdvance = FIXED_TO_INT( decoder.builder.advance.x ); t1glyph->internal->glyph_transformed = 0; if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) { /* make up vertical ones */ metrics->vertAdvance = ( face->type1.font_bbox.yMax - face->type1.font_bbox.yMin ) >> 16; t1glyph->linearVertAdvance = metrics->vertAdvance; } else { metrics->vertAdvance = FIXED_TO_INT( decoder.builder.advance.y ); t1glyph->linearVertAdvance = FIXED_TO_INT( decoder.builder.advance.y ); } t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; if ( t1size && t1size->metrics.y_ppem < 24 ) t1glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; #if 1 /* apply the font matrix, if any */ if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || font_matrix.xy != 0 || font_matrix.yx != 0 ) { FT_Outline_Transform( &t1glyph->outline, &font_matrix ); metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, font_matrix.xx ); metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, font_matrix.yy ); } if ( font_offset.x || font_offset.y ) { FT_Outline_Translate( &t1glyph->outline, font_offset.x, font_offset.y ); metrics->horiAdvance += font_offset.x; metrics->vertAdvance += font_offset.y; } #endif if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling ) { /* scale the outline and the metrics */ FT_Int n; FT_Outline* cur = decoder.builder.base; FT_Vector* vec = cur->points; FT_Fixed x_scale = glyph->x_scale; FT_Fixed y_scale = glyph->y_scale; /* First of all, scale the points, if we are not hinting */ if ( !hinting || ! decoder.builder.hints_funcs ) for ( n = cur->n_points; n > 0; n--, vec++ ) { vec->x = FT_MulFix( vec->x, x_scale ); vec->y = FT_MulFix( vec->y, y_scale ); } /* Then scale the metrics */ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); } /* compute the other metrics */ FT_Outline_Get_CBox( &t1glyph->outline, &cbox ); metrics->width = cbox.xMax - cbox.xMin; metrics->height = cbox.yMax - cbox.yMin; metrics->horiBearingX = cbox.xMin; metrics->horiBearingY = cbox.yMax; if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) { /* make up vertical ones */ ft_synthesize_vertical_metrics( metrics, metrics->vertAdvance ); } }
static FT_Error af_loader_load_g( AF_Loader loader, AF_Scaler scaler, FT_UInt glyph_index, FT_Int32 load_flags ) { AF_Module module = loader->globals->module; FT_Error error; FT_Face face = loader->face; AF_StyleMetrics metrics = loader->metrics; AF_GlyphHints hints = loader->hints; FT_GlyphSlot slot = face->glyph; FT_Slot_Internal internal = slot->internal; FT_GlyphLoader gloader = internal->loader; FT_Int32 flags; flags = load_flags | FT_LOAD_LINEAR_DESIGN; error = FT_Load_Glyph( face, glyph_index, flags ); if ( error ) goto Exit; /* * Apply stem darkening (emboldening) here before hints are applied to * the outline. Glyphs are scaled down proportionally to the * emboldening so that curve points don't fall outside their precomputed * blue zones. * * Any emboldening done by the font driver (e.g., the CFF driver) * doesn't reach here because the autohinter loads the unprocessed * glyphs in font units for analysis (functions `af_*_metrics_init_*') * and then above to prepare it for the rasterizers by itself, * independently of the font driver. So emboldening must be done here, * within the autohinter. * * All glyphs to be autohinted pass through here one by one. The * standard widths can therefore change from one glyph to the next, * depending on what script a glyph is assigned to (each script has its * own set of standard widths and other metrics). The darkening amount * must therefore be recomputed for each size and * `standard_{vertical,horizontal}_width' change. */ if ( !module->no_stem_darkening ) { AF_FaceGlobals globals = loader->globals; AF_WritingSystemClass writing_system_class; FT_Pos stdVW = 0; FT_Pos stdHW = 0; FT_Bool size_changed = face->size->metrics.x_ppem != globals->stem_darkening_for_ppem; FT_Fixed em_size = af_intToFixed( face->units_per_EM ); FT_Fixed em_ratio = FT_DivFix( af_intToFixed( 1000 ), em_size ); FT_Matrix scale_down_matrix = { 0x10000L, 0, 0, 0x10000L }; /* Skip stem darkening for broken fonts. */ if ( !face->units_per_EM ) goto After_Emboldening; /* * We depend on the writing system (script analyzers) to supply * standard widths for the script of the glyph we are looking at. If * it can't deliver, stem darkening is effectively disabled. */ writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET[metrics->style_class->writing_system]; if ( writing_system_class->style_metrics_getstdw ) writing_system_class->style_metrics_getstdw( metrics, &stdHW, &stdVW ); else goto After_Emboldening; if ( size_changed || ( stdVW > 0 && stdVW != globals->standard_vertical_width ) ) { FT_Fixed darken_by_font_units_x, darken_x; darken_by_font_units_x = af_intToFixed( af_loader_compute_darkening( loader, face, stdVW ) ); darken_x = FT_DivFix( FT_MulFix( darken_by_font_units_x, face->size->metrics.x_scale ), em_ratio ); globals->standard_vertical_width = stdVW; globals->stem_darkening_for_ppem = face->size->metrics.x_ppem; globals->darken_x = af_fixedToInt( darken_x ); } if ( size_changed || ( stdHW > 0 && stdHW != globals->standard_horizontal_width ) ) { FT_Fixed darken_by_font_units_y, darken_y; darken_by_font_units_y = af_intToFixed( af_loader_compute_darkening( loader, face, stdHW ) ); darken_y = FT_DivFix( FT_MulFix( darken_by_font_units_y, face->size->metrics.y_scale ), em_ratio ); globals->standard_horizontal_width = stdHW; globals->stem_darkening_for_ppem = face->size->metrics.x_ppem; globals->darken_y = af_fixedToInt( darken_y ); /* * Scale outlines down on the Y-axis to keep them inside their blue * zones. The stronger the emboldening, the stronger the * downscaling (plus heuristical padding to prevent outlines still * falling out their zones due to rounding). * * Reason: `FT_Outline_Embolden' works by shifting the rightmost * points of stems farther to the right, and topmost points farther * up. This positions points on the Y-axis outside their * pre-computed blue zones and leads to distortion when applying the * hints in the code further below. Code outside this emboldening * block doesn't know we are presenting it with modified outlines * the analyzer didn't see! * * An unfortunate side effect of downscaling is that the emboldening * effect is slightly decreased. The loss becomes more pronounced * versus the CFF driver at smaller sizes, e.g., at 9ppem and below. */ globals->scale_down_factor = FT_DivFix( em_size - ( darken_by_font_units_y + af_intToFixed( 8 ) ), em_size ); } FT_Outline_EmboldenXY( &slot->outline, globals->darken_x, globals->darken_y ); scale_down_matrix.yy = globals->scale_down_factor; FT_Outline_Transform( &slot->outline, &scale_down_matrix ); } After_Emboldening: loader->transformed = internal->glyph_transformed; if ( loader->transformed ) { FT_Matrix inverse; loader->trans_matrix = internal->glyph_matrix; loader->trans_delta = internal->glyph_delta; inverse = loader->trans_matrix; if ( !FT_Matrix_Invert( &inverse ) ) FT_Vector_Transform( &loader->trans_delta, &inverse ); } switch ( slot->format ) { case FT_GLYPH_FORMAT_OUTLINE: /* translate the loaded glyph when an internal transform is needed */ if ( loader->transformed ) FT_Outline_Translate( &slot->outline, loader->trans_delta.x, loader->trans_delta.y ); /* compute original horizontal phantom points (and ignore */ /* vertical ones) */ loader->pp1.x = hints->x_delta; loader->pp1.y = hints->y_delta; loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, hints->x_scale ) + hints->x_delta; loader->pp2.y = hints->y_delta; /* be sure to check for spacing glyphs */ if ( slot->outline.n_points == 0 ) goto Hint_Metrics; /* now load the slot image into the auto-outline and run the */ /* automatic hinting process */ { #ifdef FT_CONFIG_OPTION_PIC AF_FaceGlobals globals = loader->globals; #endif AF_StyleClass style_class = metrics->style_class; AF_WritingSystemClass writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; if ( writing_system_class->style_hints_apply ) writing_system_class->style_hints_apply( glyph_index, hints, &gloader->base.outline, metrics ); } /* we now need to adjust the metrics according to the change in */ /* width/positioning that occurred during the hinting process */ if ( scaler->render_mode != FT_RENDER_MODE_LIGHT ) { FT_Pos old_rsb, old_lsb, new_lsb; FT_Pos pp1x_uh, pp2x_uh; AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ]; AF_Edge edge1 = axis->edges; /* leftmost edge */ AF_Edge edge2 = edge1 + axis->num_edges - 1; /* rightmost edge */ if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) { old_rsb = loader->pp2.x - edge2->opos; old_lsb = edge1->opos; new_lsb = edge1->pos; /* remember unhinted values to later account */ /* for rounding errors */ pp1x_uh = new_lsb - old_lsb; pp2x_uh = edge2->pos + old_rsb; /* prefer too much space over too little space */ /* for very small sizes */ if ( old_lsb < 24 ) pp1x_uh -= 8; if ( old_rsb < 24 ) pp2x_uh += 8; loader->pp1.x = FT_PIX_ROUND( pp1x_uh ); loader->pp2.x = FT_PIX_ROUND( pp2x_uh ); if ( loader->pp1.x >= new_lsb && old_lsb > 0 ) loader->pp1.x -= 64; if ( loader->pp2.x <= edge2->pos && old_rsb > 0 ) loader->pp2.x += 64; slot->lsb_delta = loader->pp1.x - pp1x_uh; slot->rsb_delta = loader->pp2.x - pp2x_uh; } else { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; loader->pp1.x = FT_PIX_ROUND( pp1x ); loader->pp2.x = FT_PIX_ROUND( pp2x ); slot->lsb_delta = loader->pp1.x - pp1x; slot->rsb_delta = loader->pp2.x - pp2x; } } else { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta ); loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta ); slot->lsb_delta = loader->pp1.x - pp1x; slot->rsb_delta = loader->pp2.x - pp2x; } break; default: /* we don't support other formats (yet?) */ error = FT_THROW( Unimplemented_Feature ); } Hint_Metrics: { FT_BBox bbox; FT_Vector vvector; vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX; vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY; vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale ); vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale ); /* transform the hinted outline if needed */ if ( loader->transformed ) { FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix ); FT_Vector_Transform( &vvector, &loader->trans_matrix ); } #if 1 /* we must translate our final outline by -pp1.x and compute */ /* the new metrics */ if ( loader->pp1.x ) FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 ); #endif FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); bbox.xMax = FT_PIX_CEIL( bbox.xMax ); bbox.yMax = FT_PIX_CEIL( bbox.yMax ); slot->metrics.width = bbox.xMax - bbox.xMin; slot->metrics.height = bbox.yMax - bbox.yMin; slot->metrics.horiBearingX = bbox.xMin; slot->metrics.horiBearingY = bbox.yMax; slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x ); slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y ); /* for mono-width fonts (like Andale, Courier, etc.) we need */ /* to keep the original rounded advance width; ditto for */ /* digits if all have the same advance width */ #if 0 if ( !FT_IS_FIXED_WIDTH( slot->face ) ) slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; else slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, x_scale ); #else if ( scaler->render_mode != FT_RENDER_MODE_LIGHT && ( FT_IS_FIXED_WIDTH( slot->face ) || ( af_face_globals_is_digit( loader->globals, glyph_index ) && metrics->digits_have_same_width ) ) ) { slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, metrics->scaler.x_scale ); /* Set delta values to 0. Otherwise code that uses them is */ /* going to ruin the fixed advance width. */ slot->lsb_delta = 0; slot->rsb_delta = 0; } else { /* non-spacing glyphs must stay as-is */ if ( slot->metrics.horiAdvance ) slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; } #endif slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance, metrics->scaler.y_scale ); slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance ); #if 0 /* reassign all outline fields except flags to protect them */ slot->outline.n_contours = internal->loader->base.outline.n_contours; slot->outline.n_points = internal->loader->base.outline.n_points; slot->outline.points = internal->loader->base.outline.points; slot->outline.tags = internal->loader->base.outline.tags; slot->outline.contours = internal->loader->base.outline.contours; #endif slot->format = FT_GLYPH_FORMAT_OUTLINE; } Exit: return error; }