blob: 5e6ea9d98359463e3b12564419ac1d63dabe4096 [file] [log] [blame]
Debugging within the FreeType sources
=====================================
I. Configuration macros
-----------------------
There are several ways to enable debugging features in a FreeType 2
builds. This is controlled through the definition of special macros
located in the file `ftoption.h'. The macros are:
FT_DEBUG_LEVEL_ERROR
#define this macro if you want to compile the `FT_ERROR' macro
calls to print error messages during program execution. This does
not stop the program. Very useful to spot invalid fonts during
development and to code workarounds for them.
FT_DEBUG_LEVEL_TRACE
#define this macro if you want to compile both macros `FT_ERROR'
and `FT_TRACE'. This also includes the variants `FT_TRACE0',
`FT_TRACE1', `FT_TRACE2', ..., `FT_TRACE7'.
The trace macros are used to send debugging messages when an
appropriate `debug level' is configured at runtime through the
`FT2_DEBUG' environment variable (more on this later).
FT_LOGGING
As mentioned above if `FT_DEBUG_LEVEL_ERROR' and
`FT_DEBUG_LEVEL_TRACE' macros are defined, FreeType will send the
debug and trace logs outputted from `FT_ERROR' and `FT_TRACE'
macros to `stderr'.
`FT_LOGGING' is a new macro which is introduced to enhance the
capabilities of `FT_TRACE' and `FT_ERROR' macros.
`FT_LOGGING' macro depends on `FT_DEBUG_LEVEL_TRACE' and
`FT_DEBUG_LEVEL_ERROR', therefore these macros will automatically
be #defined once `FT_LOGGING' macro is #defined and
the behaviour of `FT_TRACE' and `FT_ERROR' macros will change.
Now, `FT_TRACE' and `FT_ERROR' macros will start sending the
tracing and debugging messages to the file system instead of
`stderr'.
On the file system the log file will be generated on the path
specified using `FT_LOGGING_FILE' environment variable(more on
this later).
There is an additional support of logging Time and the name of
the `FT_COMPONENT' from which the current log is generated along
with the actual tracing and debugging message, and for this user
will have to define additional tags under the `FT2_DEBUG'
environment variable(More details under section `FT2_DEBUG' under
Environment Variables heading).
FT_DEBUG_MEMORY
If this macro is #defined, the FreeType engine is linked with a
small but effective debugging memory manager that tracks all
allocations and frees that are performed within the font engine.
When the `FT2_DEBUG_MEMORY' environment variable is defined at
runtime, a call to `FT_Done_FreeType' dumps memory statistics,
including the list of leaked memory blocks and optionally with the
source locations where these were allocated. It is always a very
good idea to define this in development builds. This works with
_any_ program linked to FreeType, but requires a big deal of
memory (the debugging memory manager never frees the blocks to the
heap in order to detect double frees).
When `FT2_DEBUG_MEMORY' isn't defined at runtime, the debugging
memory manager is ignored, and performance is unaffected.
II. Debugging macros
--------------------
Several macros can be used within the FreeType sources to help
debugging its code:
1. FT_ERROR(( ... ))
This macro is used to send debug messages that indicate relatively
serious errors (like broken font files) without stopping the
execution of the running program. Its code is compiled only when
either `FT_DEBUG_LEVEL_ERROR' or `FT_DEBUG_LEVEL_TRACE' are
defined in `ftoption.h'.
Note that you have to use a printf-like signature, but with double
parentheses, like in
FT_ERROR(( "your %s is not %s\n", "foo", "bar" ));
2. FT_ASSERT( condition )
This macro is used to check strong assertions at runtime. If its
condition isn't TRUE, the program aborts with a panic message.
Its code is compiled when either `FT_DEBUG_LEVEL_ERROR' or
`FT_DEBUG_LEVEL_TRACE' are defined. You don't need double
parentheses here. Example:
FT_ASSERT( ptr != NULL );
3. FT_TRACE( level, (message...) )
The `FT_TRACE' macro is used to send general-purpose debugging
messages during program execution. This macro uses an *implicit*
macro named `FT_COMPONENT', which names the current FreeType
component being run.
The developer should always define `FT_COMPONENT' as appropriate,
for example as in
#undef FT_COMPONENT
#define FT_COMPONENT io
The value of the `FT_COMPONENT' macro is one of the component
names defined in the internal file `internal/fttrace.h'. If you
modify the FreeType source code and insert a new `FT_COMPONENT'
macro, you must register it in `fttrace.h'. If you insert or
remove many trace macros, you can test for undefined or unused
trace macros with the script `src/tools/chktrcmp.py'.
Each such component is assigned a `debug level', ranging from
value 0 to 7, through the use of the `FT2_DEBUG' environment
variable (described below) when a program linked with FreeType
starts.
When `FT_TRACE' is called, its level is compared to the one of the
corresponding component. Messages with trace levels *higher* than
the corresponding component level are filtered out and never
printed. This means that trace messages with level 0 are always
printed, those with level 2 are only printed when the component
level is *at least* 2, etc.
The second parameter to `FT_TRACE' must contain parentheses and
corresponds to a printf-like call, as in
FT_TRACE( 2, ( "your %s is not %s\n", "foo", "bar" ) )
The shortcut macros `FT_TRACE0', `FT_TRACE1', `FT_TRACE2', ...,
`FT_TRACE7' can be used with constant level indices, and are much
cleaner to use, as in
FT_TRACE2(( "your %s is not %s\n", "foo", "bar" ));
III. Environment variables
--------------------------
The following environment variables control debugging output and
behaviour of FreeType at runtime.
FT2_DEBUG
This variable is only used when FreeType is built with
`FT_DEBUG_LEVEL_TRACE' defined. It contains a list of component
level definitions, following this format:
component1:level1 component2:level2 component3:level3 ...
where `componentX' is the name of a tracing component, as defined
in `fttrace.h'. `levelX' is the corresponding level to use at
runtime.
`any' is a special component name that is interpreted as `any/all
components'. For example, the following definitions
set FT2_DEBUG=any:2 memory:5 io:4 (on Windows)
export FT2_DEBUG="any:2 memory:5 io:4" (on Linux with bash)
both stipulate that all components should have level 2, except for
the memory and io components, which are set to the trace levels 5
and 4, respectively.
`FT_LOGGING' related tags:
As mentioned above in the `FT_LOGGING' section below are the
additional tags which can be added in `FT2_DEBUG' environment
variable to log the time and the value of `FT_COMPONENT' in the
actual log message:
* -v: For printing the name of FreeType's component from which
the current log is produced.
* -t: For printing the time(in milliseconds) along with actual
log message.
Example:
Case 1: FT2_DEBUG="any:7 memory:5 -vt"
[20:32:02:44969 ttload] table directory loaded
Case 2: FT2_DEBUG="any:7 memory:5 -t"
[20:32:02:44969 ttload] table directory loaded
Case 3: FT2_DEBUG="any:7 memory:5 -v"
[ttload] table directory loaded
FT_LOGGING_FILE
This variable is only used when FreeType is built with
`FT_LOGGING' macro defined. It contains the path to the file where
the user wants to put his log file.
On Linux with bash:
export FT_LOGGING_FILE="/tmp/freetype2.log"
On Windows:
set FT_LOGGING_FILE=C:\Users\AppData\Local\Temp\freetype2.log
FT2_DEBUG_MEMORY
This environment variable, when defined, tells FreeType to use a
debugging memory manager that tracks leaking memory blocks as well
as other common errors like double frees. It is also capable of
reporting _where_ the leaking blocks were allocated, which
considerably saves time when debugging new additions to the
library.
This code is only compiled when FreeType is built with the
`FT_DEBUG_MEMORY' macro #defined in `ftoption.h' though, it is
ignored in other builds.
FT2_ALLOC_TOTAL_MAX
This variable is ignored if `FT2_DEBUG_MEMORY' is not defined. It
allows you to specify a maximum heap size for all memory
allocations performed by FreeType. This is very useful to test
the robustness of the font engine and programs that use it in
tight memory conditions.
If it is undefined, or if its value is not strictly positive, no
allocation bounds are checked at runtime.
FT2_ALLOC_COUNT_MAX
This variable is ignored if `FT2_DEBUG_MEMORY' is not defined. It
allows you to specify a maximum number of memory allocations
performed by FreeType before returning the error
`FT_Err_Out_Of_Memory'. This is useful for debugging and testing
the engine's robustness.
If it is undefined, or if its value is not strictly positive, no
allocation bounds are checked at runtime.
FT2_KEEP_ALIVE
This variable is ignored if `FT2_DEBUG_MEMORY' is not defined.
`Keep alive' means that freed blocks aren't released to the heap.
This is useful to detect double-frees or weird heap corruption,
reporting the source code location of the original allocation and
deallocation in case of a problem. It uses large amounts of
memory, however.
If it is undefined, or if its value is not strictly positive,
freed blocks are released at runtime.
IV. Additional Capabilities with `FT_LOGGING'
--------------------------------------------
With the support of `FT_LOGGING', four APIs have been introduced for
providing additional debugging support to the applications using
FreeType.
FT_Trace_Set_Level( const char* )
If FreeType is configured with `FT_LOGGING' the levels of tracing
component set using `FT2_DEBUG' environment variable is considered
as a default value.
And this function can be used change/set the value of the levels
of tracing components at run-time.
NOTE: If the environment variable `FT2_DEBUG is not defined the
default value of the levels of tracing components will be NULL.
FT_Trace_Set_Default_Level():
If previously, `FT_Trace_Set_Level' functions is used to set new
values of the tracing components of FreeType, this function could
be used to reset the level of tracing components to the default
value.
Hence, the functions `FT_Trace_Set_Default_Level' and
`FT_Trace_Set_Level' could be combined and used together to
change the trace levels of FreeType's components for a particular
block of code.
FT_Set_Log_Handler( ft_custom_log_handler ):
This API has been provided under the `FT_LOGGING' macro to support
a feature wherein a custom log handler can be provided based on
user’s choice. Doing so, FreeType will start calling the custom
handler for new log messages and will no longer write these
messages in predefined log file of FreeType. It will totally
depend on user how the log messages will be handled.
User just need to call this API with an argument of type
ft_custom_log_handler which should match following function
prototype:
void (*ft_custom_log_handler)( const char* ft_component, \
const char* fmt, va_list args );
FT_Set_Default_Log_Handler():
If the user has chosen to set a custom log handler using the
`FT_Set_Log_Handler' API above, the current API can be used to
reset back the log handler to the Freetype's inbuilt log handler.
Hence, the functions `FT_Set_Default_Log_Handler' and
`FT_Set_Log_Handler' in combination can be used to separately
handle the trace or error logs generated by a particular block
of code.
Applications need to #include the following header file to avail the
above APIs:
#include<freetype/ftlogging.h>
------------------------------------------------------------------------
Copyright (C) 2002-2020 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.
--- end of DEBUG ---