Source code

Revision control

Copy as Markdown

Other Tools

/****************************************************************************
*
* ftdebug.h
*
* Debugging and logging component (specification).
*
* Copyright (C) 1996-2024 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.
*
*
* IMPORTANT: A description of FreeType's debugging support can be
* found in 'docs/DEBUG.TXT'. Read it if you need to use or
* understand this code.
*
*/
#ifndef FTDEBUG_H_
#define FTDEBUG_H_
#include <ft2build.h>
#include FT_CONFIG_CONFIG_H
#include <freetype/freetype.h>
#include "compiler-macros.h"
#ifdef FT_DEBUG_LOGGING
#define DLG_STATIC
#include <dlg/output.h>
#include <dlg/dlg.h>
#include <freetype/ftlogging.h>
#endif /* FT_DEBUG_LOGGING */
FT_BEGIN_HEADER
/* force the definition of FT_DEBUG_LEVEL_TRACE if FT_DEBUG_LOGGING is */
/* already defined. */
/* */
#ifdef FT_DEBUG_LOGGING
#undef FT_DEBUG_LEVEL_TRACE
#define FT_DEBUG_LEVEL_TRACE
#endif
/* force the definition of FT_DEBUG_LEVEL_ERROR if FT_DEBUG_LEVEL_TRACE */
/* is already defined; this simplifies the following #ifdefs */
/* */
#ifdef FT_DEBUG_LEVEL_TRACE
#undef FT_DEBUG_LEVEL_ERROR
#define FT_DEBUG_LEVEL_ERROR
#endif
/**************************************************************************
*
* Define the trace enums as well as the trace levels array when they are
* needed.
*
*/
#ifdef FT_DEBUG_LEVEL_TRACE
#define FT_TRACE_DEF( x ) trace_ ## x ,
/* defining the enumeration */
typedef enum FT_Trace_
{
#include <freetype/internal/fttrace.h>
trace_count
} FT_Trace;
/* a pointer to the array of trace levels, */
/* provided by `src/base/ftdebug.c' */
extern int* ft_trace_levels;
#undef FT_TRACE_DEF
#endif /* FT_DEBUG_LEVEL_TRACE */
/**************************************************************************
*
* Define the FT_TRACE macro
*
* IMPORTANT!
*
* Each component must define the macro FT_COMPONENT to a valid FT_Trace
* value before using any TRACE macro.
*
* To get consistent logging output, there should be no newline character
* (i.e., '\n') or a single trailing one in the message string of
* `FT_TRACEx` and `FT_ERROR`.
*/
/*************************************************************************
*
* If FT_DEBUG_LOGGING is enabled, tracing messages are sent to dlg's API.
* If FT_DEBUG_LOGGING is disabled, tracing messages are sent to
* `FT_Message` (defined in ftdebug.c).
*/
#ifdef FT_DEBUG_LOGGING
/* we need two macros to convert the names of `FT_COMPONENT` to a string */
#define FT_LOGGING_TAG( x ) FT_LOGGING_TAG_( x )
#define FT_LOGGING_TAG_( x ) #x
/* we need two macros to convert the component and the trace level */
/* to a string that combines them */
#define FT_LOGGING_TAGX( x, y ) FT_LOGGING_TAGX_( x, y )
#define FT_LOGGING_TAGX_( x, y ) #x ":" #y
#define FT_LOG( level, varformat ) \
do \
{ \
const char* dlg_tag = FT_LOGGING_TAGX( FT_COMPONENT, level ); \
\
\
ft_add_tag( dlg_tag ); \
if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] >= level ) \
{ \
if ( custom_output_handler != NULL ) \
FT_Logging_Callback varformat; \
else \
dlg_trace varformat; \
} \
ft_remove_tag( dlg_tag ); \
} while( 0 )
#else /* !FT_DEBUG_LOGGING */
#define FT_LOG( level, varformat ) \
do \
{ \
if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] >= level ) \
FT_Message varformat; \
} while ( 0 )
#endif /* !FT_DEBUG_LOGGING */
#ifdef FT_DEBUG_LEVEL_TRACE
/* we need two macros here to make cpp expand `FT_COMPONENT' */
#define FT_TRACE_COMP( x ) FT_TRACE_COMP_( x )
#define FT_TRACE_COMP_( x ) trace_ ## x
#define FT_TRACE( level, varformat ) FT_LOG( level, varformat )
#else /* !FT_DEBUG_LEVEL_TRACE */
#define FT_TRACE( level, varformat ) do { } while ( 0 ) /* nothing */
#endif /* !FT_DEBUG_LEVEL_TRACE */
/**************************************************************************
*
* @function:
* FT_Trace_Get_Count
*
* @description:
* Return the number of available trace components.
*
* @return:
* The number of trace components. 0 if FreeType 2 is not built with
* FT_DEBUG_LEVEL_TRACE definition.
*
* @note:
* This function may be useful if you want to access elements of the
* internal trace levels array by an index.
*/
FT_BASE( FT_Int )
FT_Trace_Get_Count( void );
/**************************************************************************
*
* @function:
* FT_Trace_Get_Name
*
* @description:
* Return the name of a trace component.
*
* @input:
* The index of the trace component.
*
* @return:
* The name of the trace component. This is a statically allocated
* C~string, so do not free it after use. `NULL` if FreeType is not
* built with FT_DEBUG_LEVEL_TRACE definition.
*
* @note:
* Use @FT_Trace_Get_Count to get the number of available trace
* components.
*/
FT_BASE( const char* )
FT_Trace_Get_Name( FT_Int idx );
/**************************************************************************
*
* @function:
* FT_Trace_Disable
*
* @description:
* Switch off tracing temporarily. It can be activated again with
* @FT_Trace_Enable.
*/
FT_BASE( void )
FT_Trace_Disable( void );
/**************************************************************************
*
* @function:
* FT_Trace_Enable
*
* @description:
* Activate tracing. Use it after tracing has been switched off with
* @FT_Trace_Disable.
*/
FT_BASE( void )
FT_Trace_Enable( void );
/**************************************************************************
*
* You need two opening and closing parentheses!
*
* Example: FT_TRACE0(( "Value is %i", foo ))
*
* Output of the FT_TRACEX macros is sent to stderr.
*
*/
#define FT_TRACE0( varformat ) FT_TRACE( 0, varformat )
#define FT_TRACE1( varformat ) FT_TRACE( 1, varformat )
#define FT_TRACE2( varformat ) FT_TRACE( 2, varformat )
#define FT_TRACE3( varformat ) FT_TRACE( 3, varformat )
#define FT_TRACE4( varformat ) FT_TRACE( 4, varformat )
#define FT_TRACE5( varformat ) FT_TRACE( 5, varformat )
#define FT_TRACE6( varformat ) FT_TRACE( 6, varformat )
#define FT_TRACE7( varformat ) FT_TRACE( 7, varformat )
/**************************************************************************
*
* Define the FT_ERROR macro.
*
* Output of this macro is sent to stderr.
*
*/
#ifdef FT_DEBUG_LEVEL_ERROR
/**************************************************************************
*
* If FT_DEBUG_LOGGING is enabled, error messages are sent to dlg's API.
* If FT_DEBUG_LOGGING is disabled, error messages are sent to `FT_Message`
* (defined in ftdebug.c).
*
*/
#ifdef FT_DEBUG_LOGGING
#define FT_ERROR( varformat ) \
do \
{ \
const char* dlg_tag = FT_LOGGING_TAG( FT_COMPONENT ); \
\
\
ft_add_tag( dlg_tag ); \
dlg_trace varformat; \
ft_remove_tag( dlg_tag ); \
} while ( 0 )
#else /* !FT_DEBUG_LOGGING */
#define FT_ERROR( varformat ) FT_Message varformat
#endif /* !FT_DEBUG_LOGGING */
#else /* !FT_DEBUG_LEVEL_ERROR */
#define FT_ERROR( varformat ) do { } while ( 0 ) /* nothing */
#endif /* !FT_DEBUG_LEVEL_ERROR */
/**************************************************************************
*
* Define the FT_ASSERT and FT_THROW macros. The call to `FT_Throw` makes
* it possible to easily set a breakpoint at this function.
*
*/
#ifdef FT_DEBUG_LEVEL_ERROR
#define FT_ASSERT( condition ) \
do \
{ \
if ( !( condition ) ) \
FT_Panic( "assertion failed on line %d of file %s\n", \
__LINE__, __FILE__ ); \
} while ( 0 )
#define FT_THROW( e ) \
( FT_Throw( FT_ERR_CAT( FT_ERR_PREFIX, e ), \
__LINE__, \
__FILE__ ) | \
FT_ERR_CAT( FT_ERR_PREFIX, e ) )
#else /* !FT_DEBUG_LEVEL_ERROR */
#define FT_ASSERT( condition ) do { } while ( 0 )
#define FT_THROW( e ) FT_ERR_CAT( FT_ERR_PREFIX, e )
#endif /* !FT_DEBUG_LEVEL_ERROR */
/**************************************************************************
*
* Define `FT_Message` and `FT_Panic` when needed.
*
*/
#ifdef FT_DEBUG_LEVEL_ERROR
#include "stdio.h" /* for vfprintf() */
/* print a message */
FT_BASE( void )
FT_Message( const char* fmt,
... );
/* print a message and exit */
FT_BASE( void )
FT_Panic( const char* fmt,
... );
/* report file name and line number of an error */
FT_BASE( int )
FT_Throw( FT_Error error,
int line,
const char* file );
#endif /* FT_DEBUG_LEVEL_ERROR */
FT_BASE( void )
ft_debug_init( void );
#ifdef FT_DEBUG_LOGGING
/**************************************************************************
*
* 'dlg' uses output handlers to control how and where log messages are
* printed. Therefore we need to define a default output handler for
* FreeType.
*/
FT_BASE( void )
ft_log_handler( const struct dlg_origin* origin,
const char* string,
void* data );
/**************************************************************************
*
* 1. `ft_default_log_handler` stores the function pointer that is used
* internally by FreeType to print logs to a file.
*
* 2. `custom_output_handler` stores the function pointer to the callback
* function provided by the user.
*
* It is defined in `ftdebug.c`.
*/
extern dlg_handler ft_default_log_handler;
extern FT_Custom_Log_Handler custom_output_handler;
/**************************************************************************
*
* If FT_DEBUG_LOGGING macro is enabled, FreeType needs to initialize and
* un-initialize `FILE*`.
*
* These functions are defined in `ftdebug.c`.
*/
FT_BASE( void )
ft_logging_init( void );
FT_BASE( void )
ft_logging_deinit( void );
/**************************************************************************
*
* For printing the name of `FT_COMPONENT` along with the actual log we
* need to add a tag with the name of `FT_COMPONENT`.
*
* These functions are defined in `ftdebug.c`.
*/
FT_BASE( void )
ft_add_tag( const char* tag );
FT_BASE( void )
ft_remove_tag( const char* tag );
/**************************************************************************
*
* A function to print log data using a custom callback logging function
* (which is set using `FT_Set_Log_Handler`).
*
* This function is defined in `ftdebug.c`.
*/
FT_BASE( void )
FT_Logging_Callback( const char* fmt,
... );
#endif /* FT_DEBUG_LOGGING */
FT_END_HEADER
#endif /* FTDEBUG_H_ */
/* END */