/**************************************************************************** * * ftmm.c * * Multiple Master font support (body). * * Copyright (C) 1996-2019 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 #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_MM_WeightVector( FT_Face face, FT_UInt len, FT_Fixed* weightvector ) { FT_Error error; FT_Service_MultiMasters service; /* check of `face' delayed to `ft_face_get_mm_service' */ if ( len && !weightvector ) return FT_THROW( Invalid_Argument ); error = ft_face_get_mm_service( face, &service ); if ( !error ) { error = FT_ERR( Invalid_Argument ); if ( service->set_mm_weightvector ) error = service->set_mm_weightvector( face, len, weightvector ); } /* enforce recomputation of auto-hinting data */ if ( !error && face->autohint.finalizer ) { face->autohint.finalizer( face->autohint.data ); face->autohint.data = NULL; } return error; } FT_EXPORT_DEF( FT_Error ) FT_Get_MM_WeightVector( FT_Face face, FT_UInt* len, FT_Fixed* weightvector ) { FT_Error error; FT_Service_MultiMasters service; /* check of `face' delayed to `ft_face_get_mm_service' */ if ( len && !weightvector ) return FT_THROW( Invalid_Argument ); error = ft_face_get_mm_service( face, &service ); if ( !error ) { error = FT_ERR( Invalid_Argument ); if ( service->get_mm_weightvector ) error = service->get_mm_weightvector( face, len, weightvector ); } 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 */