//
//      Copyright(c) 1997 - 1999. Microsoft Corporation.
//

#ifndef __usp_dbg__
#define __usp_dbg__
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif


////    USP_DBG.HXX
//
//      We define three levels of debug support:
//
//      Highest  DBG=1, TRC=1  Invasive debug
//      Middle   DBG=0, TRC=1  Safe debug
//      Lowest   DBG=0, TRC=0  No debug
//
//      Safe debugging
//
//      o  Assertions and other failure trace messages
//      o  Flag controlled trace messages
//
//      Invasive debugging adds
//
//      o  Unflagged trace messages
//      o  Extra cross checking fields in internal structures
//      o  Extra win32 api calls for validity checking
//      o  Performance measurements
//
//      As long as no error situations occur, safe debugging should produce
//      no messages on the debugging terminal.
//
//      'Checked' builds are always compiled with DBG=1, TRC=1.
//
//      'Free' builds are compiled with safe debugging until
//      shortly before release, then for the last releases with no debugging.
//
//      Care should be taken to ensure that the presence of safe debugging
//      code does not change operation in any way, as there is little time
//      at the end of the project to validate this.






#undef ASSERT
#undef ASSERTS
#undef ASSERTHR
#undef TRACEMSG
#undef TRACE
#undef LPKPUTS
#undef THROW
#undef BIDIPUTS


// Debug support requires tracing support

#if DBG
#define TRC 1
#endif


#if !TRC


///  No debug or tracing support


#define TRACEMSG(a)
#define TRACE(a,b)
#define ASSERT(x)
#define ASSERTS(a,b)
#define ASSERTHR(a,b)
#define TIMEENTRY(id, charcount)
#define TIMEEXIT(id)
#define TIMESUSPEND
#define TIMERESUME

__inline HRESULT HRESULT_FROM_LAST_WIN32_ERROR() {

    int iWin32Error = GetLastError();

    if (FAILED(HRESULT_FROM_WIN32(iWin32Error))) {
        return HRESULT_FROM_WIN32(iWin32Error);
    } else {
        return E_FAIL;  // Guarantee that a Win32 error is always treated as failure
    }
}






#else







////    Safe debug support
//
//




///     Trace constants - each flag is separately controlled through the
//      global variable 'Debug'.
//
//      The checked build initialises debug from the registry.
//      Create a key named 'SOFTWARE\\Microsoft\\Uniscribe'
//      Add a DWORD value named 'Debug' containg the flags as below.


#define TRACE_API     0x00000001u        // USP APIs
#define TRACE_BIDI    0x00000002u        // Bidi shaper - CNTXFSM.C
#define TRACE_EDIT    0x00000004u        // Edit control
#define TRACE_FASC    0x00000008u        // Font association
#define TRACE_FONT    0x00000010u        // Font analysis
#define TRACE_GDI     0x00000020u        // GDI interface calls
#define TRACE_ITEM    0x00000040u        // Item analysis FSM
#define TRACE_NLS     0x00000080u        // NLS Info
#define TRACE_POSN    0x00000100u        // GAD positioning functions
#define TRACE_SSA     0x00000200u        // ScriptStringAnalyse
#define TRACE_SSO     0x00000400u        // ScriptStringOut
#define TRACE_THAI    0x00000800u        // Thai shaper
#define TRACE_CACHE   0x00001000u        // Font caching
#define TRACE_TIME    0x00002000u        // Timing entry/exit points
#define TRACE_CDM     0x00004000u        // CDM Shaper
#define TRACE_ALLOC   0x00008000u        // Memory allocation and deallocation


#define DEBUG_IGNOREREALIZATIONID        0x80000000u
#define DEBUG_IGNOREREGETCHARABCWIDTHSI  0x40000000u
#define DEBUG_TIMINGREPORT               0x20000000u




///     Tracing and assertion macros
//


#define TRACEMSG(a)   {DG.psFile=__FILE__; DG.iLine=__LINE__; DebugMsg a;}
#define TRACE(a,b)    {if (!DG.fDebugInitialised){DbgReadRegistrySettings();};if (debug & TRACE_##a) TRACEMSG(b);}
#define ASSERT(a)     {if (!(a)) TRACEMSG(("Assertion failure: "#a));}
#define ASSERTS(a,b)  {if (!(a)) TRACEMSG(("Assertion failure: "#a" - "#b));}
#define ASSERTHR(a,b) {if (!SUCCEEDED(a)) {DG.psFile=__FILE__; \
                       DG.iLine=__LINE__; DG.hrLastError=a; DebugHr b;}}
#define HRESULT_FROM_LAST_WIN32_ERROR() (               \
    DG.psFile=__FILE__, DG.iLine=__LINE__,              \
    HrFromLastErrorDbg())






///     Debug variables
//


struct DebugGlobals {
    char   *psFile;
    int     iLine;
    HRESULT hrLastError;     // Last hresult from GDI
    CHAR    sLastError[100];
    int     nAllocs;
    int     nFrees;
    int     nTotalBytesRequested;
    int     nCurrentBytesAllocated;
    int     nMaxBytesAllocated;
    BOOL    fDebugInitialised;      // Don't read registry settings until after process attach
};




///     Debug function prototypes
//


BOOL    WINAPI  DebugInit();
void    WINAPIV DebugMsg(char *fmt, ...);
void    WINAPIV DebugHr(char *fmt, ...);
HRESULT WINAPI  HrFromLastErrorDbg();

#ifdef USP_DLL
extern DebugGlobals DG;
extern UINT debug;
#else
extern __declspec(dllimport) DebugGlobals DG;
extern __declspec(dllimport) UINT debug;
#endif



#if DBG
void WINAPI DbgReadRegistrySettings();
#endif




////    Performance tracking
//
//      Defines macros TIMEENTRY and TIMEEXIT to time code sequences.
//
//      If an inner level TIMENTRY is encountered while a more global
//      code sequence is being timed, the more global timing is stopped
//      until the inner level TIMEXIT.
//      I.e. timings reported for a given TIMENTRY/TIMEEXIT pair exclude
//      time spent in nested timed sequences.


#if !DBG || !defined(i386)

#define DbgTimeEntry(a, b)
#define DbgTimeExit(a)
#define DbgTimeSuspend()
#define DbgTimeResume()
#define DbgTimingReport()

#define TIMEENTRY(id, charcount)
#define TIMEEXIT(id)
#define TIMESUSPEND
#define TIMERESUME
#define TIMINGINFOHERE


#else

#define TIME_LSA            0
#define TIME_SSA            1
#define TIME_RNS            2
#define TIME_SSAGDI         3
#define TIME_SI             4
#define TIME_SS             5
#define TIME_SP             6
#define TIME_UC             7
#define TIME_GFD            8
#define TIME_ACMAP          9
#define TIME_FCMAP         10
#define TIME_GETUNAM       11
#define TIME_GRI           12
#define TIME_PCW           13
#define TIME_LGM           14
#define TIME_USPALLOCCACHE 15
#define TIME_USPALLOCTEMP  16
#define TIME_USPFREE       17
#define TIME_SSO           18
#define TIME_SSOSBL        19
#define TIME_ETOBGC        20
#define TIME_ETOCOD        21
#define TIME_SSOSFF        22
#define TIME_STO           23
#define TIME_STOETO        24
#define TIME_MAX           25


typedef struct tagTimingInfo {
    PSTR    pcTitle;
    __int64 i64TotalClocksUsed;
    __int64 i64ClocksAtLastEntry;
    __int64 i64NumTimesEntered;
    __int64 i64CharCountProcessed;
    int     iCaller;                // Who was active when we started, -1 if none,
} TIMINGINFO;


void WINAPI DbgTimeEntry(int id, int charcount);
void WINAPI DbgTimeExit(int id);
void WINAPI DbgTimeSuspend();
void WINAPI DbgTimeResume();
void WINAPI DbgTimingReport();

#define TIMEENTRY(id, charcount) DbgTimeEntry(TIME_##id, charcount)
#define TIMEEXIT(id)             DbgTimeExit(TIME_##id)
#define TIMESUSPEND              DbgTimeSuspend()
#define TIMERESUME               DbgTimeResume()




#define TIMINGINFOHERE                                   \
                                                         \
TIMINGINFO ti[] = {                                      \
    {"LpkStringAnalyze",            0, 0, 0, 0, -1},     \
    {"ScriptStringAnalyze",         0, 0, 0, 0, -1},     \
    {"ReadNLSScriptSettings",       0, 0, 0, 0, -1},     \
    {"SSA gdi calls",               0, 0, 0, 0, -1},     \
    {"ScriptItemize",               0, 0, 0, 0, -1},     \
    {"ScriptShape",                 0, 0, 0, 0, -1},     \
    {"ScriptPlace",                 0, 0, 0, 0, -1},     \
    {"UpdateCache",                 0, 0, 0, 0, -1},     \
    {"GetFontDetails",              0, 0, 0, 0, -1},     \
    {"Allocate CMAP",               0, 0, 0, 0, -1},     \
    {"Fill CMAP",                   0, 0, 0, 0, -1},     \
    {"Get Unicode Name and Metrics",0, 0, 0, 0, -1},     \
    {"GetRealizationInfo",          0, 0, 0, 0, -1},     \
    {"Preload common widths",       0, 0, 0, 0, -1},     \
    {"LoadGlyphMetrics",            0, 0, 0, 0, -1},     \
    {"USPALLOCCACHE",               0, 0, 0, 0, -1},     \
    {"USPALLOCTEMP",                0, 0, 0, 0, -1},     \
    {"USPFREE",                     0, 0, 0, 0, -1},     \
    {"ScriptStringOut",             0, 0, 0, 0, -1},     \
    {"ScriptStringOut - StBtchLm",  0, 0, 0, 0, -1},     \
    {"ScriptStringOut - bkg clr",   0, 0, 0, 0, -1},     \
    {"ScriptStringOut - end pnts",  0, 0, 0, 0, -1},     \
    {"ScriptStringOut - slctflbck", 0, 0, 0, 0, -1},     \
    {"ScriptTextOut",               0, 0, 0, 0, -1},     \
    {"SimpleTextOut - ETO",         0, 0, 0, 0, -1},     \
};                                                       \
                                                         \
int  iStdParent[TIME_MAX] =                              \
{-1,-1,-1,-1,                                            \
 -1,-1,-1,-1,                                            \
 -1,-1,-1,-1,                                            \
 -1,-1,-1,-1,                                            \
 -1,-1,-1,-1,                                            \
 -1,-1,-1,-1,                                            \
 -1};






#endif
#endif



#ifdef __cplusplus
}
#endif
#endif