xref: /aosp_15_r20/external/freetype/builds/windows/ftdebug.c (revision 63949dbd25bcc50c4e1178497ff9e9574d44fc5a)
1 /****************************************************************************
2  *
3  * ftdebug.c
4  *
5  *   Debugging and logging component for Win32 (body).
6  *
7  * Copyright (C) 1996-2023 by
8  * David Turner, Robert Wilhelm, and Werner Lemberg.
9  *
10  * This file is part of the FreeType project, and may only be used,
11  * modified, and distributed under the terms of the FreeType project
12  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
13  * this file you indicate that you have read the license and
14  * understand and accept it fully.
15  *
16  */
17 
18 
19   /**************************************************************************
20    *
21    * This component contains various macros and functions used to ease the
22    * debugging of the FreeType engine.  Its main purpose is in assertion
23    * checking, tracing, and error detection.
24    *
25    * There are now three debugging modes:
26    *
27    * - trace mode
28    *
29    *   Error and trace messages are sent to the log file (which can be the
30    *   standard error output).
31    *
32    * - error mode
33    *
34    *   Only error messages are generated.
35    *
36    * - release mode:
37    *
38    *   No error message is sent or generated.  The code is free from any
39    *   debugging parts.
40    *
41    */
42 
43 
44 #include <freetype/freetype.h>
45 #include <freetype/ftlogging.h>
46 #include <freetype/internal/ftdebug.h>
47 #include <freetype/internal/ftobjs.h>
48 
49 
50 #ifdef FT_DEBUG_LOGGING
51 
52   /**************************************************************************
53    *
54    * Variables used to control logging.
55    *
56    * 1. `ft_default_trace_level` stores the value of trace levels, which are
57    *    provided to FreeType using the `FT2_DEBUG` environment variable.
58    *
59    * 2. `ft_fileptr` stores the `FILE*` handle.
60    *
61    * 3. `ft_component` is a string that holds the name of `FT_COMPONENT`.
62    *
63    * 4. The flag `ft_component_flag` prints the name of `FT_COMPONENT` along
64    *    with the actual log message if set to true.
65    *
66    * 5. The flag `ft_timestamp_flag` prints time along with the actual log
67    *    message if set to ture.
68    *
69    * 6. `ft_have_newline_char` is used to differentiate between a log
70    *    message with and without a trailing newline character.
71    *
72    * 7. `ft_custom_trace_level` stores the custom trace level value, which
73    *    is provided by the user at run-time.
74    *
75    * We use `static` to avoid 'unused variable' warnings.
76    *
77    */
78   static const char*  ft_default_trace_level = NULL;
79   static FILE*        ft_fileptr             = NULL;
80   static const char*  ft_component           = NULL;
81   static FT_Bool      ft_component_flag      = FALSE;
82   static FT_Bool      ft_timestamp_flag      = FALSE;
83   static FT_Bool      ft_have_newline_char   = TRUE;
84   static const char*  ft_custom_trace_level  = NULL;
85 
86   /* declared in ftdebug.h */
87 
88   dlg_handler            ft_default_log_handler = NULL;
89   FT_Custom_Log_Handler  custom_output_handler  = NULL;
90 
91 #endif /* FT_DEBUG_LOGGING */
92 
93 
94 #ifdef FT_DEBUG_LEVEL_ERROR
95 
96 #define WIN32_LEAN_AND_MEAN
97 #include <windows.h>
98 
99 
100 #ifdef _WIN32_WCE
101 
102   FT_LOACAL_DEF( void )
OutputDebugStringA(LPCSTR lpOutputString)103   OutputDebugStringA( LPCSTR lpOutputString )
104   {
105     int            len;
106     LPWSTR         lpOutputStringW;
107 
108 
109     /* allocate memory space for converted string */
110     len = MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS,
111                                lpOutputString, -1, NULL, 0 );
112 
113     lpOutputStringW = (LPWSTR)_alloca( len * sizeof ( WCHAR ) );
114 
115     if ( !len || !lpOutputStringW )
116       return;
117 
118     /* now it is safe to do the translation */
119     MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS,
120                          lpOutputString, -1, lpOutputStringW, len );
121 
122     OutputDebugStringW( lpOutputStringW );
123   }
124 
125 #endif /* _WIN32_WCE */
126 
127 
128   /* documentation is in ftdebug.h */
129 
130   FT_BASE_DEF( void )
FT_Message(const char * fmt,...)131   FT_Message( const char*  fmt,
132               ... )
133   {
134     va_list  ap;
135 
136 
137     va_start( ap, fmt );
138     vfprintf( stderr, fmt, ap );
139 #if ( defined( _WIN32_WINNT ) && _WIN32_WINNT >= 0x0400 ) || \
140     ( defined( _WIN32_WCE )   && _WIN32_WCE   >= 0x0600 )
141     if ( IsDebuggerPresent() )
142     {
143       static char  buf[1024];
144 
145 
146       vsnprintf( buf, sizeof buf, fmt, ap );
147       OutputDebugStringA( buf );
148     }
149 #endif
150     va_end( ap );
151   }
152 
153 
154   /* documentation is in ftdebug.h */
155 
156   FT_BASE_DEF( void )
FT_Panic(const char * fmt,...)157   FT_Panic( const char*  fmt,
158             ... )
159   {
160     va_list  ap;
161 
162 
163     va_start( ap, fmt );
164     vfprintf( stderr, fmt, ap );
165 #if ( defined( _WIN32_WINNT ) && _WIN32_WINNT >= 0x0400 ) || \
166     ( defined( _WIN32_WCE )   && _WIN32_WCE   >= 0x0600 )
167     if ( IsDebuggerPresent() )
168     {
169       static char  buf[1024];
170 
171 
172       vsnprintf( buf, sizeof buf, fmt, ap );
173       OutputDebugStringA( buf );
174     }
175 #endif
176     va_end( ap );
177 
178     exit( EXIT_FAILURE );
179   }
180 
181 
182   /* documentation is in ftdebug.h */
183 
184   FT_BASE_DEF( int )
FT_Throw(FT_Error error,int line,const char * file)185   FT_Throw( FT_Error     error,
186             int          line,
187             const char*  file )
188   {
189 #if 0
190     /* activating the code in this block makes FreeType very chatty */
191     fprintf( stderr,
192              "%s:%d: error 0x%02x: %s\n",
193              file,
194              line,
195              error,
196              FT_Error_String( error ) );
197 #else
198     FT_UNUSED( error );
199     FT_UNUSED( line );
200     FT_UNUSED( file );
201 #endif
202 
203     return 0;
204   }
205 
206 #endif /* FT_DEBUG_LEVEL_ERROR */
207 
208 
209 #ifdef FT_DEBUG_LEVEL_TRACE
210 
211   /* array of trace levels, initialized to 0; */
212   /* this gets adjusted at run-time           */
213   static int  ft_trace_levels_enabled[trace_count];
214 
215   /* array of trace levels, always initialized to 0 */
216   static int  ft_trace_levels_disabled[trace_count];
217 
218   /* a pointer to either `ft_trace_levels_enabled' */
219   /* or `ft_trace_levels_disabled'                 */
220   int*  ft_trace_levels;
221 
222   /* define array of trace toggle names */
223 #define FT_TRACE_DEF( x )  #x ,
224 
225   static const char*  ft_trace_toggles[trace_count + 1] =
226   {
227 #include <freetype/internal/fttrace.h>
228     NULL
229   };
230 
231 #undef FT_TRACE_DEF
232 
233 
234   /* documentation is in ftdebug.h */
235 
236   FT_BASE_DEF( FT_Int )
FT_Trace_Get_Count(void)237   FT_Trace_Get_Count( void )
238   {
239     return trace_count;
240   }
241 
242 
243   /* documentation is in ftdebug.h */
244 
245   FT_BASE_DEF( const char * )
FT_Trace_Get_Name(FT_Int idx)246   FT_Trace_Get_Name( FT_Int  idx )
247   {
248     int  max = FT_Trace_Get_Count();
249 
250 
251     if ( idx < max )
252       return ft_trace_toggles[idx];
253     else
254       return NULL;
255   }
256 
257 
258   /* documentation is in ftdebug.h */
259 
260   FT_BASE_DEF( void )
FT_Trace_Disable(void)261   FT_Trace_Disable( void )
262   {
263     ft_trace_levels = ft_trace_levels_disabled;
264   }
265 
266 
267   /* documentation is in ftdebug.h */
268 
269   FT_BASE_DEF( void )
FT_Trace_Enable(void)270   FT_Trace_Enable( void )
271   {
272     ft_trace_levels = ft_trace_levels_enabled;
273   }
274 
275 
276   /**************************************************************************
277    *
278    * Initialize the tracing sub-system.  This is done by retrieving the
279    * value of the `FT2_DEBUG' environment variable.  It must be a list of
280    * toggles, separated by spaces, `;', or `,'.  Example:
281    *
282    *   export FT2_DEBUG="any:3 memory:7 stream:5"
283    *
284    * This requests that all levels be set to 3, except the trace level for
285    * the memory and stream components which are set to 7 and 5,
286    * respectively.
287    *
288    * See the file `include/freetype/internal/fttrace.h' for details of
289    * the available toggle names.
290    *
291    * The level must be between 0 and 7; 0 means quiet (except for serious
292    * runtime errors), and 7 means _very_ verbose.
293    */
294   FT_BASE_DEF( void )
ft_debug_init(void)295   ft_debug_init( void )
296   {
297     const char*  ft2_debug = NULL;
298 
299 
300 #ifdef FT_DEBUG_LOGGING
301     if ( ft_custom_trace_level != NULL )
302       ft2_debug = ft_custom_trace_level;
303     else
304       ft2_debug = ft_default_trace_level;
305 #else
306     ft2_debug = ft_getenv( "FT2_DEBUG" );
307 #endif
308 
309     if ( ft2_debug )
310     {
311       const char*  p = ft2_debug;
312       const char*  q;
313 
314 
315       for ( ; *p; p++ )
316       {
317         /* skip leading whitespace and separators */
318         if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' )
319           continue;
320 
321 #ifdef FT_DEBUG_LOGGING
322 
323         /* check extra arguments for logging */
324         if ( *p == '-' )
325         {
326           const char*  r = ++p;
327 
328 
329           if ( *r == 'v' )
330           {
331             const char*  s = ++r;
332 
333 
334             ft_component_flag = TRUE;
335 
336             if ( *s == 't' )
337             {
338               ft_timestamp_flag = TRUE;
339               p++;
340             }
341 
342             p++;
343           }
344 
345           else if ( *r == 't' )
346           {
347             const char*  s = ++r;
348 
349 
350             ft_timestamp_flag = TRUE;
351 
352             if ( *s == 'v' )
353             {
354               ft_component_flag = TRUE;
355               p++;
356             }
357 
358             p++;
359           }
360         }
361 
362 #endif /* FT_DEBUG_LOGGING */
363 
364         /* read toggle name, followed by ':' */
365         q = p;
366         while ( *p && *p != ':' )
367           p++;
368 
369         if ( !*p )
370           break;
371 
372         if ( *p == ':' && p > q )
373         {
374           FT_Int  n, i, len = (FT_Int)( p - q );
375           FT_Int  level = -1, found = -1;
376 
377 
378           for ( n = 0; n < trace_count; n++ )
379           {
380             const char*  toggle = ft_trace_toggles[n];
381 
382 
383             for ( i = 0; i < len; i++ )
384             {
385               if ( toggle[i] != q[i] )
386                 break;
387             }
388 
389             if ( i == len && toggle[i] == 0 )
390             {
391               found = n;
392               break;
393             }
394           }
395 
396           /* read level */
397           p++;
398           if ( *p )
399           {
400             level = *p - '0';
401             if ( level < 0 || level > 7 )
402               level = -1;
403           }
404 
405           if ( found >= 0 && level >= 0 )
406           {
407             if ( found == trace_any )
408             {
409               /* special case for `any' */
410               for ( n = 0; n < trace_count; n++ )
411                 ft_trace_levels_enabled[n] = level;
412             }
413             else
414               ft_trace_levels_enabled[found] = level;
415           }
416         }
417       }
418     }
419 
420     ft_trace_levels = ft_trace_levels_enabled;
421   }
422 
423 
424 #else  /* !FT_DEBUG_LEVEL_TRACE */
425 
426 
427   FT_BASE_DEF( void )
ft_debug_init(void)428   ft_debug_init( void )
429   {
430     /* nothing */
431   }
432 
433 
434   FT_BASE_DEF( FT_Int )
FT_Trace_Get_Count(void)435   FT_Trace_Get_Count( void )
436   {
437     return 0;
438   }
439 
440 
441   FT_BASE_DEF( const char * )
FT_Trace_Get_Name(FT_Int idx)442   FT_Trace_Get_Name( FT_Int  idx )
443   {
444     FT_UNUSED( idx );
445 
446     return NULL;
447   }
448 
449 
450   FT_BASE_DEF( void )
FT_Trace_Disable(void)451   FT_Trace_Disable( void )
452   {
453     /* nothing */
454   }
455 
456 
457   /* documentation is in ftdebug.h */
458 
459   FT_BASE_DEF( void )
FT_Trace_Enable(void)460   FT_Trace_Enable( void )
461   {
462     /* nothing */
463   }
464 
465 #endif /* !FT_DEBUG_LEVEL_TRACE */
466 
467 
468 #ifdef FT_DEBUG_LOGGING
469 
470   /**************************************************************************
471    *
472    * Initialize and de-initialize 'dlg' library.
473    *
474    */
475 
476   FT_BASE_DEF( void )
ft_logging_init(void)477   ft_logging_init( void )
478   {
479     ft_default_log_handler = ft_log_handler;
480     ft_default_trace_level = ft_getenv( "FT2_DEBUG" );
481 
482     if ( ft_getenv( "FT_LOGGING_FILE" ) )
483       ft_fileptr = ft_fopen( ft_getenv( "FT_LOGGING_FILE" ), "w" );
484     else
485       ft_fileptr = stderr;
486 
487     ft_debug_init();
488 
489     /* Set the default output handler for 'dlg'. */
490     dlg_set_handler( ft_default_log_handler, NULL );
491   }
492 
493 
494   FT_BASE_DEF( void )
ft_logging_deinit(void)495   ft_logging_deinit( void )
496   {
497     if ( ft_fileptr != stderr )
498       ft_fclose( ft_fileptr );
499   }
500 
501 
502   /**************************************************************************
503    *
504    * An output log handler for FreeType.
505    *
506    */
507   FT_BASE_DEF( void )
ft_log_handler(const struct dlg_origin * origin,const char * string,void * data)508   ft_log_handler( const struct dlg_origin*  origin,
509                   const char*               string,
510                   void*                     data )
511   {
512     char         features_buf[128];
513     char*        bufp = features_buf;
514 
515     FT_UNUSED( data );
516 
517 
518     if ( ft_have_newline_char )
519     {
520       const char*  features        = NULL;
521       size_t       features_length = 0;
522 
523 
524 #define FEATURES_TIMESTAMP            "[%h:%m] "
525 #define FEATURES_COMPONENT            "[%t] "
526 #define FEATURES_TIMESTAMP_COMPONENT  "[%h:%m %t] "
527 
528       if ( ft_timestamp_flag && ft_component_flag )
529       {
530         features        = FEATURES_TIMESTAMP_COMPONENT;
531         features_length = sizeof ( FEATURES_TIMESTAMP_COMPONENT );
532       }
533       else if ( ft_timestamp_flag )
534       {
535         features        = FEATURES_TIMESTAMP;
536         features_length = sizeof ( FEATURES_TIMESTAMP );
537       }
538       else if ( ft_component_flag )
539       {
540         features        = FEATURES_COMPONENT;
541         features_length = sizeof ( FEATURES_COMPONENT );
542       }
543 
544       if ( ft_component_flag || ft_timestamp_flag )
545       {
546         ft_strncpy( features_buf, features, features_length );
547         bufp += features_length - 1;
548       }
549 
550       if ( ft_component_flag )
551       {
552         size_t  tag_length = ft_strlen( *origin->tags );
553         size_t  i;
554 
555 
556         /* To vertically align tracing messages we compensate the */
557         /* different FT_COMPONENT string lengths by inserting an  */
558         /* appropriate amount of space characters.                */
559         for ( i = 0;
560               i < FT_MAX_TRACE_LEVEL_LENGTH - tag_length;
561               i++ )
562           *bufp++ = ' ';
563       }
564     }
565 
566     /* Finally add the format string for the tracing message. */
567     *bufp++ = '%';
568     *bufp++ = 'c';
569     *bufp   = '\0';
570 
571     dlg_generic_outputf_stream( ft_fileptr,
572                                 (const char*)features_buf,
573                                 origin,
574                                 string,
575                                 dlg_default_output_styles,
576                                 true );
577 
578     if ( ft_strrchr( string, '\n' ) )
579       ft_have_newline_char = TRUE;
580     else
581       ft_have_newline_char = FALSE;
582   }
583 
584 
585   /* documentation is in ftdebug.h */
586   FT_BASE_DEF( void )
ft_add_tag(const char * tag)587   ft_add_tag( const char*  tag )
588   {
589     ft_component = tag;
590 
591     dlg_add_tag( tag, NULL );
592   }
593 
594 
595   /* documentation is in ftdebug.h */
596   FT_BASE_DEF( void )
ft_remove_tag(const char * tag)597   ft_remove_tag( const char*  tag )
598   {
599     dlg_remove_tag( tag, NULL );
600   }
601 
602 
603   /* documentation is in ftlogging.h */
604 
605   FT_EXPORT_DEF( void )
FT_Trace_Set_Level(const char * level)606   FT_Trace_Set_Level( const char*  level )
607   {
608     ft_component_flag     = FALSE;
609     ft_timestamp_flag     = FALSE;
610     ft_custom_trace_level = level;
611 
612     ft_debug_init();
613   }
614 
615 
616   /* documentation is in ftlogging.h */
617 
618   FT_EXPORT_DEF( void )
FT_Trace_Set_Default_Level(void)619   FT_Trace_Set_Default_Level( void )
620   {
621     ft_component_flag     = FALSE;
622     ft_timestamp_flag     = FALSE;
623     ft_custom_trace_level = NULL;
624 
625     ft_debug_init();
626   }
627 
628 
629   /**************************************************************************
630    *
631    * Functions to handle a custom log handler.
632    *
633    */
634 
635   /* documentation is in ftlogging.h */
636 
637   FT_EXPORT_DEF( void )
FT_Set_Log_Handler(FT_Custom_Log_Handler handler)638   FT_Set_Log_Handler( FT_Custom_Log_Handler  handler )
639   {
640     custom_output_handler = handler;
641   }
642 
643 
644   /* documentation is in ftlogging.h */
645 
646   FT_EXPORT_DEF( void )
FT_Set_Default_Log_Handler(void)647   FT_Set_Default_Log_Handler( void )
648   {
649     custom_output_handler = NULL;
650   }
651 
652 
653   /* documentation is in ftdebug.h */
654   FT_BASE_DEF( void )
FT_Logging_Callback(const char * fmt,...)655   FT_Logging_Callback( const char*  fmt,
656                        ... )
657   {
658     va_list  ap;
659 
660 
661     va_start( ap, fmt );
662     custom_output_handler( ft_component, fmt, ap );
663     va_end( ap );
664   }
665 
666 #else /* !FT_DEBUG_LOGGING */
667 
668   FT_EXPORT_DEF( void )
FT_Trace_Set_Level(const char * level)669   FT_Trace_Set_Level( const char*  level )
670   {
671     FT_UNUSED( level );
672   }
673 
674 
675   FT_EXPORT_DEF( void )
FT_Trace_Set_Default_Level(void)676   FT_Trace_Set_Default_Level( void )
677   {
678     /* nothing */
679   }
680 
681 
682   FT_EXPORT_DEF( void )
FT_Set_Log_Handler(FT_Custom_Log_Handler handler)683   FT_Set_Log_Handler( FT_Custom_Log_Handler  handler )
684   {
685     FT_UNUSED( handler );
686   }
687 
688 
689   FT_EXPORT_DEF( void )
FT_Set_Default_Log_Handler(void)690   FT_Set_Default_Log_Handler( void )
691   {
692     /* nothing */
693   }
694 
695 #endif /* !FT_DEBUG_LOGGING */
696 
697 
698 /* END */
699