/******************************Module*Header*******************************\
* Module Name: ftuni.c
*
* the tests for simple unicode extended functions
*
* Created: 06-Aug-1991 16:05:32
* Author: Bodin Dresevic [BodinD]
*
* Copyright (c) 1990 Microsoft Corporation
*
\**************************************************************************/

#include "precomp.h"
#pragma hdrstop

// This is to create a bitmapinfo structure

BOOL bEqualABC(LPABC pabc1,LPABC pabc2)
{
    return (
            (pabc1->abcA == pabc2->abcA) &&
            (pabc1->abcB == pabc2->abcB) &&
            (pabc1->abcC == pabc2->abcC)
           );
}

BOOL bEqualABCFLOAT(LPABCFLOAT pabcf1,LPABCFLOAT pabcf2)
{
    return (
            (pabcf1->abcfA == pabcf2->abcfA) &&
            (pabcf1->abcfB == pabcf2->abcfB) &&
            (pabcf1->abcfC == pabcf2->abcfC)
           );
}


VOID vToUNICODE(LPWSTR pwszDst, PSZ pszSrc)
{
    while((*pwszDst++ = (WCHAR)(*pszSrc++)) != (WCHAR)'\0')
        ;
}

#define CGLYPHS 300

VOID DbgPrintLOGFONT(PVOID pv);

VOID  vTestEnumFonts(HDC hdc);
VOID  vTestStuff(HDC hdcScreen);
VOID  vTestAddFR(HDC);





void    vTestGetOTM(HDC hdc);


VOID vTestUnicode(HWND hwnd, HDC hdcScreen, RECT* prcl)
{
    prcl; hwnd;

    vTestGetOTM   (hdcScreen);
    vTestAddFR    (hdcScreen);
    vTestStuff    (hdcScreen);
    vTestEnumFonts(hdcScreen);
}


void    vTestGetOTM(HDC hdc)
{
    HFONT   hfont;
    HFONT   hfontOriginal;
    LOGFONT lfnt;
    OUTLINETEXTMETRICA  otma, *potma;
    UINT    cjotma;

    OUTLINETEXTMETRICW  otmw, *potmw;
    UINT                cjotmw;

// Clear the screen to black.

    BitBlt(hdc, 0, 0, 3000, 4000, (HDC) 0, 0, 0, 0);

// Get a font.

    memset(&lfnt, 0, sizeof(lfnt));
    lstrcpy(lfnt.lfFaceName, "Arial");
    lfnt.lfHeight = -14;
    lfnt.lfWeight = 400;

    if ((hfont = CreateFontIndirect(&lfnt)) == NULL)
    {
        DbgPrint("ft!bTestGOTM(): Logical font creation failed.\n");
    }

    hfontOriginal = SelectObject(hdc, hfont);

// Determine size needed for OTM.

    cjotma = GetOutlineTextMetricsA(hdc, sizeof(OUTLINETEXTMETRICA), &otma);

    if (cjotma != sizeof(OUTLINETEXTMETRICA))
    {
        DbgPrint("ft!bTestGOTM(): cjotma != sizeof(OUTLINETEXTMETRICA)\n");
    }

    cjotma = GetOutlineTextMetricsA(hdc, offsetof(OUTLINETEXTMETRICA,otmpFamilyName), &otma);

    if (cjotma != offsetof(OUTLINETEXTMETRICA,otmpFamilyName))
    {
        DbgPrint("ft!bTestGOTM(): cjotma != offsetof(OUTLINETEXTMETRICA,otmpFamilyName)\n");
    }


    cjotma = GetOutlineTextMetricsA(hdc, 0, NULL);

    potma = (OUTLINETEXTMETRICA*)LocalAlloc(LMEM_FIXED, cjotma);

    if (potma)
    {
        UINT cjotma1 = GetOutlineTextMetricsA(hdc, cjotma, potma);
        if (cjotma1 != cjotma)
        {
            DbgPrint("ft!bTestGOTM(): cjotma != cjotma1, cjotma = %ld, cjotma1 = %ld \n",
                cjotma, cjotma1);
        }
        else
        {
            DbgPrint("\n\nAnsi version: \n\n");

            DbgPrint("Family: %s\n", (BYTE*)potma + (ULONG_PTR)potma->otmpFamilyName);
            DbgPrint("Face:   %s\n", (BYTE*)potma + (ULONG_PTR)potma->otmpFaceName);
            DbgPrint("Style:  %s\n", (BYTE*)potma + (ULONG_PTR)potma->otmpStyleName);
            DbgPrint("Full:   %s\n", (BYTE*)potma + (ULONG_PTR)potma->otmpFullName);
        }

    // this should fail, no room for all the strings:

        cjotma1 = GetOutlineTextMetricsA(hdc, cjotma - 3 , potma);
        if (cjotma1 != 0)
        {
            DbgPrint("ft!bTestGOTM(): cjotma1 = %ld, != 0 \n",cjotma1);
        }

        LocalFree(potma);
    }

// repeat all of this for a unicode version

// Determine size needed for OTM.


    cjotmw = GetOutlineTextMetricsW(hdc, sizeof(OUTLINETEXTMETRICW), &otmw);

    if (cjotmw != sizeof(OUTLINETEXTMETRICW))
    {
        DbgPrint("ft!bTestGOTM(): cjotmw != sizeof(OUTLINETEXTMETRICW)\n");
    }

    cjotmw = GetOutlineTextMetricsW(hdc, offsetof(OUTLINETEXTMETRICW,otmpFamilyName), &otmw);

    if (cjotmw != offsetof(OUTLINETEXTMETRICW,otmpFamilyName))
    {
        DbgPrint("ft!bTestGOTM(): cjotmw != offsetof(OUTLINETEXTMETRICW,otmpFamilyName)\n");
    }


    cjotmw = GetOutlineTextMetricsW(hdc, 0, NULL);

    potmw = (OUTLINETEXTMETRICW*)LocalAlloc(LMEM_FIXED, cjotmw);

    if (potmw)
    {
        UINT cjotmw1 = GetOutlineTextMetricsW(hdc, cjotmw, potmw);
        if (cjotmw1 != cjotmw)
        {
            DbgPrint("ft!bTestGOTM(): cjotmw != cjotmw1, cjotmw = %ld, cjotmw1 = %ld \n",
                cjotmw, cjotmw1);
        }
        else
        {
            DbgPrint("\n\nUnicode version: \n\n");

            DbgPrint("Family: %ws\n", (BYTE*)potmw + (ULONG_PTR)potmw->otmpFamilyName);
            DbgPrint("Face:   %ws\n", (BYTE*)potmw + (ULONG_PTR)potmw->otmpFaceName);
            DbgPrint("Style:  %ws\n", (BYTE*)potmw + (ULONG_PTR)potmw->otmpStyleName);
            DbgPrint("Full:   %ws\n", (BYTE*)potmw + (ULONG_PTR)potmw->otmpFullName);
        }

    // this should fail, no room for all the strings:

        cjotmw1 = GetOutlineTextMetricsW(hdc, cjotmw - 3 , potmw);
        if (cjotmw1 != 0)
        {
            DbgPrint("ft!bTestGOTM(): cjotmw1 = %ld, != 0 \n",cjotmw1);
        }

        LocalFree(potmw);
    }


    SelectObject(hdc, hfontOriginal);
    DeleteObject(hfont);

}




VOID vTestStuff(HDC hdcScreen)
{
// produce several UNICODE strings to be used with Unicode text calls.

    BYTE ajStack[CGLYPHS * 2];   // can accomodate up to CGLYPHS WCHARS

    char * pszETOU = "This is ExtTextOutW output ";
    char * pszNoPdx = "This is ExtTextOutW with no pdx ";
    char * pszPdx = "This is ExtTextOutW with pdx ";
    char * pszTOU = "This is TextOutW output ";
    char * pszTO = "This is ordinary TextOut output ";


    ULONG adx[CGLYPHS];

    ULONG idx;


    for (idx = 0; idx < CGLYPHS; idx++)
        adx[idx] = 20;

// just do one string

    vToUNICODE((LPWSTR)ajStack, pszETOU);

    ExtTextOutW(
                hdcScreen,
                10,20,
                0, (LPRECT)NULL,
                (LPWSTR)ajStack, strlen(pszETOU),
                (LPINT)NULL
               );

// no pdx

    vToUNICODE((LPWSTR)ajStack, pszNoPdx);

    ExtTextOutW(
                hdcScreen,
                10,40,
                0, (LPRECT)NULL,
                (LPWSTR)ajStack, strlen(pszNoPdx),
                (LPINT)NULL
               );


// with pdx

    vToUNICODE((LPWSTR)ajStack, pszPdx);

    ExtTextOutW(
                hdcScreen,
                10,60,
                0, (LPRECT)NULL,
                (LPWSTR)ajStack, strlen(pszPdx),
                (LPINT)adx
               );


    ExtTextOut(                 // compare it with ordinary ExtTextOut
                hdcScreen,
                10,80,
                0, (LPRECT)NULL,
                pszPdx, strlen(pszPdx),
                (LPINT)adx
               );

// change adx and try again

    for (idx = 0; idx < CGLYPHS; idx++)
        adx[idx] = 15 + 2 * (idx & 7);


    ExtTextOutW(
                hdcScreen,
                10,100,
                0, (LPRECT)NULL,
                (LPWSTR)ajStack, strlen(pszPdx),
                (LPINT)adx
               );


    ExtTextOut(                 // compare it with ordinary ExtTextOut
                hdcScreen,
                10,120,
                0, (LPRECT)NULL,
                pszPdx, strlen(pszPdx),
                (LPINT)adx
               );

// ordinary text out

    TextOut(hdcScreen,
            10,160,
            pszTO, strlen(pszTO));

// text out,  unicode version

    vToUNICODE((LPWSTR)ajStack, pszTOU);

    ExtTextOutW(
                hdcScreen,
                10,180,
                0, (LPRECT)NULL,
                (LPWSTR)ajStack, strlen(pszTOU),
                (LPINT)NULL
               );

// try doing a very long string, bigger than 256 chars

    {
        PCHAR pchar = (PCHAR)ajStack;
        for (idx = 0; idx < 250; idx++)
        {
            adx[idx] = 0;                // put them on the top of each other
            *pchar++ = 'a';
        }
        adx[249] = 10;                // put them on the top of each other
        for (idx = 250; idx < 260; idx++)
        {
            adx[idx] = 10;
            *pchar++ = 'b';
        }

        ExtTextOut(
                    hdcScreen,
                    10,220,
                    0, (LPRECT)NULL,
                    (LPSTR)ajStack, 260,
                    (LPINT)adx
                   );
    }

// test GetTextFace(W)

    {
        int cRet, cRetW;

        cRet = GetTextFace(hdcScreen, CGLYPHS * 2, (LPSTR)ajStack);
        TextOut(hdcScreen, 10, 300, (LPSTR)ajStack, (DWORD)cRet);

        cRetW = GetTextFaceW(hdcScreen, CGLYPHS * 2, (LPWSTR)ajStack);
        TextOutW(hdcScreen, 10, 320, (LPWSTR)ajStack, cRetW);

    // output of the two text out calls should look exactly the same

        if ((cRet * 2) != cRetW)
            DbgPrint("GetTextFace(W) error\n\n");
    }

    {
    // here must add the test for GetTextMetrics(W)
    }

// test for GetObject(W)

    {
        LOGFONT lfIn, lfOut;
        LOGFONTW lfwOut;
        HFONT   hfnt;
        int x = 300,y = 300;

        lfIn.lfHeight =  16;
        lfIn.lfWidth =  8;
        lfIn.lfEscapement =  0;
        lfIn.lfOrientation =  0;
        lfIn.lfWeight =  700;
        lfIn.lfItalic =  0;
        lfIn.lfUnderline =  0;
        lfIn.lfStrikeOut =  0;
        lfIn.lfCharSet =  ANSI_CHARSET;
        lfIn.lfOutPrecision =  OUT_DEFAULT_PRECIS;
        lfIn.lfClipPrecision =  CLIP_DEFAULT_PRECIS;
        lfIn.lfQuality =  DEFAULT_QUALITY;
        lfIn.lfPitchAndFamily =  (FIXED_PITCH | FF_DONTCARE);

        strcpy(lfIn.lfFaceName, "System");

        hfnt = CreateFontIndirect(&lfIn);

        if (hfnt == (HFONT)0)
        {
            DbgPrint("CreateFontIndirect failed\n");
        }
        else
        {
            int cjRet = GetObject(hfnt, sizeof(LOGFONT), (LPVOID)&lfOut);

            if (cjRet)
            {
                if (cjRet != (int)sizeof(LOGFONT))
                    DbgPrint("GetObject  returned bizzare value \n");

                TextOut(hdcScreen, x, y, lfOut.lfFaceName, strlen(lfIn.lfFaceName));

                DbgPrintLOGFONT((PVOID)&lfOut);

            }
            else
            {
                DbgPrint("GetObject  failed \n");
            }

        // GetObjectW test

            cjRet = GetObjectW(hfnt, sizeof(LOGFONTW), (LPVOID)&lfwOut);

            if (cjRet)
            {
                if (cjRet != (int)sizeof(LOGFONTW))
                    DbgPrint("GetObjectW  returned bizzare value \n");

                y += 40;
		TextOutW(hdcScreen, x, y, lfwOut.lfFaceName, strlen(lfIn.lfFaceName));

                DbgPrintLOGFONT((PVOID)&lfwOut);

            }
            else
            {
                DbgPrint("GetObjectW  failed \n");
            }

            if (!DeleteObject(hfnt))
                DbgPrint("DeleteObject(hfnt) failed\n");


        }

    // try to fill the face name with junk, do not put terminating zero in any
    // of the slots

        {
            int i;
            for (i = 0; i < LF_FACESIZE; i++)
                lfIn.lfFaceName[i] = 'A';
        }

        hfnt = CreateFontIndirect(&lfIn);

        if (hfnt == (HFONT)0)
        {
            DbgPrint("CreateFontIndirect failed\n");
        }
        else
        {
            ULONG cjRet = GetObject(hfnt, sizeof(LOGFONT), (LPVOID)&lfOut);

            if (cjRet)
            {
                if (cjRet != sizeof(LOGFONT))
                    DbgPrint("GetObject  returned bizzare value \n");

                y += 40;
                TextOut(hdcScreen, x, y, lfOut.lfFaceName, LF_FACESIZE);
                DbgPrintLOGFONT((PVOID)&lfOut);
            }
            else
            {
                DbgPrint("GetObject  failed \n");
            }

        // GetObjectW is implemented

            cjRet = GetObjectW(hfnt, sizeof(LOGFONTW), (LPVOID)&lfwOut);

            if (cjRet)
            {
                if (cjRet != sizeof(LOGFONTW))
                    DbgPrint("GetObjectW  returned bizzare value \n");

		TextOutW(hdcScreen, x, y + 32, lfwOut.lfFaceName, LF_FACESIZE);
                DbgPrintLOGFONT((PVOID)&lfwOut);
            }
            else
            {
                DbgPrint("GetObjectW  failed \n");
            }

            if (!DeleteObject(hfnt))
                DbgPrint("DeleteObject(hfnt) failed\n");

        }

    }

#define C_CHAR   150


// check GetCharWidth


    {

        UINT iFirst = 30;
        UINT iLast = iFirst + C_CHAR - 1;

        INT  aiWidth[C_CHAR];
        INT  aiWidthW[C_CHAR];

        FLOAT  aeWidth[C_CHAR];
        FLOAT  aeWidthW[C_CHAR];

        BOOL b, bW, bFloat, bFloatW;

        b  = GetCharWidth (hdcScreen, iFirst, iLast, aiWidth);
        bW = GetCharWidthW(hdcScreen, iFirst, iLast, aiWidthW);

        bFloat  = GetCharWidthFloat (hdcScreen, iFirst, iLast, aeWidth);
        bFloatW = GetCharWidthFloatW(hdcScreen, iFirst, iLast, aeWidthW);

        if (!b || !bW || !bFloat || !bFloatW)
        {
            DbgPrint("GetCharWidth (Float)(W) failed\n");
        }
        else
        {
            INT iWidth;

            DbgPrint("\n Width Table : \n");

            for (iWidth = 0; iWidth < C_CHAR; iWidth++)
            {
                if (
                    (aiWidth[iWidth] != aiWidthW[iWidth])
                    ||
                    (aeWidth[iWidth] != aeWidthW[iWidth])
                   )
                {
                    DbgPrint("aiWidth[%ld] != aiWidthW[%ld], aiWidth = %ld, aiWidthW = %ld\n", iWidth, aiWidth[iWidth], aiWidthW[iWidth]);
                }
                else
                {
                #ifdef NEVER
                    DbgPrint("aiWidth[%ld] = %ld \n",
                             iFirst + iWidth,       // offset the index to disply the true ascii value
                             aiWidth[iWidth]);
                #endif  // NEVER
                }

                if (aeWidth[iWidth] != (FLOAT)aiWidth[iWidth])
                {
                //!!! the following test will only be ok on the integer fonts

                    DbgPrint("ft: width problem if not an integer font\n");
                }
            }
            DbgPrint("\n completed Width Table test : \n");
        }

    }

// this should be moved to some other file, ftbmtext.c e.g.

    {

        UINT iFirst = 30;
        UINT iLast = iFirst + C_CHAR - 1;

        ABC  aABC[C_CHAR];
        ABC  aABCW[C_CHAR];

        ABCFLOAT  aABCF[C_CHAR];
        ABCFLOAT  aABCFW[C_CHAR];

        BOOL b, bW, bFloat, bFloatW;

        b  = GetCharABCWidths (hdcScreen, iFirst, iLast, aABC );
        bW = GetCharABCWidthsW(hdcScreen, iFirst, iLast, aABCW);

        bFloat  = GetCharABCWidthsFloat (hdcScreen, iFirst, iLast, aABCF );
        bFloatW = GetCharABCWidthsFloatW(hdcScreen, iFirst, iLast, aABCFW);

        if (!b || !bW || !bFloat || !bFloatW)
        {
            DbgPrint("GetCharABCWidths (Float)(W) failed\n");
        }
        else
        {
            INT iWidth;

            DbgPrint("\n abc Width test : \n");

            for (iWidth = 0; iWidth < C_CHAR; iWidth++)
            {
            #ifdef PRINT_STUFF
                if (
                    !(b = bEqualABC(&aABC[iWidth], &aABCW[iWidth]))
                    ||
                    !(bFloat = bEqualABCFLOAT(&aABCF[iWidth], &aABCFW[iWidth]))
                   )
            #endif // PRINT_STUFF
                {
                    DbgPrint("\n abc screwed up on iWidth = %ld, bABC = %ld, bABCF = %ld \n",
                              iWidth, b, bFloat);

                    DbgPrint ("ANSI Integer: a = %ld, b = %ld, c = %ld,\n",
                              aABC[iWidth].abcA,
                              aABC[iWidth].abcB,
                              aABC[iWidth].abcC);

                    DbgPrint ("UNICODE Integer: a = %ld, b = %ld, c = %ld,\n",
                              aABCW[iWidth].abcA,
                              aABCW[iWidth].abcB,
                              aABCW[iWidth].abcC);

                    DbgPrint ("ANSI float: a = %ld, b = %ld, c = %ld,\n",
                              (LONG)aABCF[iWidth].abcfA,
                              (LONG)aABCF[iWidth].abcfB,
                              (LONG)aABCF[iWidth].abcfC);

                    DbgPrint ("UNICODE float: a = %ld, b = %ld, c = %ld,\n",
                              (LONG)aABCFW[iWidth].abcfA,
                              (LONG)aABCFW[iWidth].abcfB,
                              (LONG)aABCFW[iWidth].abcfC);
                }

            //!!! the following test will only be ok on the integer fonts

                if (
                    ((FLOAT)aABC[iWidth].abcA != aABCF[iWidth].abcfA) ||
                    ((FLOAT)aABC[iWidth].abcB != aABCF[iWidth].abcfB) ||
                    ((FLOAT)aABC[iWidth].abcC != aABCF[iWidth].abcfC)
                   )
                {
                    DbgPrint("ft: this is an ABC problem if not an integer font\n\n");
                }
            }
            DbgPrint("\n completed abc Width test : \n");

        }

    }

// this is a test to verify the use of the sections, where the amount of data
// that needs to be transfered over the client server boundary
// is  bigger than 64K (size of mem window)

#define C_GLYPHS_HUGE   (0X00004000)

    {
        UINT       iFirst = 30;
        UINT       iLast = iFirst + C_GLYPHS_HUGE - 1;
        PVOID      pvMem;
        BOOL       b;
        LPINT      pintWidth;
        PFLOAT     peWidth;
        LPABC      pabc;
        LPABCFLOAT pabcf;

        pvMem = malloc(C_GLYPHS_HUGE * sizeof(ABC));

        if (pvMem != (PVOID)NULL)
        {
            pintWidth = (LPINT)pvMem;
            peWidth   = (PFLOAT)pvMem;
            pabc      = (LPABC)pvMem ;
            pabcf     = (LPABCFLOAT)pvMem ;

            b = GetCharABCWidthsW (hdcScreen, iFirst, iLast, pabc);

            if (!b)
            {
                DbgPrint(" section test GetCharABCWidthsW  failed\n");
            }
            else
            {
                INT iWidth;

            #ifdef NEVER_DO_IT

                DbgPrint("\n abc Width section test : \n");

                for (iWidth = 0; iWidth < C_GLYPHS_HUGE; iWidth++)
                {
                    DbgPrint ("UNICODE Integer: a = %ld, b = %ld, c = %ld,\n",
                               pabc[iWidth].abcA,
                               pabc[iWidth].abcB,
                               pabc[iWidth].abcC);
                }
                DbgPrint("\n completed abc Width section test : \n");

            #endif // NEVER_DO_IT
            }

        // GetCharWidthsW section test

            b = GetCharWidthW (hdcScreen, iFirst, iLast, pintWidth);

            if (!b)
            {
                DbgPrint(" section test GetCharWidthW  failed\n");
            }
            else
            {
                INT iWidth;

                DbgPrint("\n  Width section test : \n");

            #ifdef NEVER_DO_IT
                for (iWidth = 0; iWidth < C_GLYPHS_HUGE; iWidth++)
                {
                    DbgPrint("\n width[%ld] = %ld \n", iWidth, pintWidth[iWidth]);
                }
            #endif // NEVER_DO_IT
                DbgPrint("\n completed Width section test : \n");
            }

            b = GetCharWidthFloatW (hdcScreen, iFirst, iLast, peWidth);

            if (!b)
            {
                DbgPrint(" section test GetCharWidthFloatW  failed\n");
            }
            else
            {
                INT iWidth;

                DbgPrint("\n  Width section test : \n");

            #ifdef NEVER_DO_IT
                for (iWidth = 0; iWidth < C_GLYPHS_HUGE; iWidth++)
                {
                    DbgPrint("\n float width[%ld] = %ld \n", iWidth, (LONG)peWidth[iWidth]);
                }
            #endif // NEVER_DO_IT
                DbgPrint("\n completed Width section test : \n");
            }

            free(pvMem);
        }

    }



/*
    {
        HBITMAP hbm, hbmOld;
        BITMAP  bm;
        HDC     hdcMem;
        char * pszMem = "Memory Bitmap";
        LOGFONT lfItalic;
        HFONT    hfItalic, hfOld;
        int cPelCorrection;

        lfItalic.lfHeight =  16;
        lfItalic.lfWidth =  8;
        lfItalic.lfEscapement =  0;
        lfItalic.lfOrientation =  0;
        lfItalic.lfWeight =  700;
        lfItalic.lfItalic =  1;
        lfItalic.lfUnderline =  0;
        lfItalic.lfStrikeOut =  0;
        lfItalic.lfCharSet =  ANSI_CHARSET;
        lfItalic.lfOutPrecision =  OUT_DEFAULT_PRECIS;
        lfItalic.lfClipPrecision =  CLIP_DEFAULT_PRECIS;
        lfItalic.lfQuality =  DEFAULT_QUALITY;
        lfItalic.lfPitchAndFamily =  (FIXED_PITCH | FF_DONTCARE);

        strcpy(lfItalic.lfFaceName, "System");

        hfItalic = CreateFontIndirect(&lfItalic);

        if (hfItalic == (HFONT)0)
        {
            DbgPrint("CreateFontIndirect failed\n");
        }

    // create bitmap

        bm.bmType   = 0;  // what does this mean
        bm.bmWidth  = 256;
        bm.bmHeight = 64;
        bm.bmBitsPixel  = 1;   // 8;
        bm.bmPlanes  = 1;

    // cj = (((Width in pels) + pels/dword - 1) & ~(pels/dword - 1)) * 4

        cPelCorrection = (32 / bm.bmBitsPixel) - 1;

        bm.bmWidthBytes =   ((bm.bmWidth + cPelCorrection) & ~cPelCorrection) * 4;      // chriswil  used GetObject on this
        bm.bmBits       = (LPSTR)NULL;


        hbm = CreateBitmapIndirect(&bm);
        if (hbm == (HBITMAP)0)
            DbgPrint("CreateBitmapIndirect failed  on 1 bpp\n");
        else
            DbgPrint("CreateBitmapIndirect succeeded 1 bpp\n");

        hdcMem = CreateCompatibleDC(hdcScreen);
        if (hdcMem == (HDC)0)
            DbgPrint("CreateCompatibleDC failed \n");

        hbmOld = SelectObject(hdcMem, hbm);
        hfOld  = SelectObject(hdcMem, hfItalic);
        SetBkMode(hdcMem, TRANSPARENT);
        PatBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, WHITENESS);
        TextOut(hdcMem, 5, 10, pszMem, strlen(pszMem));


    // display on the screen

        BitBlt(hdcScreen,               // Dst
               0, 200,                  // Dst
               bm.bmWidth, bm.bmHeight, // cx, cy
               hdcMem,                  // Src
               0,0,                     // Src
               SRCCOPY
               );

        SelectObject(hdcMem, hbmOld);
        SelectObject(hdcMem, hfOld);

        if (!DeleteObject(hbm))
        	DbgPrint("ERROR failed to delete 1bpp  hbm\n");

        if (!DeleteObject(hfItalic))
        	DbgPrint("ERROR failed to delete hfItalic  \n");

        if (!DeleteDC(hdcMem))
        	DbgPrint("ERROR failed to delete hdcMem\n");


    }



    {
        HBITMAP hbm;
        BITMAP  bm;
        int cPelCorrection;

        bm.bmType   = 1;  0;  //!!! what does this mean
        bm.bmWidth  = 30;
        bm.bmHeight = 70;
        bm.bmBitsPixel  = 4;   // 8;
        bm.bmPlanes  = 1;

     // cj = (((Width in pels) + pels/dword - 1) & ~(pels/dword - 1)) * 4

        cPelCorrection = (32 / bm.bmBitsPixel) - 1;

        bm.bmWidthBytes =   ((bm.bmWidth + cPelCorrection) & ~cPelCorrection) * 4;      // chriswil  used GetObject on this
        bm.bmBits       = (LPSTR)NULL;


        hbm = CreateBitmapIndirect(&bm);
        if (hbm == (HBITMAP)0)
            DbgPrint("CreateBitmapIndirect failed  on 4 bpp\n");
        else
            DbgPrint("CreateBitmapIndirect succeeded 4 bpp\n");

        if (!DeleteObject(hbm))
        	DbgPrint("ERROR failed to delete 4bpp  hbm\n");

        bm.bmType   = 0;
        bm.bmWidth  = 30;
        bm.bmHeight = 70;
        bm.bmBitsPixel  = 8;   // 8;
        bm.bmPlanes  = 1;
        cPelCorrection = (32 / bm.bmBitsPixel) - 1;

        bm.bmWidthBytes =   ((bm.bmWidth + cPelCorrection) & ~cPelCorrection) * 4;      // chriswil  used GetObject on this
        bm.bmBits       = (LPSTR)NULL;

        hbm = CreateBitmapIndirect(&bm);
        if (hbm == (HBITMAP)0)
            DbgPrint("CreateBitmapIndirect failed 8bpp \n");
        else
            DbgPrint("CreateBitmapIndirect succeeded 8 bpp \n");

        if (!DeleteObject(hbm))
        	DbgPrint("ERROR failed to delete  8bpp hbm\n");


    }

*/

// test GetTextExtentPoint

    {
        SIZE size, sizeU;
        RECT rc;

// couple of strings to demonstrate that there is no overlap of chars that
// have low stems with the top of the next row

        char *psz1 = "ab__cdjjyygg";
        char *psz2 = "abTTHHTT__djjyygg";
        char *psz3 = "abTTHHTTcdjjyygg";
        int x,y;

        PatBlt(hdcScreen, 0,0, 2000, 2000, WHITENESS);


        if (
            !GetTextExtentPoint(hdcScreen, pszTOU, strlen(pszTOU),&size)
                  ||
            !GetTextExtentPointW(hdcScreen, (LPWSTR)ajStack, strlen(pszTOU),&sizeU)
           )
        {
            DbgPrint("GetTextExtentPoint or GetTextExtentPointW failed\n\n");
        }

        DbgPrint("size.cx = %ld, size.cy = %ld \n", size.cx, size.cy);
        DbgPrint("sizeU.cx = %ld, sizeU.cy = %ld \n", sizeU.cx, sizeU.cy);

        SetBkColor(hdcScreen, RGB(255,0,0));

        x = 200;
        y = 20;
        TextOut(hdcScreen, x, y, psz1, strlen(psz1));
        y += size.cy;
        TextOut(hdcScreen, x, y, psz2, strlen(psz2));
        y += size.cy;
        TextOut(hdcScreen, x, y, psz3, strlen(psz3));


// demonstrate that clipping and opaqueing works

        SetBkColor(hdcScreen, RGB(0,255,0));

        GetTextExtentPoint(hdcScreen, psz1, strlen(psz1), &size);

        x = 10;
        y = 200;

        rc.left = x;
        rc.top  = y;
        rc.right = x + (3 * size.cx / 4);
        rc.bottom = y + (size.cy / 2);

        ExtTextOut(hdcScreen, x, y, 0 ,NULL , psz1, strlen(psz1), NULL);

        y += (2 * size.cy);
        rc.left = x;
        rc.top  = y;
        rc.right = x + (3 * size.cx / 4);
        rc.bottom = y + (size.cy / 2);
        ExtTextOut(hdcScreen, x, y, ETO_CLIPPED ,&rc, psz1, strlen(psz1), NULL);

        y += (2 * size.cy);
        rc.left = x;
        rc.top  = y;
        rc.right = x + (3 * size.cx / 4);
        rc.bottom = y + (size.cy / 2);
        ExtTextOut(hdcScreen, x, y, ETO_OPAQUE ,&rc, psz1, strlen(psz1), NULL);

        y += (2 * size.cy);
        rc.left = x;
        rc.top  = y;
        rc.right = x + (3 * size.cx / 4);
        rc.bottom = y + (size.cy / 2);
        ExtTextOut(hdcScreen, x, y, ETO_CLIPPED | ETO_OPAQUE,&rc, psz1, strlen(psz1), NULL);

        SetBkMode(hdcScreen, TRANSPARENT);

        x = 300;
        y = 200;

        rc.left = x;
        rc.top  = y;
        rc.right = x + (3 * size.cx / 4);
        rc.bottom = y + (size.cy / 2);

        ExtTextOut(hdcScreen, x, y, 0 ,NULL , psz1, strlen(psz1), NULL);

        y += (2 * size.cy);
        rc.left = x;
        rc.top  = y;
        rc.right = x + (3 * size.cx / 4);
        rc.bottom = y + (size.cy / 2);
        ExtTextOut(hdcScreen, x, y, ETO_CLIPPED ,&rc, psz1, strlen(psz1), NULL);

        y += (2 * size.cy);
        rc.left = x;
        rc.top  = y;
        rc.right = x + (3 * size.cx / 4);
        rc.bottom = y + (size.cy / 2);
        ExtTextOut(hdcScreen, x, y, ETO_OPAQUE ,&rc, psz1, strlen(psz1), NULL);

        y += (2 * size.cy);
        rc.left = x;
        rc.top  = y;
        rc.right = x + (3 * size.cx / 4);
        rc.bottom = y + (size.cy / 2);
        ExtTextOut(hdcScreen, x, y, ETO_CLIPPED | ETO_OPAQUE,&rc, psz1, strlen(psz1), NULL);


        SetBkMode(hdcScreen, OPAQUE);

        SetBkColor(hdcScreen, RGB(255,255,255));
    }





}




typedef struct _FONTFACE
{
    ULONG cFont;                   // COUNT OF FONTS WITH THIS FACE NAME
    UCHAR achFaceName[LF_FACESIZE];
} FONTFACE, *PFONTFACE;

typedef struct _FONTFACEW
{
    ULONG cFont;                   // COUNT OF FONTS WITH THIS FACE NAME
    WCHAR awcFaceName[LF_FACESIZE];
} FONTFACEW, *PFONTFACEW;


typedef struct _TEXTOUTDATA
{
    int cFaces;
    HDC hdc;
    int x;
    int y;
} TEXTOUTDATA, *PTEXTOUTDATA;


#define FF_CUTOFF 10

FONTFACE  gaff[FF_CUTOFF];
FONTFACEW gaffw[FF_CUTOFF];



/******************************Public*Routine******************************\
*
*  callback function, to be used with lpFaceName == NULL, to get the total
*  number of all face names
*
\**************************************************************************/

int iCountFaces
(
PLOGFONT     plf,
PTEXTMETRIC  ptm,
int          flFontType,
PVOID        pv
)
{

    PTEXTOUTDATA ptod = (PTEXTOUTDATA)pv;
    HFONT hf, hfOld;

    strcpy(gaff[ptod->cFaces].achFaceName, plf->lfFaceName);

    hf = CreateFontIndirect(plf);

    if (hf == (HFONT)0)
    {
        DbgPrint("CreateFontIndirect failed \n");
        return 0;
    }


    hfOld = SelectObject(ptod->hdc, hf);
    if (flFontType & RASTER_FONTTYPE)
        TextOut(ptod->hdc, ptod->x, ptod->y, plf->lfFaceName, strlen(plf->lfFaceName));
    ptod->y += (ptm->tmHeight + ptm->tmExternalLeading);

    SelectObject(ptod->hdc, hfOld);
    if (!DeleteObject(hf))
    {
        DbgPrint("DeleteObject(hf) failed \n");
        return 0;
    }

    ptod->cFaces++;

    if (ptod->cFaces >= FF_CUTOFF)
        return 0;     // break out of the loop that calls this function
    return(1);
}



int iCountFacesW
(
PLOGFONTW     plfw,
PTEXTMETRICW  ptmw,
int           flFontType,
PVOID         pv
)
{

    PTEXTOUTDATA ptod = (PTEXTOUTDATA)pv;
    HFONT hf, hfOld;

    wcscpy(gaffw[ptod->cFaces].awcFaceName, plfw->lfFaceName);

    hf = CreateFontIndirectW(plfw);
    if (hf == (HFONT)0)
    {
        DbgPrint("CreateFontIndirectW failed \n");
        return 0;
    }

    hfOld = SelectObject(ptod->hdc, hf);
    if (flFontType & RASTER_FONTTYPE)
	TextOutW(ptod->hdc, ptod->x, ptod->y, plfw->lfFaceName, wcslen(plfw->lfFaceName));
    ptod->y += (ptmw->tmHeight + ptmw->tmExternalLeading);

    SelectObject(ptod->hdc, hfOld);
    if (!DeleteObject(hf))
    {
        DbgPrint("DeleteObject(hf) failed \n");
        return 0;
    }

    ptod->cFaces++;
    if (ptod->cFaces >= FF_CUTOFF)
        return 0;     // break out of the loop that calls this function

    return(1);
}

#define COLORS 7

COLORREF gcr[COLORS] =
{
RGB(0,255,255),
RGB(255,0,255),
RGB(255,255,0),
RGB(0,0,255),
RGB(0,255,0),
RGB(255,0,0),
RGB(127,127,127)
};


int  iPrintSample
(
PLOGFONT     plf,
PTEXTMETRIC  ptm,
int          flFontType,
PVOID        pv
)
{

    PTEXTOUTDATA ptod = (PTEXTOUTDATA)pv;
    HFONT hf, hfOld;


    hf = CreateFontIndirect(plf);

    if (hf == (HFONT)0)
    {
        DbgPrint("CreateFontIndirect failed \n");
        return 0;
    }

    hfOld = SelectObject(ptod->hdc, hf);

    SetTextColor(ptod->hdc, gcr[plf->lfHeight % COLORS]);
    if (flFontType & RASTER_FONTTYPE)
        TextOut(ptod->hdc, ptod->x, ptod->y, plf->lfFaceName, strlen(plf->lfFaceName));
    ptod->y += (ptm->tmHeight + ptm->tmExternalLeading);

    SelectObject(ptod->hdc, hfOld);
    if (!DeleteObject(hf))
    {
        DbgPrint("DeleteObject(hf) failed \n");
        return 0;
    }

    return(1);
}

int  iPrintSampleW
(
PLOGFONTW     plfw,
PTEXTMETRICW  ptmw,
int           flFontType,
PVOID         pv
)
{

    PTEXTOUTDATA ptod = (PTEXTOUTDATA)pv;
    HFONT hf, hfOld;

    hf = CreateFontIndirectW(plfw);
    if (hf == (HFONT)0)
    {
        DbgPrint("CreateFontIndirectW failed \n");
        return 0;
    }

    hfOld = SelectObject(ptod->hdc, hf);

    SetTextColor(ptod->hdc, gcr[plfw->lfHeight % COLORS]);
    if (flFontType & RASTER_FONTTYPE)
	TextOutW(ptod->hdc, ptod->x, ptod->y, plfw->lfFaceName, wcslen(plfw->lfFaceName));
    ptod->y += (ptmw->tmHeight + ptmw->tmExternalLeading);

    SelectObject(ptod->hdc, hfOld);
    if (!DeleteObject(hf))
    {
        DbgPrint("DeleteObject(hf) failed \n");
        return 0;
    }

    return(1);
}





VOID  vTestEnumFonts(HDC hdc)
{
    TEXTOUTDATA tod, todW;
    int iFace;

// initialize

    BitBlt(
           hdc,               // Dst
           0, 0,              // Dst
           2000, 1000,        // cx, cy
           (HDC)0,            // Src
           0,0,               // Src
           WHITENESS
          );


    tod.cFaces = 0;
    tod.hdc = hdc;
    tod.x   = 10;
    tod.y   = 10;

    EnumFonts(hdc, (LPCSTR)NULL, (FONTENUMPROC)iCountFaces, (LPARAM)&tod);

    DbgPrint("\n Total number of faces = %ld\n", tod.cFaces);

    todW.cFaces = 0;
    todW.hdc = hdc;
    todW.x   = 300;
    todW.y   = 10;

    EnumFontsW(hdc, (LPWSTR)NULL, (FONTENUMPROCW)iCountFacesW, (LPARAM)&todW);

    DbgPrint("\n Total number of faces = %ld\n", todW.cFaces);

    if (tod.cFaces != todW.cFaces)
    {
        DbgPrint("\n tod.cFaces != todW.cFaces \n");
        return;
    }

    for (iFace = 0; iFace < tod.cFaces; iFace++)
    {
        BitBlt(
               hdc,               // Dst
               0, 0,              // Dst
               2000, 1000,        // cx, cy
               (HDC)0,            // Src
               0,0,               // Src
               WHITENESS
              );

        tod.hdc = hdc;
        tod.x   = 10;
        tod.y   = 10;

        todW.hdc = hdc;
        todW.x   = 300;
        todW.y   = 10;



        EnumFonts (hdc, gaff[iFace].achFaceName, (FONTENUMPROC)iPrintSample , (LPARAM)&tod);
        EnumFontsW(hdc, gaffw[iFace].awcFaceName,(FONTENUMPROCW)iPrintSampleW, (LPARAM)&todW);
    }

    SetTextColor(hdc, RGB(0,0,0));

}


VOID DbgPrintLOGFONT(PVOID pv)
{
    PLOGFONT  plf = (PLOGFONT)pv;

        DbgPrint("\n");
        DbgPrint("lfHeight          = %ld\n", (LONG)plf->lfHeight          );
        DbgPrint("lfWidth           = %ld\n", (LONG)plf->lfWidth           );
        DbgPrint("lfEscapement      = %ld\n", (LONG)plf->lfEscapement      );
        DbgPrint("lfOrientation     = %ld\n", (LONG)plf->lfOrientation     );
        DbgPrint("lfWeight          = %ld\n", (LONG)plf->lfWeight          );
        DbgPrint("lfItalic          = %ld\n", (LONG)plf->lfItalic          );
        DbgPrint("lfUnderline       = %ld\n", (LONG)plf->lfUnderline       );
        DbgPrint("lfStrikeOut       = %ld\n", (LONG)plf->lfStrikeOut       );
        DbgPrint("lfCharSet         = %ld\n", (LONG)plf->lfCharSet         );
        DbgPrint("lfOutPrecision    = %ld\n", (LONG)plf->lfOutPrecision    );
        DbgPrint("lfClipPrecision   = %ld\n", (LONG)plf->lfClipPrecision   );
        DbgPrint("lfQuality         = %ld\n", (LONG)plf->lfQuality         );
        DbgPrint("lfPitchAndFamily  = %ld\n", (LONG)plf->lfPitchAndFamily  );

        DbgPrint("face name = %s\n", plf->lfFaceName);
        DbgPrint("\n");

}


/******************************Public*Routine******************************\
*
* vTestAddFR(HDC hdc);
*
* Effects:
*
* Warnings:
*
* History:
*  12-Jun-1992 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/


VOID  vTestAddFR(HDC hdcScreen)
{
// test add/remove font resource
    LPSTR pszFileName = "serife.fon";
    LPSTR pszPath = "c:\\nt\\system\\serife.fon";
    int cFonts, cFontsSave;
    BYTE ajStack[CGLYPHS * 2];   // can accomodate up to CGLYPHS WCHARS

    cFontsSave = cFonts = AddFontResource(pszFileName);
    if (cFontsSave == 0)
        DbgPrint("AddFontResource(%s) failed\n\n", pszFileName);
    else
    {
        DbgPrint("AddFontResource(%s) loaded %ld fonts\n\n", pszFileName, cFonts);
        if (!RemoveFontResource(pszFileName))
            DbgPrint("RemoveFontResource(%s) failed\n\n", pszFileName);

        cFonts = cFontsSave = AddFontResource(pszPath);
        if ((cFonts == 0) || (cFonts != cFontsSave))
            DbgPrint("AddFontResource(%s) failed, cFonts = %ld\n\n", pszPath, cFonts);
        else
        {
            DbgPrint("AddFontResource(%s) succeeded, cFonts = %ld\n\n", pszPath, cFonts);
            if (!RemoveFontResource(pszPath))
                DbgPrint("RemoveFontResourceW(%s) failed\n\n", pszPath);
        }

    // convert the strings to unicode

        vToUNICODE((LPWSTR)ajStack, pszFileName);

        cFonts = cFontsSave = AddFontResourceW((LPWSTR)ajStack);
        if ((cFonts == 0) || (cFonts != cFontsSave))
            DbgPrint("AddFontResourceW(%s) failed, cFonts = %ld\n\n", pszFileName, cFonts);
        else
        {
            DbgPrint("AddFontResourceW(%s) succeeded, cFonts = %ld\n\n", pszFileName, cFonts);
            if (!RemoveFontResourceW((LPWSTR)ajStack))
                DbgPrint("RemoveFontResourceW(%s) failed\n\n", pszPath);
        }

        vToUNICODE((LPWSTR)ajStack, pszPath);

        cFonts = cFontsSave = AddFontResourceW((LPWSTR)ajStack);
        if ((cFonts == 0) || (cFonts != cFontsSave))
            DbgPrint("AddFontResourceW(%s) failed, cFonts = %ld\n\n", pszPath, cFonts);
        else
        {
            DbgPrint("AddFontResourceW(%s) succeeded, cFonts = %ld\n\n", pszPath, cFonts);

            if (!RemoveFontResourceW((LPWSTR)ajStack))
                DbgPrint("RemoveFontResourceW(%s) failed\n\n", pszPath);
        }
    }
}