/**************************** Module Header ********************************\
* Module Name: mngray.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* Server-side version of DrawState.
*
* History:
* 06-Jan-1993 FritzS    Created
\***************************************************************************/

#include "precomp.h"
#pragma hdrstop


/***************************************************************************\
 *
 * CreateCompatiblePublicDC
 *
 * This is used in several callback routines to the lpk(s).  We can't
 * pass G_TERM(pDispInfo)->hdcGray, HDCBITS() or gfade.hdc to the client since
 * they are public DCs.
 * We can't just change the owner since we're about to leave the
 * critical section.  Some other thread may enter before we return
 * and use hdcGray, HDCBITS() or gfade.hdc. Instead, we create a compatible
 * dc with the same font and bitmap that are currently selected in hdcGray, 
 * HDCBITS() or gfade.hdc).  Pass that to the client lpk.
 *
 * If the function returns successfully , then the dc and bitmap object are
 * guaranteed to be successfully created.
 *
 * History:
 *
 * Dec-16-1997  Samer Arafeh  [samera]
 * Jan-20-1998  Samer Arafeh  [samera] Add support for both hdcGray and HDCBITS()
 * May-05-2000  MHamid                 Add support for gfade.hdc
 *
\***************************************************************************/
HDC CreateCompatiblePublicDC(
    HDC      hdcPublic,
    HBITMAP *pbmPublicDC)
{
    HDC     hdcCompatible = 0;
    HBITMAP hbmCompatible, hbm = NULL;
    BITMAP  bmBits;
    HFONT   hFont;

    /*
     * If it is not public DC just return it.
     */
    if(GreGetObjectOwner((HOBJ)hdcPublic, DC_TYPE) != OBJECT_OWNER_PUBLIC) {
        return hdcPublic;
    }

    if ((hdcCompatible = GreCreateCompatibleDC(hdcPublic)) == NULL) {
        RIPMSG1(RIP_WARNING, "CreateCompatiblePublicDC: GreCreateCompatibleDC Failed %lX", hdcPublic);
        return (HDC)NULL;
    }

    if (!GreSetDCOwner(hdcCompatible, OBJECT_OWNER_CURRENT)) {
        RIPMSG1(RIP_WARNING, "CreateCompatiblePublicDC: SetDCOwner Failed %lX", hdcCompatible);
        GreDeleteDC(hdcCompatible);
        return (HDC)NULL;
    }

    hbm = NtGdiGetDCObject(hdcPublic, LO_BITMAP_TYPE);

    GreExtGetObjectW(hbm, sizeof(BITMAP), &bmBits);

    hbmCompatible = GreCreateCompatibleBitmap(hdcPublic,
                                              bmBits.bmWidth,
                                              bmBits.bmHeight);

    //
    // Check whether bitmap couldn't be created or can't
    // be set to OBJECT_OWNER_CURRENT, then fail and
    // do necessary cleanup now!
    //

    if( (hbmCompatible == NULL) ||
        (!GreSetBitmapOwner(hbmCompatible, OBJECT_OWNER_CURRENT)) ) {

        RIPMSG1(RIP_WARNING, "CreateCompatiblePublicDC: GreCreateCompatibleBitmap Failed %lX", hbmCompatible);
        GreDeleteDC( hdcCompatible );

        if( hbmCompatible ) {
            GreDeleteObject( hbmCompatible );
        }

        return (HDC)NULL;
    }

    GreSelectBitmap(hdcCompatible, hbmCompatible);
    /*
     * Make sure we use the same font and text alignment.
     */
    hFont = GreSelectFont(hdcPublic, ghFontSys);
    GreSelectFont(hdcPublic, hFont);
    GreSelectFont(hdcCompatible, hFont);
    GreSetTextAlign(hdcCompatible, GreGetTextAlign(hdcPublic));
    /*
     * Copy any information already written into G_TERM(pDispInfo)->hdcGray.
     */

    //
    // Mirror the created DC if the hdcGray is currently mirrored,
    // so that TextOut won't get mirrored on User Client DCs
    //
    if (GreGetLayout(hdcPublic) & LAYOUT_RTL) {
        GreSetLayout(hdcCompatible, bmBits.bmWidth - 1, LAYOUT_RTL);
    }
    GreBitBlt(hdcCompatible, 0, 0, bmBits.bmWidth, bmBits.bmHeight, hdcPublic, 0, 0, SRCCOPY, 0);

    *pbmPublicDC = hbmCompatible ;      // for later deletion, by the server side

    return hdcCompatible;
}



/***************************************************************************\
*
*  xxxDrawState()
*
*  Generic state drawing routine.  Does simple drawing into same DC if
*  normal state;  uses offscreen bitmap otherwise.
*
*  We do drawing for these simple types ourselves:
*      (1) Text
*          lData is string pointer.
*          wData is string length
*      (2) Icon
*          LOWORD(lData) is hIcon
*      (3) Bitmap
*          LOWORD(lData) is hBitmap
*      (4) Glyph (internal)
*          LOWORD(lData) is OBI_ value, one of
*              OBI_CHECKMARK
*              OBI_BULLET
*              OBI_MENUARROW
*          right now
*
*  Other types are required to draw via the callback function, and are
*  allowed to stick whatever they want in lData and wData.
*
*  We apply the following effects onto the image:
*      (1) Normal      (nothing)
*      (2) Default     (drop shadow)
*      (3) Union       (gray string dither)
*      (4) Disabled    (embossed)
*
*  Note that we do NOT stretch anything.  We just clip.
*
\***************************************************************************/
BOOL xxxDrawState(
    HDC           hdcDraw,
    HBRUSH        hbrFore,
    LPARAM        lData,
    int           x,
    int           y,
    int           cx,
    int           cy,
    UINT          uFlags)
{
    HFONT   hFont;
    HFONT   hFontSave = NULL;
    HDC     hdcT;
    HBITMAP hbmpT;
    POINT   ptOrg;
    BOOL    fResult;
    int     oldAlign;
    DWORD   dwOldLayout=0;

    /*
     * These require monochrome conversion
     *
     * Enforce monochrome: embossed doesn't look great with 2 color displays
     */
    if ((uFlags & DSS_DISABLED) &&
        ((gpsi->BitCount == 1) || SYSMET(SLOWMACHINE))) {

        uFlags &= ~DSS_DISABLED;
        uFlags |= DSS_UNION;
    }

    if (uFlags & (DSS_INACTIVE | DSS_DISABLED | DSS_DEFAULT | DSS_UNION))
        uFlags |= DSS_MONO;

    /*
     * Validate flags - we only support DST_COMPLEX in kernel
     */
    if ((uFlags & DST_TYPEMASK) != DST_COMPLEX) {
        RIPMSG1(RIP_ERROR, "xxxDrawState: invalid DST_ type %x", (uFlags & DST_TYPEMASK));
        return FALSE;
    }

    /*
     * Optimize:  nothing to draw
     */
    if (!cx || !cy) {
        return TRUE;
    }

    /*
     * Setup drawing dc
     */
    if (uFlags & DSS_MONO) {

        hdcT = gpDispInfo->hdcGray;
        /*
         * First turn off mirroring on hdcGray if any.
         */
        GreSetLayout(hdcT, -1, 0);
        /*
         * Set the hdcGray layout to be equal to the screen hdcDraw layout.
         */
        dwOldLayout = GreGetLayout(hdcDraw);
        if (dwOldLayout != GDI_ERROR) {
            GreSetLayout(hdcT, cx, dwOldLayout);
        }

        /*
         * Is our scratch bitmap big enough?  We need potentially
         * cx+1 by cy pixels for default etc.
         */
        if ((gpDispInfo->cxGray < cx + 1) || (gpDispInfo->cyGray < cy)) {

            if (hbmpT = GreCreateBitmap(max(gpDispInfo->cxGray, cx + 1), max(gpDispInfo->cyGray, cy), 1, 1, 0L)) {

                HBITMAP hbmGray;

                hbmGray = GreSelectBitmap(gpDispInfo->hdcGray, hbmpT);
                GreDeleteObject(hbmGray);

                GreSetBitmapOwner(hbmpT, OBJECT_OWNER_PUBLIC);

                gpDispInfo->cxGray = max(gpDispInfo->cxGray, cx + 1);
                gpDispInfo->cyGray = max(gpDispInfo->cyGray, cy);

            } else {
                cx = gpDispInfo->cxGray - 1;
                cy = gpDispInfo->cyGray;
            }
        }

        GrePatBlt(gpDispInfo->hdcGray,
                  0,
                  0,
                  gpDispInfo->cxGray,
                  gpDispInfo->cyGray,
                  WHITENESS);

        GreSetTextCharacterExtra(gpDispInfo->hdcGray,
                                 GreGetTextCharacterExtra(hdcDraw));

        oldAlign = GreGetTextAlign(hdcT);
        GreSetTextAlign(hdcT, (oldAlign & ~(TA_RTLREADING |TA_CENTER |TA_RIGHT))
                     | (GreGetTextAlign(hdcDraw) & (TA_RTLREADING |TA_CENTER |TA_RIGHT)));
        /*
         * Setup font
         */
        if (GreGetHFONT(hdcDraw) != ghFontSys) {
            hFont = GreSelectFont(hdcDraw, ghFontSys);
            GreSelectFont(hdcDraw, hFont);
            hFontSave = GreSelectFont(gpDispInfo->hdcGray, hFont);
        }
    } else {
        hdcT = hdcDraw;
        /*
         * Adjust viewport
         */
        GreGetViewportOrg(hdcT, &ptOrg);
        GreSetViewportOrg(hdcT, ptOrg.x+x, ptOrg.y+y, NULL);

    }

    /*
     * Now, draw original image
     */
    fResult = xxxRealDrawMenuItem(hdcT, (PGRAYMENU)lData, cx, cy);

    /*
     * The callbacks could have altered the attributes of hdcGray
     */
    if (hdcT == gpDispInfo->hdcGray) {
        GreSetBkColor(gpDispInfo->hdcGray, RGB(255, 255, 255));
        GreSetTextColor(gpDispInfo->hdcGray, RGB(0, 0, 0));
        GreSelectBrush(gpDispInfo->hdcGray, ghbrBlack);
        GreSetBkMode(gpDispInfo->hdcGray, OPAQUE);
    }

    /*
     * Clean up
     */
    if (uFlags & DSS_MONO) {

        /*
         * Reset font
         */
        if (hFontSave)
            GreSelectFont(hdcT, hFontSave);
        GreSetTextAlign(hdcT, oldAlign);
    } else {
        /*
         * Reset DC.
         */
        GreSetViewportOrg(hdcT, ptOrg.x, ptOrg.y, NULL);
        return TRUE;
    }

    /*
     * UNION state
     * Dither over image
     * We want white pixels to stay white, in either dest or pattern.
     */
    if (uFlags & DSS_UNION) {

         POLYPATBLT PolyData;

         PolyData.x         = 0;
         PolyData.y         = 0;
         PolyData.cx        = cx;
         PolyData.cy        = cy;
         PolyData.BrClr.hbr = gpsi->hbrGray;

         GrePolyPatBlt(gpDispInfo->hdcGray, PATOR, &PolyData, 1, PPB_BRUSH);
    }

    if (uFlags & DSS_INACTIVE) {

        BltColor(hdcDraw,
                 SYSHBR(3DSHADOW),
                 gpDispInfo->hdcGray,
                 x,
                 y,
                 cx,
                 cy,
                 0,
                 0,
                 BC_INVERT);

    } else if (uFlags & DSS_DISABLED) {

        /*
         * Emboss
         * Draw over-1/down-1 in hilight color, and in same position in shadow.
         */

        BltColor(hdcDraw,
                 SYSHBR(3DHILIGHT),
                 gpDispInfo->hdcGray,
                 x+1,
                 y+1,
                 cx,
                 cy,
                 0,
                 0,
                 BC_INVERT);

        BltColor(hdcDraw,
                 SYSHBR(3DSHADOW),
                 gpDispInfo->hdcGray,
                 x,
                 y,
                 cx,
                 cy,
                 0,
                 0,
                 BC_INVERT);

    } else if (uFlags & DSS_DEFAULT) {

        BltColor(hdcDraw,
                 hbrFore,
                 gpDispInfo->hdcGray,
                 x,
                 y,
                 cx,
                 cy,
                 0,
                 0,
                 BC_INVERT);

        BltColor(hdcDraw,
                 hbrFore,
                 gpDispInfo->hdcGray,
                 x+1,
                 y,
                 cx,
                 cy,
                 0,
                 0,
                 BC_INVERT);

    } else {

        BltColor(hdcDraw,
                 hbrFore,
                 gpDispInfo->hdcGray,
                 x,
                 y,
                 cx,
                 cy,
                 0,
                 0,
                 BC_INVERT);
    }


    if ((uFlags & DSS_MONO)){
        /*
         * Set the hdcGray layout to 0, it is a public DC.
         */
       GreSetLayout(hdcT, -1, 0);
    }
    return fResult;
}

/***************************************************************************\
* BltColor
*
* <brief description>
*
* History:
* 13-Nov-1990 JimA      Ported from Win3.
\***************************************************************************/

VOID BltColor(
    HDC    hdc,
    HBRUSH hbr,
    HDC    hdcSrce,
    int    xO,
    int    yO,
    int    cx,
    int    cy,
    int    xO1,
    int    yO1,
    UINT   uBltFlags)
{
    HBRUSH hbrSave;
    DWORD  textColorSave;
    DWORD  bkColorSave;
    DWORD  ROP;

    /*
     * Set the Text and Background colors so that bltColor handles the
     * background of buttons (and other bitmaps) properly.
     * Save the HDC's old Text and Background colors.  This causes problems
     * with Omega (and probably other apps) when calling GrayString which
     * uses this routine...
     */
    textColorSave = GreSetTextColor(hdc, 0x00000000L);
    bkColorSave = GreSetBkColor(hdc, 0x00FFFFFFL);

    if (hbr != NULL)
        hbrSave = GreSelectBrush(hdc, hbr);
    if (uBltFlags & BC_INVERT)
        ROP = 0xB8074AL;
    else
        ROP = 0xE20746L;

    if (uBltFlags & BC_NOMIRROR)
        ROP |= NOMIRRORBITMAP;

    GreBitBlt(hdc,
              xO,
              yO,
              cx,
              cy,
              hdcSrce ? hdcSrce : gpDispInfo->hdcGray,
              xO1,
              yO1,
              ROP,
              0x00FFFFFF);

    if (hbr != NULL)
        GreSelectBrush(hdc, hbrSave);

    /*
     * Restore saved colors
     */
    GreSetTextColor(hdc, textColorSave);
    GreSetBkColor(hdc, bkColorSave);
}