FT_Outline_Copy( const FT_Outline* source, FT_Outline *target ) { FT_Int is_owner; if ( !source || !target || source->n_points != target->n_points || source->n_contours != target->n_contours ) return FT_Err_Invalid_Argument; if ( source == target ) return FT_Err_Ok; FT_ARRAY_COPY( target->points, source->points, source->n_points ); FT_ARRAY_COPY( target->tags, source->tags, source->n_points ); FT_ARRAY_COPY( target->contours, source->contours, source->n_contours ); /* copy all flags, except the `FT_OUTLINE_OWNER' one */ is_owner = target->flags & FT_OUTLINE_OWNER; target->flags = source->flags; target->flags &= ~FT_OUTLINE_OWNER; target->flags |= is_owner; return FT_Err_Ok; }
FT_GlyphLoader_CopyPoints( FT_GlyphLoader target, FT_GlyphLoader source ) { FT_Error error; FT_UInt num_points = source->base.outline.n_points; FT_UInt num_contours = source->base.outline.n_contours; error = FT_GlyphLoader_CheckPoints( target, num_points, num_contours ); if ( !error ) { FT_Outline* out = &target->base.outline; FT_Outline* in = &source->base.outline; FT_ARRAY_COPY( out->points, in->points, num_points ); FT_ARRAY_COPY( out->tags, in->tags, num_points ); FT_ARRAY_COPY( out->contours, in->contours, num_contours ); /* do we need to copy the extra points? */ if ( target->use_extra && source->use_extra ) FT_ARRAY_COPY( target->base.extra_points, source->base.extra_points, num_points ); out->n_points = (short)num_points; out->n_contours = (short)num_contours; FT_GlyphLoader_Adjust_Points( target ); } return error; }
ft_outline_glyph_init( FT_Glyph outline_glyph, FT_GlyphSlot slot ) { FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; FT_Error error = FT_Err_Ok; FT_Library library = FT_GLYPH( glyph )->library; FT_Outline* source = &slot->outline; FT_Outline* target = &glyph->outline; /* check format in glyph slot */ if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) { error = FT_Err_Invalid_Glyph_Format; goto Exit; } /* allocate new outline */ error = FT_Outline_New( library, source->n_points, source->n_contours, &glyph->outline ); if ( error ) goto Exit; /* copy it */ FT_ARRAY_COPY( target->points, source->points, source->n_points ); FT_ARRAY_COPY( target->tags, source->tags, source->n_points ); FT_ARRAY_COPY( target->contours, source->contours, source->n_contours ); /* copy all flags, except the `FT_OUTLINE_OWNER' one */ target->flags = source->flags | FT_OUTLINE_OWNER; Exit: return error; }
static FT_Error cff_encoding_load( CFF_Encoding encoding, CFF_Charset charset, FT_UInt num_glyphs, FT_Stream stream, FT_ULong base_offset, FT_ULong offset ) { FT_Error error = CFF_Err_Ok; FT_UInt count; FT_UInt j; FT_UShort glyph_sid; FT_UInt glyph_code; /* Check for charset->sids. If we do not have this, we fail. */ if ( !charset->sids ) { error = CFF_Err_Invalid_File_Format; goto Exit; } /* Zero out the code to gid/sid mappings. */ for ( j = 0; j < 256; j++ ) { encoding->sids [j] = 0; encoding->codes[j] = 0; } /* Note: The encoding table in a CFF font is indexed by glyph index; */ /* the first encoded glyph index is 1. Hence, we read the character */ /* code (`glyph_code') at index j and make the assignment: */ /* */ /* encoding->codes[glyph_code] = j + 1 */ /* */ /* We also make the assignment: */ /* */ /* encoding->sids[glyph_code] = charset->sids[j + 1] */ /* */ /* This gives us both a code to GID and a code to SID mapping. */ if ( offset > 1 ) { encoding->offset = base_offset + offset; /* we need to parse the table to determine its size */ if ( FT_STREAM_SEEK( encoding->offset ) || FT_READ_BYTE( encoding->format ) || FT_READ_BYTE( count ) ) goto Exit; switch ( encoding->format & 0x7F ) { case 0: { FT_Byte* p; /* By convention, GID 0 is always ".notdef" and is never */ /* coded in the font. Hence, the number of codes found */ /* in the table is `count+1'. */ /* */ encoding->count = count + 1; if ( FT_FRAME_ENTER( count ) ) goto Exit; p = (FT_Byte*)stream->cursor; for ( j = 1; j <= count; j++ ) { glyph_code = *p++; /* Make sure j is not too big. */ if ( j < num_glyphs ) { /* Assign code to GID mapping. */ encoding->codes[glyph_code] = (FT_UShort)j; /* Assign code to SID mapping. */ encoding->sids[glyph_code] = charset->sids[j]; } } FT_FRAME_EXIT(); } break; case 1: { FT_UInt nleft; FT_UInt i = 1; FT_UInt k; encoding->count = 0; /* Parse the Format1 ranges. */ for ( j = 0; j < count; j++, i += nleft ) { /* Read the first glyph code of the range. */ if ( FT_READ_BYTE( glyph_code ) ) goto Exit; /* Read the number of codes in the range. */ if ( FT_READ_BYTE( nleft ) ) goto Exit; /* Increment nleft, so we read `nleft + 1' codes/sids. */ nleft++; /* compute max number of character codes */ if ( (FT_UInt)nleft > encoding->count ) encoding->count = nleft; /* Fill in the range of codes/sids. */ for ( k = i; k < nleft + i; k++, glyph_code++ ) { /* Make sure k is not too big. */ if ( k < num_glyphs && glyph_code < 256 ) { /* Assign code to GID mapping. */ encoding->codes[glyph_code] = (FT_UShort)k; /* Assign code to SID mapping. */ encoding->sids[glyph_code] = charset->sids[k]; } } } /* simple check; one never knows what can be found in a font */ if ( encoding->count > 256 ) encoding->count = 256; } break; default: FT_ERROR(( "cff_encoding_load: invalid table format!\n" )); error = CFF_Err_Invalid_File_Format; goto Exit; } /* Parse supplemental encodings, if any. */ if ( encoding->format & 0x80 ) { FT_UInt gindex; /* count supplements */ if ( FT_READ_BYTE( count ) ) goto Exit; for ( j = 0; j < count; j++ ) { /* Read supplemental glyph code. */ if ( FT_READ_BYTE( glyph_code ) ) goto Exit; /* Read the SID associated with this glyph code. */ if ( FT_READ_USHORT( glyph_sid ) ) goto Exit; /* Assign code to SID mapping. */ encoding->sids[glyph_code] = glyph_sid; /* First, look up GID which has been assigned to */ /* SID glyph_sid. */ for ( gindex = 0; gindex < num_glyphs; gindex++ ) { if ( charset->sids[gindex] == glyph_sid ) { encoding->codes[glyph_code] = (FT_UShort)gindex; break; } } } } } else { /* We take into account the fact a CFF font can use a predefined */ /* encoding without containing all of the glyphs encoded by this */ /* encoding (see the note at the end of section 12 in the CFF */ /* specification). */ switch ( (FT_UInt)offset ) { case 0: /* First, copy the code to SID mapping. */ FT_ARRAY_COPY( encoding->sids, cff_standard_encoding, 256 ); goto Populate; case 1: /* First, copy the code to SID mapping. */ FT_ARRAY_COPY( encoding->sids, cff_expert_encoding, 256 ); Populate: /* Construct code to GID mapping from code to SID mapping */ /* and charset. */ encoding->count = 0; error = cff_charset_compute_cids( charset, num_glyphs, stream->memory ); if ( error ) goto Exit; for ( j = 0; j < 256; j++ ) { FT_UInt sid = encoding->sids[j]; FT_UInt gid = 0; if ( sid ) gid = cff_charset_cid_to_gindex( charset, sid ); if ( gid != 0 ) { encoding->codes[j] = (FT_UShort)gid; if ( encoding->count < j + 1 ) encoding->count = j + 1; } else { encoding->codes[j] = 0; encoding->sids [j] = 0; } } break; default: FT_ERROR(( "cff_encoding_load: invalid table format!\n" )); error = CFF_Err_Invalid_File_Format; goto Exit; } } Exit: /* Clean up if there was an error. */ return error; }
static FT_Error cff_charset_load( CFF_Charset charset, FT_UInt num_glyphs, FT_Stream stream, FT_ULong base_offset, FT_ULong offset, FT_Bool invert ) { FT_Memory memory = stream->memory; FT_Error error = CFF_Err_Ok; FT_UShort glyph_sid; /* If the the offset is greater than 2, we have to parse the */ /* charset table. */ if ( offset > 2 ) { FT_UInt j; charset->offset = base_offset + offset; /* Get the format of the table. */ if ( FT_STREAM_SEEK( charset->offset ) || FT_READ_BYTE( charset->format ) ) goto Exit; /* Allocate memory for sids. */ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* assign the .notdef glyph */ charset->sids[0] = 0; switch ( charset->format ) { case 0: if ( num_glyphs > 0 ) { if ( FT_FRAME_ENTER( ( num_glyphs - 1 ) * 2 ) ) goto Exit; for ( j = 1; j < num_glyphs; j++ ) charset->sids[j] = FT_GET_USHORT(); FT_FRAME_EXIT(); } break; case 1: case 2: { FT_UInt nleft; FT_UInt i; j = 1; while ( j < num_glyphs ) { /* Read the first glyph sid of the range. */ if ( FT_READ_USHORT( glyph_sid ) ) goto Exit; /* Read the number of glyphs in the range. */ if ( charset->format == 2 ) { if ( FT_READ_USHORT( nleft ) ) goto Exit; } else { if ( FT_READ_BYTE( nleft ) ) goto Exit; } /* Fill in the range of sids -- `nleft + 1' glyphs. */ for ( i = 0; j < num_glyphs && i <= nleft; i++, j++, glyph_sid++ ) charset->sids[j] = glyph_sid; } } break; default: FT_ERROR(( "cff_charset_load: invalid table format!\n" )); error = CFF_Err_Invalid_File_Format; goto Exit; } } else { /* Parse default tables corresponding to offset == 0, 1, or 2. */ /* CFF specification intimates the following: */ /* */ /* In order to use a predefined charset, the following must be */ /* true: The charset constructed for the glyphs in the font's */ /* charstrings dictionary must match the predefined charset in */ /* the first num_glyphs. */ charset->offset = offset; /* record charset type */ switch ( (FT_UInt)offset ) { case 0: if ( num_glyphs > 229 ) { FT_ERROR(( "cff_charset_load: implicit charset larger than\n" "predefined charset (Adobe ISO-Latin)!\n" )); error = CFF_Err_Invalid_File_Format; goto Exit; } /* Allocate memory for sids. */ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ FT_ARRAY_COPY( charset->sids, cff_isoadobe_charset, num_glyphs ); break; case 1: if ( num_glyphs > 166 ) { FT_ERROR(( "cff_charset_load: implicit charset larger than\n" "predefined charset (Adobe Expert)!\n" )); error = CFF_Err_Invalid_File_Format; goto Exit; } /* Allocate memory for sids. */ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ FT_ARRAY_COPY( charset->sids, cff_expert_charset, num_glyphs ); break; case 2: if ( num_glyphs > 87 ) { FT_ERROR(( "cff_charset_load: implicit charset larger than\n" "predefined charset (Adobe Expert Subset)!\n" )); error = CFF_Err_Invalid_File_Format; goto Exit; } /* Allocate memory for sids. */ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ FT_ARRAY_COPY( charset->sids, cff_expertsubset_charset, num_glyphs ); break; default: error = CFF_Err_Invalid_File_Format; goto Exit; } } /* we have to invert the `sids' array for subsetted CID-keyed fonts */ if ( invert ) error = cff_charset_compute_cids( charset, num_glyphs, memory ); Exit: /* Clean up if there was an error. */ if ( error ) { FT_FREE( charset->sids ); FT_FREE( charset->cids ); charset->format = 0; charset->offset = 0; charset->sids = 0; } 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; }
FT_Bitmap_Copy( FT_Library library, const FT_Bitmap *source, FT_Bitmap *target) { FT_Memory memory; FT_Error error = FT_Err_Ok; FT_Int pitch; FT_ULong size; FT_Int source_pitch_sign, target_pitch_sign; if ( !library ) return FT_THROW( Invalid_Library_Handle ); if ( !source || !target ) return FT_THROW( Invalid_Argument ); if ( source == target ) return FT_Err_Ok; source_pitch_sign = source->pitch < 0 ? -1 : 1; target_pitch_sign = target->pitch < 0 ? -1 : 1; if ( source->buffer == NULL ) { *target = *source; if ( source_pitch_sign != target_pitch_sign ) target->pitch = -target->pitch; return FT_Err_Ok; } memory = library->memory; pitch = source->pitch; if ( pitch < 0 ) pitch = -pitch; size = (FT_ULong)pitch * source->rows; if ( target->buffer ) { FT_Int target_pitch = target->pitch; FT_ULong target_size; if ( target_pitch < 0 ) target_pitch = -target_pitch; target_size = (FT_ULong)target_pitch * target->rows; if ( target_size != size ) (void)FT_QREALLOC( target->buffer, target_size, size ); } else (void)FT_QALLOC( target->buffer, size ); if ( !error ) { unsigned char *p; p = target->buffer; *target = *source; target->buffer = p; if ( source_pitch_sign == target_pitch_sign ) FT_MEM_COPY( target->buffer, source->buffer, size ); else { /* take care of bitmap flow */ FT_UInt i; FT_Byte* s = source->buffer; FT_Byte* t = target->buffer; t += pitch * ( target->rows - 1 ); for ( i = target->rows; i > 0; i-- ) { FT_ARRAY_COPY( t, s, pitch ); s += pitch; t -= pitch; } } } 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; }