* include/freetype/internal/ftdebug.h (FT_TRACE_COMP, FT_TRACE_COMP_): New auxiliary macros to add `trace_' prefix. (FT_TRACE): Use `FT_TRACE_COMP'. */* (FT_COMPONENT): Updated.
509 lines
12 KiB
C
509 lines
12 KiB
C
/****************************************************************************
|
|
*
|
|
* ftmm.c
|
|
*
|
|
* Multiple Master font support (body).
|
|
*
|
|
* Copyright 1996-2018 by
|
|
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
|
*
|
|
* This file is part of the FreeType project, and may only be used,
|
|
* modified, and distributed under the terms of the FreeType project
|
|
* license, LICENSE.TXT. By continuing to use, modify, or distribute
|
|
* this file you indicate that you have read the license and
|
|
* understand and accept it fully.
|
|
*
|
|
*/
|
|
|
|
|
|
#include <ft2build.h>
|
|
#include FT_INTERNAL_DEBUG_H
|
|
|
|
#include FT_MULTIPLE_MASTERS_H
|
|
#include FT_INTERNAL_OBJECTS_H
|
|
#include FT_SERVICE_MULTIPLE_MASTERS_H
|
|
#include FT_SERVICE_METRICS_VARIATIONS_H
|
|
|
|
|
|
/**************************************************************************
|
|
*
|
|
* The macro FT_COMPONENT is used in trace mode. It is an implicit
|
|
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
|
|
* messages during execution.
|
|
*/
|
|
#undef FT_COMPONENT
|
|
#define FT_COMPONENT mm
|
|
|
|
|
|
static FT_Error
|
|
ft_face_get_mm_service( FT_Face face,
|
|
FT_Service_MultiMasters *aservice )
|
|
{
|
|
FT_Error error;
|
|
|
|
|
|
*aservice = NULL;
|
|
|
|
if ( !face )
|
|
return FT_THROW( Invalid_Face_Handle );
|
|
|
|
error = FT_ERR( Invalid_Argument );
|
|
|
|
if ( FT_HAS_MULTIPLE_MASTERS( face ) )
|
|
{
|
|
FT_FACE_LOOKUP_SERVICE( face,
|
|
*aservice,
|
|
MULTI_MASTERS );
|
|
|
|
if ( *aservice )
|
|
error = FT_Err_Ok;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
static FT_Error
|
|
ft_face_get_mvar_service( FT_Face face,
|
|
FT_Service_MetricsVariations *aservice )
|
|
{
|
|
FT_Error error;
|
|
|
|
|
|
*aservice = NULL;
|
|
|
|
if ( !face )
|
|
return FT_THROW( Invalid_Face_Handle );
|
|
|
|
error = FT_ERR( Invalid_Argument );
|
|
|
|
if ( FT_HAS_MULTIPLE_MASTERS( face ) )
|
|
{
|
|
FT_FACE_LOOKUP_SERVICE( face,
|
|
*aservice,
|
|
METRICS_VARIATIONS );
|
|
|
|
if ( *aservice )
|
|
error = FT_Err_Ok;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
/* documentation is in ftmm.h */
|
|
|
|
FT_EXPORT_DEF( FT_Error )
|
|
FT_Get_Multi_Master( FT_Face face,
|
|
FT_Multi_Master *amaster )
|
|
{
|
|
FT_Error error;
|
|
FT_Service_MultiMasters service;
|
|
|
|
|
|
/* check of `face' delayed to `ft_face_get_mm_service' */
|
|
|
|
if ( !amaster )
|
|
return FT_THROW( Invalid_Argument );
|
|
|
|
error = ft_face_get_mm_service( face, &service );
|
|
if ( !error )
|
|
{
|
|
error = FT_ERR( Invalid_Argument );
|
|
if ( service->get_mm )
|
|
error = service->get_mm( face, amaster );
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
/* documentation is in ftmm.h */
|
|
|
|
FT_EXPORT_DEF( FT_Error )
|
|
FT_Get_MM_Var( FT_Face face,
|
|
FT_MM_Var* *amaster )
|
|
{
|
|
FT_Error error;
|
|
FT_Service_MultiMasters service;
|
|
|
|
|
|
/* check of `face' delayed to `ft_face_get_mm_service' */
|
|
|
|
if ( !amaster )
|
|
return FT_THROW( Invalid_Argument );
|
|
|
|
error = ft_face_get_mm_service( face, &service );
|
|
if ( !error )
|
|
{
|
|
error = FT_ERR( Invalid_Argument );
|
|
if ( service->get_mm_var )
|
|
error = service->get_mm_var( face, amaster );
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
/* documentation is in ftmm.h */
|
|
|
|
FT_EXPORT_DEF( FT_Error )
|
|
FT_Done_MM_Var( FT_Library library,
|
|
FT_MM_Var* amaster )
|
|
{
|
|
FT_Memory memory;
|
|
|
|
|
|
if ( !library )
|
|
return FT_THROW( Invalid_Library_Handle );
|
|
|
|
memory = library->memory;
|
|
FT_FREE( amaster );
|
|
|
|
return FT_Err_Ok;
|
|
}
|
|
|
|
|
|
/* documentation is in ftmm.h */
|
|
|
|
FT_EXPORT_DEF( FT_Error )
|
|
FT_Set_MM_Design_Coordinates( FT_Face face,
|
|
FT_UInt num_coords,
|
|
FT_Long* coords )
|
|
{
|
|
FT_Error error;
|
|
FT_Service_MultiMasters service;
|
|
|
|
|
|
/* check of `face' delayed to `ft_face_get_mm_service' */
|
|
|
|
if ( num_coords && !coords )
|
|
return FT_THROW( Invalid_Argument );
|
|
|
|
error = ft_face_get_mm_service( face, &service );
|
|
if ( !error )
|
|
{
|
|
error = FT_ERR( Invalid_Argument );
|
|
if ( service->set_mm_design )
|
|
error = service->set_mm_design( face, num_coords, coords );
|
|
}
|
|
|
|
/* enforce recomputation of auto-hinting data */
|
|
if ( !error && face->autohint.finalizer )
|
|
{
|
|
face->autohint.finalizer( face->autohint.data );
|
|
face->autohint.data = NULL;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
/* documentation is in ftmm.h */
|
|
|
|
FT_EXPORT_DEF( FT_Error )
|
|
FT_Set_Var_Design_Coordinates( FT_Face face,
|
|
FT_UInt num_coords,
|
|
FT_Fixed* coords )
|
|
{
|
|
FT_Error error;
|
|
FT_Service_MultiMasters service_mm = NULL;
|
|
FT_Service_MetricsVariations service_mvar = NULL;
|
|
|
|
|
|
/* check of `face' delayed to `ft_face_get_mm_service' */
|
|
|
|
if ( num_coords && !coords )
|
|
return FT_THROW( Invalid_Argument );
|
|
|
|
error = ft_face_get_mm_service( face, &service_mm );
|
|
if ( !error )
|
|
{
|
|
error = FT_ERR( Invalid_Argument );
|
|
if ( service_mm->set_var_design )
|
|
error = service_mm->set_var_design( face, num_coords, coords );
|
|
|
|
/* internal error code -1 means `no change'; we can exit immediately */
|
|
if ( error == -1 )
|
|
return FT_Err_Ok;
|
|
}
|
|
|
|
if ( !error )
|
|
{
|
|
(void)ft_face_get_mvar_service( face, &service_mvar );
|
|
|
|
if ( service_mvar && service_mvar->metrics_adjust )
|
|
service_mvar->metrics_adjust( face );
|
|
}
|
|
|
|
/* enforce recomputation of auto-hinting data */
|
|
if ( !error && face->autohint.finalizer )
|
|
{
|
|
face->autohint.finalizer( face->autohint.data );
|
|
face->autohint.data = NULL;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
/* documentation is in ftmm.h */
|
|
|
|
FT_EXPORT_DEF( FT_Error )
|
|
FT_Get_Var_Design_Coordinates( FT_Face face,
|
|
FT_UInt num_coords,
|
|
FT_Fixed* coords )
|
|
{
|
|
FT_Error error;
|
|
FT_Service_MultiMasters service;
|
|
|
|
|
|
/* check of `face' delayed to `ft_face_get_mm_service' */
|
|
|
|
if ( !coords )
|
|
return FT_THROW( Invalid_Argument );
|
|
|
|
error = ft_face_get_mm_service( face, &service );
|
|
if ( !error )
|
|
{
|
|
error = FT_ERR( Invalid_Argument );
|
|
if ( service->get_var_design )
|
|
error = service->get_var_design( face, num_coords, coords );
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
/* documentation is in ftmm.h */
|
|
|
|
FT_EXPORT_DEF( FT_Error )
|
|
FT_Set_MM_Blend_Coordinates( FT_Face face,
|
|
FT_UInt num_coords,
|
|
FT_Fixed* coords )
|
|
{
|
|
FT_Error error;
|
|
FT_Service_MultiMasters service_mm = NULL;
|
|
FT_Service_MetricsVariations service_mvar = NULL;
|
|
|
|
|
|
/* check of `face' delayed to `ft_face_get_mm_service' */
|
|
|
|
if ( num_coords && !coords )
|
|
return FT_THROW( Invalid_Argument );
|
|
|
|
error = ft_face_get_mm_service( face, &service_mm );
|
|
if ( !error )
|
|
{
|
|
error = FT_ERR( Invalid_Argument );
|
|
if ( service_mm->set_mm_blend )
|
|
error = service_mm->set_mm_blend( face, num_coords, coords );
|
|
|
|
/* internal error code -1 means `no change'; we can exit immediately */
|
|
if ( error == -1 )
|
|
return FT_Err_Ok;
|
|
}
|
|
|
|
if ( !error )
|
|
{
|
|
(void)ft_face_get_mvar_service( face, &service_mvar );
|
|
|
|
if ( service_mvar && service_mvar->metrics_adjust )
|
|
service_mvar->metrics_adjust( face );
|
|
}
|
|
|
|
/* enforce recomputation of auto-hinting data */
|
|
if ( !error && face->autohint.finalizer )
|
|
{
|
|
face->autohint.finalizer( face->autohint.data );
|
|
face->autohint.data = NULL;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
/* documentation is in ftmm.h */
|
|
|
|
/* This is exactly the same as the previous function. It exists for */
|
|
/* orthogonality. */
|
|
|
|
FT_EXPORT_DEF( FT_Error )
|
|
FT_Set_Var_Blend_Coordinates( FT_Face face,
|
|
FT_UInt num_coords,
|
|
FT_Fixed* coords )
|
|
{
|
|
FT_Error error;
|
|
FT_Service_MultiMasters service_mm = NULL;
|
|
FT_Service_MetricsVariations service_mvar = NULL;
|
|
|
|
|
|
/* check of `face' delayed to `ft_face_get_mm_service' */
|
|
|
|
if ( num_coords && !coords )
|
|
return FT_THROW( Invalid_Argument );
|
|
|
|
error = ft_face_get_mm_service( face, &service_mm );
|
|
if ( !error )
|
|
{
|
|
error = FT_ERR( Invalid_Argument );
|
|
if ( service_mm->set_mm_blend )
|
|
error = service_mm->set_mm_blend( face, num_coords, coords );
|
|
|
|
/* internal error code -1 means `no change'; we can exit immediately */
|
|
if ( error == -1 )
|
|
return FT_Err_Ok;
|
|
}
|
|
|
|
if ( !error )
|
|
{
|
|
(void)ft_face_get_mvar_service( face, &service_mvar );
|
|
|
|
if ( service_mvar && service_mvar->metrics_adjust )
|
|
service_mvar->metrics_adjust( face );
|
|
}
|
|
|
|
/* enforce recomputation of auto-hinting data */
|
|
if ( !error && face->autohint.finalizer )
|
|
{
|
|
face->autohint.finalizer( face->autohint.data );
|
|
face->autohint.data = NULL;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
/* documentation is in ftmm.h */
|
|
|
|
FT_EXPORT_DEF( FT_Error )
|
|
FT_Get_MM_Blend_Coordinates( FT_Face face,
|
|
FT_UInt num_coords,
|
|
FT_Fixed* coords )
|
|
{
|
|
FT_Error error;
|
|
FT_Service_MultiMasters service;
|
|
|
|
|
|
/* check of `face' delayed to `ft_face_get_mm_service' */
|
|
|
|
if ( !coords )
|
|
return FT_THROW( Invalid_Argument );
|
|
|
|
error = ft_face_get_mm_service( face, &service );
|
|
if ( !error )
|
|
{
|
|
error = FT_ERR( Invalid_Argument );
|
|
if ( service->get_mm_blend )
|
|
error = service->get_mm_blend( face, num_coords, coords );
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
/* documentation is in ftmm.h */
|
|
|
|
/* This is exactly the same as the previous function. It exists for */
|
|
/* orthogonality. */
|
|
|
|
FT_EXPORT_DEF( FT_Error )
|
|
FT_Get_Var_Blend_Coordinates( FT_Face face,
|
|
FT_UInt num_coords,
|
|
FT_Fixed* coords )
|
|
{
|
|
FT_Error error;
|
|
FT_Service_MultiMasters service;
|
|
|
|
|
|
/* check of `face' delayed to `ft_face_get_mm_service' */
|
|
|
|
if ( !coords )
|
|
return FT_THROW( Invalid_Argument );
|
|
|
|
error = ft_face_get_mm_service( face, &service );
|
|
if ( !error )
|
|
{
|
|
error = FT_ERR( Invalid_Argument );
|
|
if ( service->get_mm_blend )
|
|
error = service->get_mm_blend( face, num_coords, coords );
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
/* documentation is in ftmm.h */
|
|
|
|
FT_EXPORT_DEF( FT_Error )
|
|
FT_Get_Var_Axis_Flags( FT_MM_Var* master,
|
|
FT_UInt axis_index,
|
|
FT_UInt* flags )
|
|
{
|
|
FT_UShort* axis_flags;
|
|
|
|
|
|
if ( !master || !flags )
|
|
return FT_THROW( Invalid_Argument );
|
|
|
|
if ( axis_index >= master->num_axis )
|
|
return FT_THROW( Invalid_Argument );
|
|
|
|
/* the axis flags array immediately follows the data of `master' */
|
|
axis_flags = (FT_UShort*)&( master[1] );
|
|
*flags = axis_flags[axis_index];
|
|
|
|
return FT_Err_Ok;
|
|
}
|
|
|
|
|
|
/* documentation is in ftmm.h */
|
|
|
|
FT_EXPORT_DEF( FT_Error )
|
|
FT_Set_Named_Instance( FT_Face face,
|
|
FT_UInt instance_index )
|
|
{
|
|
FT_Error error;
|
|
|
|
FT_Service_MultiMasters service_mm = NULL;
|
|
FT_Service_MetricsVariations service_mvar = NULL;
|
|
|
|
|
|
/* check of `face' delayed to `ft_face_get_mm_service' */
|
|
|
|
error = ft_face_get_mm_service( face, &service_mm );
|
|
if ( !error )
|
|
{
|
|
error = FT_ERR( Invalid_Argument );
|
|
if ( service_mm->set_instance )
|
|
error = service_mm->set_instance( face, instance_index );
|
|
}
|
|
|
|
if ( !error )
|
|
{
|
|
(void)ft_face_get_mvar_service( face, &service_mvar );
|
|
|
|
if ( service_mvar && service_mvar->metrics_adjust )
|
|
service_mvar->metrics_adjust( face );
|
|
}
|
|
|
|
/* enforce recomputation of auto-hinting data */
|
|
if ( !error && face->autohint.finalizer )
|
|
{
|
|
face->autohint.finalizer( face->autohint.data );
|
|
face->autohint.data = NULL;
|
|
}
|
|
|
|
if ( !error )
|
|
{
|
|
face->face_index = ( instance_index << 16 ) |
|
|
( face->face_index & 0xFFFFL );
|
|
face->face_flags &= ~FT_FACE_FLAG_VARIATION;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
/* END */
|