#include "stdafx.h"
#include "global.h"
#include "pbrush.h"
#include "pbrusdoc.h"
#include "pbrusfrm.h"
#include "pbrusvw.h"
#include "minifwnd.h"
#include "bmobject.h"
#include "imgsuprt.h"
#include "imgwnd.h"
#include "imgcolor.h"
#include "imgbrush.h"
#include "imgwell.h"
#include "imgtools.h"
#include "tedit.h"
#include "t_text.h"
#include "t_fhsel.h"
#include "toolbox.h"
#include "props.h"
#include "undo.h"
#include "srvritem.h"

#ifdef _DEBUG
#undef THIS_FILE
static CHAR BASED_CODE THIS_FILE[] = __FILE__;
#endif

#include "memtrace.h"

BOOL GetMFDimensions(
    HANDLE hMF,     /* handle to the CF_METAFILEPICT object from clipbrd */
    HDC hDC,        /* display context */
    long *pWidth,    /* width of picture in pixels, OUT param */
    long *pHeight,   /* height of picture in pixels, OUT param */
    long *pcXPelsPerMeter,    /* horizontal resolution, OUT param */
    long *pcYPelsPerMeter,    /* vertical resolution, OUT param */
    IMG* pImg)
    ;
BOOL PlayMetafileIntoDC(
    HANDLE hMF,
    RECT *pRect,
    HDC hDC)
    ;

/***************************************************************************/

void CImgWnd::OnDestroyClipboard()
    {
    if (m_hPoints)
        {
        ::GlobalFree( m_hPoints );
        m_hPoints = NULL;
        }
    }

/***************************************************************************/

void CImgWnd::CopyBMAndPal(HBITMAP *pBM, CPalette ** ppPal)
    {
    IMG* pImg = m_pImg;

    CRect copyRect;

    if (theImgBrush.m_pImg == NULL)
        {
        HideBrush();
        copyRect.SetRect(0, 0, pImg->cxWidth, pImg->cyHeight);
        }
    else
        {
        copyRect = rcDragBrush;
        copyRect.right  -= 1;
        copyRect.bottom -= 1;
        }

    BOOL bRegion = (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL);

#ifdef FHSELCLIP
    if (bRegion)
        {
        if (! m_wClipboardFormat)
            m_wClipboardFormat = RegisterClipboardFormat( TEXT("MSPaintFreehand") );

        if (theImgBrush.m_bFirstDrag)
//          PickupSelection(); but no way to tell if we do it twice...
            PrepareForBrushChange( TRUE, FALSE );

        CFreehandSelectTool* pTool = (CFreehandSelectTool*)CImgTool::GetCurrent();

        ASSERT( pTool );

        if (m_wClipboardFormat && pTool)
            {
            CPoint* pptArray;
            int     iEntries;
            BOOL    bData = pTool->CopyPointsToMemArray( &pptArray, &iEntries );

            if (bData && iEntries)
                {
                HGLOBAL hMem = ::GlobalAlloc( GHND | GMEM_MOVEABLE | GMEM_DDESHARE,
                                                    iEntries * sizeof( POINT )
                                                             + sizeof( short ));
                if (hMem)
                    {
                    short* pShort = (short*)::GlobalLock( hMem );

                    *pShort++ = iEntries;

                    LPPOINT pPts = (LPPOINT)pShort;

                    for (int iPt = 0; iPt < iEntries; iPt++, pPts++)
                        {
                        pPts->x = pptArray[iPt].x - pTool->m_cRectBounding.left;
                        pPts->y = pptArray[iPt].y - pTool->m_cRectBounding.top;
                        }

                    ::GlobalUnlock( hMem );

                    if (m_hPoints)
                        {
                        ::GlobalFree( m_hPoints );
                        m_hPoints = NULL;
                        }

                    m_hPoints = SetClipboardData( m_wClipboardFormat, hMem );
                    }
                else
                    theApp.SetMemoryEmergency();

                delete [] pptArray;
                }
            }
        else
            theApp.SetGdiEmergency();
        }
#endif // FHSELCLIP

    if ( theImgBrush.m_pImg )
        {
        CPalette* ppalOld = SetImgPalette( &theImgBrush.m_dc );

        // Copy the selection...
        CRect rc( 0, 0, theImgBrush.m_size.cx, theImgBrush.m_size.cy );

        *pBM = CopyDC( &theImgBrush.m_dc, &rc );

        if (ppalOld)
            theImgBrush.m_dc.SelectPalette( ppalOld, TRUE );
        }
    else
        // Copy the whole image...
        *pBM = CopyDC( CDC::FromHandle( m_pImg->hDC ), &copyRect );

    if (theApp.m_pPalette && (*ppPal=new CPalette)!=NULL)
        {
        LOGPALETTE256 logPal;

        logPal.palVersion = 0x300;
        logPal.palNumEntries = (WORD)theApp.m_pPalette->GetPaletteEntries( 0, 256,
                                                     &logPal.palPalEntry[0]);

                if ( logPal.palNumEntries )
                        {
                theApp.m_pPalette->GetPaletteEntries( 0, logPal.palNumEntries,
                                                             &logPal.palPalEntry[0] );

                (*ppPal)->CreatePalette( (LPLOGPALETTE)&logPal );
                        }
        }
    }

void CImgWnd::CmdCopy()
{
        if (TextToolProcessed( ID_EDIT_COPY ))
        {
                return;
        }

        CBitmapObj* pResObject = new CBitmapObj;
        if (pResObject)
        {
                IMG* pImgStruct = new IMG;

                if (pImgStruct)
                {
                        if (FillBitmapObj(c_pImgWndCur, pResObject, pImgStruct))
                        {
                                pImgStruct->m_pFirstImgWnd = NULL;
                                pImgStruct->m_pBitmapObj = pResObject;

                                HDC hDCSave = pImgStruct->hDC;

                                pImgStruct->hDC = NULL;
                                pImgStruct->hMaskDC = NULL;

                                pImgStruct->hMaskBitmap = NULL;
                                pImgStruct->hMaskBitmapOld = NULL;

                                pImgStruct->hBitmap = NULL;
                                pImgStruct->m_pPalette = NULL;
                                CopyBMAndPal(&pImgStruct->hBitmap, &pImgStruct->m_pPalette);

                                if (pImgStruct->hBitmap)
                                {
                                        pImgStruct->hDC = CreateCompatibleDC(hDCSave);
                                        if (pImgStruct->hDC)
                                        {
                                                pImgStruct->hBitmapOld = (HBITMAP)SelectObject(
                                                        pImgStruct->hDC, pImgStruct->hBitmap);
                                                pImgStruct->m_hPalOld = pImgStruct->m_pPalette
                                                        ? SelectPalette(pImgStruct->hDC,
                                                        (HPALETTE)pImgStruct->m_pPalette->m_hObject, FALSE)
                                                        : NULL;

                                                // get a server item suitable to generate the clipboard data
                                                CPBView* pView = (CPBView*)
                                                        ((CFrameWnd*)AfxGetMainWnd())->GetActiveView();
                                                CPBSrvrItem* pItem = new CPBSrvrItem(pView->GetDocument(),
                                                        pResObject);

                                                if (pItem)
                                                {
                                                        pItem->CopyToClipboard(FALSE);

                                                        delete pItem;

                                                        return;
                                                }
                                        }
                                }
                        }
                        else
                        {
                                // the IMG and all it contains will get cleaned up when
                                // pResObject is deleted, but only if FillBitmapObj succeeded
                                delete pImgStruct;
                        }
                }

                delete pResObject;
        }
}

/***************************************************************************/

void CImgWnd::CmdCut()
    {
    if (TextToolProcessed( ID_EDIT_CUT ))
        return;

    // BOGUS:
    // CmdCopy doesn't just copy -- it can change the state of the selection
    // this forces the CmdClear to act in the context of the new state
    // save off a flag for CmdClear to special-case like 'first-drag'
    BOOL *pFlag;
    if (theImgBrush.m_pImg && theImgBrush.m_bFirstDrag)
        {
        pFlag = &theImgBrush.m_bCuttingFromImage;
        }
    else
        pFlag = NULL;

    CmdCopy();

    TRY
        {
        if (pFlag)
            *pFlag = TRUE;

        CmdClear();
        }
    CATCH_ALL(e)
        {
        // don't leave the flag set
        if (pFlag)
            *pFlag = FALSE;

        THROW_LAST();
        }
    END_CATCH_ALL

    // normal execution path
    if (pFlag)
        *pFlag = FALSE;
    }

/***************************************************************************/

void CImgWnd::CmdPaste()
    {
    if (TextToolProcessed( ID_EDIT_PASTE ))
        return;

    CancelToolMode(FALSE);

    CommitSelection(TRUE);

    HideBrush();
    SetupRubber( m_pImg );
    EraseTracker();
    theImgBrush.m_pImg = NULL;
    DrawTracker();
    SetUndo( m_pImg );

    if (! PasteImageClip())
        AfxMessageBox( IDS_ERROR_CLIPBOARD, MB_OK | MB_ICONHAND );
    }

/***************************************************************************/

HBITMAP CImgWnd::CopyDC( CDC* pImgDC, CRect* prcClip )
    {
    // BLOCK: copy the image to hStdBitmap for the clipboard
    CDC       dc;
    CBitmap   bm;
    CBitmap*  pOldStdBitmap;
    int       cxWidth  = prcClip->Width();
    int       cyHeight = prcClip->Height();

    if (! dc.CreateCompatibleDC    ( pImgDC                    )
    ||  ! bm.CreateCompatibleBitmap( pImgDC, cxWidth, cyHeight ))
        {
        theApp.SetGdiEmergency();
        return FALSE;
        }

    pOldStdBitmap = dc.SelectObject( &bm );

    CPalette* pOldPalette = SetImgPalette( &dc );

    dc.BitBlt( 0, 0, cxWidth, cyHeight, pImgDC, prcClip->left, prcClip->top, SRCCOPY );
    dc.SelectObject( pOldStdBitmap );

    if (pOldPalette)
        dc.SelectPalette( pOldPalette, FALSE );

    // return the standard format (bitmap) data
    return (HBITMAP)bm.Detach();
    }

/***************************************************************************/

BOOL CImgWnd::IsPasteAvailable()
    {
    BOOL bPasteIsAvailable = FALSE;
    BOOL bBitmapAvailable  = IsClipboardFormatAvailable( CF_BITMAP );
    BOOL bDIBAvailable     = IsClipboardFormatAvailable( CF_DIB );
    BOOL bTextAvailable    = IsClipboardFormatAvailable( CF_TEXT );
    BOOL bMFAvailable      = IsClipboardFormatAvailable( CF_METAFILEPICT );

    if (CImgTool::GetCurrentID() == IDMX_TEXTTOOL)
        {
        CTextTool* pTextTool = (CTextTool*)CImgTool::GetCurrent();

        if (pTextTool                     != NULL
        &&  pTextTool->GetTextEditField() != NULL)
            bPasteIsAvailable = bTextAvailable;
        }
    else
        {
        bPasteIsAvailable = bBitmapAvailable || bDIBAvailable || bMFAvailable;
        }

    return bPasteIsAvailable;
    }

/***************************************************************************/

BOOL CImgWnd::IsSelectionAvailable( void )
    {
    if (CImgTool::GetCurrentID() == IDMX_TEXTTOOL)
        {
        CTextTool* pTextTool = (CTextTool*)CImgTool::GetCurrent();

        if (pTextTool != NULL
        &&  pTextTool->IsKindOf( RUNTIME_CLASS( CTextTool ) ))
            {
            CTedit* pTextEdit = pTextTool->GetTextEditField();

            if (pTextEdit != NULL
            &&  pTextEdit->IsKindOf( RUNTIME_CLASS( CTedit ) ))
                {
                DWORD dwSel = pTextEdit->GetEditWindow()->GetSel();
                BOOL bReturn = (HIWORD( dwSel) != LOWORD( dwSel ));

                if (! bReturn)
                    bReturn = (pTextEdit->GetEditWindow()->GetWindowTextLength()
                           != (int)LOWORD( dwSel ));

                return bReturn;
                }
            }
        }

    if (CImgTool::GetCurrentID() == IDMB_PICKTOOL
    ||  CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL)
        {
        return (theImgBrush.m_pImg != NULL && ! g_bCustomBrush);
        }
    return FALSE;
    }

/***************************************************************************/

int PASCAL CheckPastedSize(int nWidth, int nHeight, IMG* pImg)
{
        int nRet = IDNO;

        // If the image is a bitmap and the bitmap in the clipboard is larger,
        // then give the suer the option2 of growing the image...
        if (nWidth  > pImg->cxWidth
                ||  nHeight > pImg->cyHeight)
        {
                CSize size( max(nWidth, pImg->cxWidth),
                        max(nHeight, pImg->cyHeight) );

                theUndo.BeginUndo( TEXT("Resize Bitmap") );
                VERIFY( pImg->m_pBitmapObj->SetSizeProp( P_Size, size ) );

                theUndo.EndUndo();

                // PSS says users don't want to see this dialog
#if 0
                // WARNING!!! MB_SYSTEMMODAL is _necessary_.  No message boxes should
                // be run while the clipboard is opened.  Loss of focus to other apps
                // can be disasterous! The clipboard will be hung or if the clipboard
                // is closed, the contents could be changed by another app.

                nRet = AfxMessageBox( IDS_ENLAGEBITMAPFORCLIP,
                        MB_YESNOCANCEL | MB_ICONQUESTION | MB_SYSTEMMODAL );
                switch (nRet)
                {
                        case IDYES:
                        {
                                CSize size( max(nWidth, pImg->cxWidth),
                                        max(nHeight, pImg->cyHeight) );

                                theUndo.BeginUndo( TEXT("Resize Bitmap") );
                                VERIFY( pImg->m_pBitmapObj->SetSizeProp( P_Size, size ) );

                                theUndo.EndUndo();
                        }
                        break;
                }
#endif
        }

        return(nRet);
}

struct CStgMedium : public STGMEDIUM
{
    CStgMedium()
    {
        ZeroMemory(this, sizeof(*this));
    }

    ~CStgMedium()
    {
        ReleaseStgMedium(this);
    }
};

HGLOBAL
_GetClipboardData (CLIPFORMAT cf, TYMED tymed, STGMEDIUM *pMedium)
{
    IDataObject *pdo = NULL;
    HANDLE hRet = NULL;

    if (SUCCEEDED(OleGetClipboard (&pdo)))
    {
        FORMATETC fmt = { 0 };

        fmt.cfFormat = cf;
        fmt.lindex   = -1;
        fmt.tymed    = tymed;
        fmt.dwAspect = DVASPECT_CONTENT;

        pMedium->tymed = tymed;

        if (SUCCEEDED(pdo->GetData (&fmt, pMedium)))
        {
            hRet = pMedium->hGlobal;
        }
        else
        {
            ReleaseStgMedium(pMedium);
        }

        pdo->Release ();
    }
    else
    {
        TRACE( TEXT("Cannot open clipboard!\n") );
    }

    return hRet;
}

BOOL CImgWnd::PasteImageClip()
    {
    CWaitCursor wait;
    /////////////////////////////////////////////////////////////////////////
    // Find out what format is available on the clipboard. if it is
    //   A. CF_BITMAP only - Set the mask bits opaque and blt the bitmap
    //      into ICimageDC
    // In both cases, if the destination bitmap differs in size from
    // source bitmap, user is asked if he/she wants the src bitmap
    // stretched/clipped to new size
    /////////////////////////////////////////////////////////////////////////
    if (! m_wClipboardFormat)
        m_wClipboardFormat = (WORD)RegisterClipboardFormat( TEXT("MSPaintFreehand") );


    // Enumerate the cliboard contents to determine what is available.
    // If a CF_BITMAP is seen, set a flag and proceed. If a SDKPAINT
    // private format is seen, stop looking further
    BOOL bBitmapAvailable  = FALSE;
#ifdef FHSELCLIP
    BOOL bPrivateAvailable = FALSE;
#endif // FHSELCLIP
    BOOL bPaletteAvailable = FALSE;
    BOOL bDIBAvailable     = FALSE;
    BOOL bMFAvailable      = FALSE;
    WORD wClipFmt          = 0;

    BITMAP    bmData;
    LONG      cXPelsPerMeter = 0;
    LONG      cYPelsPerMeter = 0;
    BOOL      bResizedBitmap = FALSE;
    CPalette* ppalClipboard  = NULL;
    CBitmap*  pbmClipboard   = NULL;
    LPSTR     lpDib          = NULL;
    HPALETTE  hPal           = NULL;
    HBITMAP   hBitmap        = NULL;
    HGLOBAL   hDIB           = NULL;
    HGLOBAL   hMF            = NULL;

    CStgMedium stgMedium;

        BOOL bGotClip = FALSE;

        hPal = (HPALETTE)_GetClipboardData( CF_PALETTE, TYMED_GDI, &stgMedium );
        if (hPal)
        {
                bPaletteAvailable = TRUE;
                ppalClipboard = CPalette::FromHandle( hPal );

                ReleaseStgMedium(&stgMedium);
        }

    if (!bGotClip)
        {
        hDIB = (HGLOBAL)_GetClipboardData( CF_DIB, TYMED_HGLOBAL, &stgMedium );

        if (hDIB)
            {
            lpDib = (LPSTR)::GlobalLock( hDIB );

            if (lpDib)
                {
                bmData.bmWidth  = DIBWidth ( lpDib );
                bmData.bmHeight = DIBHeight( lpDib );

                if (bmData.bmWidth && bmData.bmHeight)
                    {
                    bDIBAvailable = TRUE;
                    bPaletteAvailable = FALSE;

                    PBITMAPINFOHEADER pbmih = (PBITMAPINFOHEADER) lpDib;

                    if (pbmih->biSize >= sizeof(BITMAPINFOHEADER))
                        {
                        cXPelsPerMeter = pbmih->biXPelsPerMeter;
                        cYPelsPerMeter = pbmih->biYPelsPerMeter;
                        }
                    }
                }
            }
        #ifdef _DEBUG
        TRACE1( "Loaded the DIB %s.\n", (bDIBAvailable? TEXT("Yes"): TEXT("No")) );
        #endif

        bGotClip = bDIBAvailable;
        }

    if (!bGotClip)
        {
        hBitmap = (HBITMAP)_GetClipboardData( CF_BITMAP, TYMED_GDI, &stgMedium );

        if (hBitmap)
            {
            pbmClipboard = CBitmap::FromHandle( hBitmap );

            if (pbmClipboard->GetObject( sizeof( BITMAP ), &bmData ))
                {
                bBitmapAvailable = TRUE;

                DIBSECTION ds;

                if (pbmClipboard->GetObject( sizeof( ds ), &ds ))
                    {
                    cXPelsPerMeter = ds.dsBmih.biXPelsPerMeter;
                    cYPelsPerMeter = ds.dsBmih.biYPelsPerMeter;
                    }

                if (bPaletteAvailable)
                    {
                    if (!ppalClipboard)
                        bBitmapAvailable = FALSE;
                    }
                }
            }

        #ifdef _DEBUG
        TRACE1( "Loaded the Bitmap %s.\n", (bBitmapAvailable? TEXT("Yes"): TEXT("No")) );
        #endif

        bGotClip = bBitmapAvailable;
        }

        if (!bGotClip)
        {
                hMF = (HGLOBAL)_GetClipboardData(CF_METAFILEPICT, TYMED_MFPICT, &stgMedium);
                if (hMF)
                {
                        CDC dcMF;

                        if (dcMF.CreateCompatibleDC( NULL ))
                        {
                                if (GetMFDimensions(hMF, dcMF.m_hDC, &bmData.bmWidth,
                                        &bmData.bmHeight, &cXPelsPerMeter, &cYPelsPerMeter, m_pImg))
                                {
                                        bMFAvailable = TRUE;
                                }
                        }
                }

                bGotClip = bMFAvailable;
        }

    if (!bGotClip)
        {
        return FALSE;
        }

    switch (CheckPastedSize(bmData.bmWidth, bmData.bmHeight, m_pImg))
        {
        default:
            return TRUE;

        case IDYES:
            bResizedBitmap = TRUE;
            break;

        case IDNO:
            break;
        }

    CDC       stdDC;
    BOOL      bOkay   = FALSE;
    CBitmap*  pbmOld  = NULL;
    CPalette* ppalOld = NULL;

    if (bBitmapAvailable)
        {
        CBitmap   bmClipboard;
        CBitmap*  pbmOldCopy  = NULL;
        CPalette* ppalOldCopy = NULL;
        CDC*      pdcCopy     = NULL;

        if (! stdDC.CreateCompatibleDC( NULL ))
            {
            theApp.SetGdiEmergency();
            goto LReturn;
            }

        pbmOld = stdDC.SelectObject( pbmClipboard );

        if (! pbmOld)
            {
            theApp.SetGdiEmergency();
            goto LReturn;
            }

        if (ppalClipboard)
            {
            ppalOld = stdDC.SelectPalette( ppalClipboard, FALSE );
            stdDC.RealizePalette();
            }

        // duplicate the bitmap
        if (! bmClipboard.CreateBitmap( bmData.bmWidth, bmData.bmHeight,
                                        bmData.bmPlanes, bmData.bmBitsPixel, NULL ))
            {
            theApp.SetMemoryEmergency();
            goto LReturn;
            }

        pdcCopy = new CDC;

        if (pdcCopy == NULL)
            {
            theApp.SetMemoryEmergency();
            goto LReturn;
            }

        if (! pdcCopy->CreateCompatibleDC( NULL ))
            {
            delete pdcCopy;
            theApp.SetGdiEmergency();
            goto LReturn;
            }

        pbmOldCopy = pdcCopy->SelectObject( &bmClipboard );

        if (ppalClipboard)
            {
            ppalOldCopy = pdcCopy->SelectPalette( ppalClipboard, FALSE );
            pdcCopy->RealizePalette();
            }

        pdcCopy->BitBlt( 0, 0, bmData.bmWidth, bmData.bmHeight, &stdDC, 0, 0, SRCCOPY );

        if (ppalOldCopy)
            pdcCopy->SelectPalette( ppalOldCopy, FALSE );

        pdcCopy->SelectObject( pbmOldCopy );
        delete pdcCopy;

        stdDC.SelectObject( &bmClipboard );

        // Unload the bitmap
        stdDC.SelectObject( pbmOld );
        pbmOld = NULL;

        if (ppalOld)
            {
            stdDC.SelectPalette( ppalOld, FALSE );
            ppalOld = NULL;
            }

        // if we still do not know the image resolution, use the display resolution
        if (cXPelsPerMeter == 0 && cYPelsPerMeter == 0)
            {
            cXPelsPerMeter = MulDiv(::GetDeviceCaps(stdDC, LOGPIXELSX),10000, 254);
            cYPelsPerMeter = MulDiv(::GetDeviceCaps(stdDC, LOGPIXELSY),10000, 254);
            }

        stdDC.DeleteDC();
        // Now we convert our nice DDB to a DIB and back so we can
        // convert color bitmaps to monochrome nicely and deal with
        // palette differences...
        DWORD dwSize;

        lpDib = (LPSTR) DibFromBitmap( 
            (HBITMAP)bmClipboard.GetSafeHandle(), 
            BI_RGB, 
            0,                                     
            ppalClipboard, 
            NULL, 
            dwSize,
            cXPelsPerMeter, 
            cYPelsPerMeter );
        }

        if (bMFAvailable)
        {
                CDC dcMF;

                if (dcMF.CreateCompatibleDC(CDC::FromHandle(m_pImg->hDC)))
                {
                        CBitmap bmMF;

                        if (bmMF.CreateCompatibleBitmap(CDC::FromHandle(m_pImg->hDC),
                                bmData.bmWidth, bmData.bmHeight))
                        {
                                dcMF.SelectObject(&bmMF);
                                //not needed for DIBSection!!!
                                if (ppalClipboard)
                                {
                                        dcMF.SelectPalette(ppalClipboard, FALSE);
                                }

                                CRect rc(0, 0, bmData.bmWidth, bmData.bmHeight);

                                PlayMetafileIntoDC(hMF, &rc, dcMF.m_hDC);

                                // Select out the bitmap and palette
                                dcMF.DeleteDC();

                                DWORD dwSize;

                                lpDib = (LPSTR) DibFromBitmap(
                                    (HBITMAP)bmMF.m_hObject, BI_RGB, 0,
                                    ppalClipboard, NULL, dwSize,
                                    cXPelsPerMeter, cYPelsPerMeter );
                        }
                }
        }

    if (lpDib)
        {
        CPalette* ppalDib = CreateDIBPalette( lpDib );

        ppalDib = FixupDibPalette( lpDib, ppalDib );

        HBITMAP hbmDib = DIBToBitmap( lpDib, theApp.m_pPalette, m_pImg->hDC );

        if (bDIBAvailable)
            ::GlobalUnlock( hDIB );
        else
            FreeDib( lpDib );

        if (hbmDib != NULL
        && stdDC.CreateCompatibleDC( CDC::FromHandle( m_pImg->hDC ) ))
            {
            CRect   rtBrush( 0, 0, bmData.bmWidth, bmData.bmHeight );
            BOOL    bBrushMade = FALSE;
            CBitmap bmDib;

            bmDib.Attach( hbmDib );

            pbmOld = stdDC.SelectObject( &bmDib );

            if (m_pImg->m_pPalette)
                {
                ppalOld = stdDC.SelectPalette( m_pImg->m_pPalette, FALSE );
                stdDC.RealizePalette();
                }

#ifdef FHSELCLIP
            if (bPrivateAvailable)
                {
                HGLOBAL hPts = (HGLOBAL)_GetClipboardData( m_wClipboardFormat );

                if (hPts)
                    {
                    short* lpShort = (short*)::GlobalLock( hPts );

                    if (lpShort)
                        {
                        BOOL bError   = FALSE;
                        int  iEntries = *lpShort++;
                        LPPOINT lpPts = (LPPOINT)lpShort;

                        CImgTool::Select( IDMB_PICKRGNTOOL );
                        CFreehandSelectTool* pTool = (CFreehandSelectTool*)CImgTool::GetCurrent();

                        if (pTool)
                            {
                            if (pTool->CreatePolyRegion( GetZoom(), lpPts, iEntries )
                            &&  MakeBrush( stdDC.m_hDC, rtBrush ))
                                {
                                bBrushMade = TRUE;
                                }
                            }
                        ::GlobalUnlock( hPts );
                        }
                    }
                }
#endif // FHSELCLIP

            if (! bBrushMade)
                {
                if (CImgTool::GetCurrentID() != IDMB_PICKTOOL)
                    CImgTool::Select( IDMB_PICKTOOL );

                bBrushMade = MakeBrush( stdDC.m_hDC, rtBrush );
                }

            if (bBrushMade)
                {
                // We have to "move" the brush so it appears...
                CRect rect( 0, 0, theImgBrush.m_rcSelection.Width(),
                                  theImgBrush.m_rcSelection.Height() );

                if (! bResizedBitmap)
                    {
                    // Move the brush so that it is in the upper-left corner of
                    // the view (in case it's scrolled)...
                    rect.OffsetRect( -m_xScroll, -m_yScroll );
                    }
                MoveBrush( rect );

                DirtyImg( m_pImg );

                theImgBrush.m_bFirstDrag = FALSE;

                bOkay = TRUE;
                }
            else
                {
                TRACE( TEXT("Paste: MakeBrush failed!\n") );
                }
            if (ppalOld)
                {
                ppalOld = stdDC.SelectPalette( ppalOld, FALSE );
                ppalOld = NULL;
                }

            stdDC.SelectObject( pbmOld );
            pbmOld = NULL;
            bmDib.Detach();
            }

        if (hbmDib != NULL)
            ::DeleteObject( hbmDib );

        if (ppalDib != NULL)
            delete ppalDib;
        }
LReturn:
    if (pbmOld != NULL)
        stdDC.SelectObject( pbmOld );

    if (ppalOld != NULL)
        stdDC.SelectPalette( ppalOld, FALSE );

    return bOkay;
    }

/***************************************************************************/
/* very similar to PasteImageClip, but this will paste into an existing    */
/* selection (theImgBrush), resizing it if necessary, and not moving it    */
/***************************************************************************/

BOOL CImgWnd::PasteImageFile( LPSTR lpDib )
    {
    CDC   stdDC;
    CRect cRectSelection = theImgBrush.m_rcSelection;
    BOOL bOkay = FALSE;

    if (lpDib == NULL)
        return bOkay;

    int iWidth  = (int)DIBWidth ( lpDib );
    int iHeight = (int)DIBHeight( lpDib );

    if (CImgTool::GetCurrentID()==IDMB_PICKTOOL && theImgBrush.m_bFirstDrag)
    {
        if (iWidth < theImgBrush.m_size.cx)
            {
            cRectSelection.right = cRectSelection.left + iWidth - 1;
            }
        if (iHeight < theImgBrush.m_size.cy)
            {
            cRectSelection.bottom = cRectSelection.top + iHeight - 1;
            }

        // If the image is a bitmap and the bitmap in the clipboard is larger,
        // then give the user the option of growing the image...
        if (iWidth  > theImgBrush.m_size.cx
        ||  iHeight > theImgBrush.m_size.cy)
            {
                cRectSelection.right  = cRectSelection.left + iWidth  - 1;
                cRectSelection.bottom = cRectSelection.top  + iHeight - 1;

                // PSS says users don't want to see this dialog
#if 0
            switch (AfxMessageBox( IDS_ENLAGEBITMAPFORCLIP,
                                    MB_YESNOCANCEL | MB_ICONQUESTION ))
                {
                default:
                    return bOkay;
                    break;

                case IDYES:
                    cRectSelection.right  = cRectSelection.left + iWidth  - 1;
                    cRectSelection.bottom = cRectSelection.top  + iHeight - 1;
                    break;

                case IDNO:
                    break;
                }
#endif
            }
    }
    else
    {
                int xPos = -m_xScroll;
                int yPos = -m_yScroll;

                switch (CheckPastedSize(iWidth, iHeight, m_pImg))
                {
                case IDYES:
                        xPos = yPos = 0;
                        break;

                case IDNO:
                        break;

                default:
                        return(bOkay);
                }

                CImgTool::Select(IDMB_PICKTOOL);
                cRectSelection = CRect(xPos, yPos, xPos+iWidth, yPos+iHeight);
    }

    MakeBrush( m_pImg->hDC, cRectSelection );
    // MakeBrush sets this
    theImgBrush.m_bFirstDrag = FALSE;

    if (! stdDC.CreateCompatibleDC( CDC::FromHandle( m_pImg->hDC ) ))
        {
        theApp.SetGdiEmergency();
        return bOkay;
        }

    CPalette* ppalDib = CreateDIBPalette( lpDib );

    ppalDib = FixupDibPalette( lpDib, ppalDib );

    HBITMAP hbmDib = DIBToBitmap( lpDib, theApp.m_pPalette, m_pImg->hDC );

    SetUndo( m_pImg );

    if (hbmDib != NULL)
        {
        CBitmap   bmDib;
        CPalette* ppalOld = NULL;
        CBitmap*  pbmOld  = NULL;

        bmDib.Attach( hbmDib );

        pbmOld = stdDC.SelectObject( &bmDib );

        if (m_pImg->m_pPalette)
            {
            ppalOld = stdDC.SelectPalette( m_pImg->m_pPalette, FALSE );
            stdDC.RealizePalette();
            }

        if (MakeBrush( stdDC.m_hDC, CRect( CPoint( 0, 0 ), cRectSelection.Size() ) ))
            {
            theImgBrush.m_bFirstDrag = FALSE;

            // We have to "move" the brush so it appears...
            MoveBrush( cRectSelection );

            DirtyImg( m_pImg );

            bOkay = TRUE;
            }
        else
            {
            TRACE( TEXT("Paste: MakeBrush failed!\n") );
            }

        if (ppalOld != NULL)
            {
            ppalOld = stdDC.SelectPalette( ppalOld, FALSE );
            }

        stdDC.SelectObject( pbmOld );
        bmDib.Detach();

        ::DeleteObject( hbmDib );
        }

    if (ppalDib != NULL)
        delete ppalDib;

    return bOkay;
    }

/***************************************************************************/
// Stolen from PBrush
//
/****************************Module*Header******************************\
* Module Name: metafile.c                                               *
* Routines to paste a metafile as a bitmap.                             *
* Copyright (c) 1987 - 1991  Microsoft Corporation                      *
\***********************************************************************/

/* Computes dimensions of a metafile picture in pixels */
BOOL GetMFDimensions(
    HANDLE hMF,     /* handle to the CF_METAFILEPICT object from clipbrd */
    HDC hDC,        /* display context */
    long *pWidth,    /* width of picture in pixels, OUT param */
    long *pHeight,   /* height of picture in pixels, OUT param */
    long *pcXPelsPerMeter,    /* horizontal resolution, OUT param */
    long *pcYPelsPerMeter,    /* vertical resolution, OUT param */
    IMG* pImg)
{
    METAFILEPICT FAR *lpMfp, Picture;
    int MapModeOld=0;
    RECT Rect;
    long xScale, yScale, Scale;
    int hRes, vRes;     /* horz and vert resolution, in pixels */
    int hSize, vSize;   /* horz and vert size, in mm */
    int fResult = FALSE;

    if (!hMF || !(lpMfp = (METAFILEPICT FAR *)GlobalLock(hMF)))
        return FALSE;
    /* copy metafile picture hdr */
    Picture = *lpMfp;
    GlobalUnlock(hMF);

    /* Do not modify given DC's attributes */
    SaveDC(hDC);

    /* set the mapping mode */
    MapModeOld = SetMapMode(hDC, Picture.mm);
    if (Picture.mm != MM_ISOTROPIC && Picture.mm != MM_ANISOTROPIC)
    {
        /* For modes other than ISOTROPIC and ANISOTROPIC the picture
         * dimensions are given in logical units.
        /* Convert logical units to pixels. */
        Rect.left = 0; Rect.right = Picture.xExt;
        Rect.top = 0;  Rect.bottom = Picture.yExt;
        if (!LPtoDP(hDC, (LPPOINT)&Rect, 2))
            goto Error;
        *pWidth = Rect.right - Rect.left + 1;
        *pHeight = Rect.bottom - Rect.top + 1;
        fResult = TRUE;
    }
    else    /* ISOTROPIC or ANISOTROPIC mode,
             * using the xExt and yExt, determine pixel width and height of
             * the image */
    {
        hRes = GetDeviceCaps(hDC, HORZRES);
        vRes = GetDeviceCaps(hDC, VERTRES);
        hSize = GetDeviceCaps(hDC, HORZSIZE);
        vSize = GetDeviceCaps(hDC, VERTSIZE);
        *pcXPelsPerMeter = hRes * 1000 / hSize;
        *pcYPelsPerMeter = vRes * 1000 / vSize;
        if (Picture.xExt == 0)  /* assume default size, aspect ratio */
        {
            *pWidth = pImg->cxWidth;
            *pHeight = pImg->cyHeight;
        }
        else if (Picture.xExt > 0)  /* use suggested size in HIMETRIC units */
        {
            // convert suggested extents(in .01 mm units) for picture to pixel units.

            // xPixelsPermm = hRes/hSize;, yPixelsPermm = vRes/vSize;
            // Use Pixels Per logical unit.
            // *pWidth = Picture.xExt*xPixelsPermm/100;
            // *pHeight = Picture.yExt*yPixelsPermm/100;
            *pWidth = ((long)Picture.xExt * hRes/hSize/100);
            *pHeight = ((long)Picture.yExt * vRes/vSize/100);
        }
        else if (Picture.xExt < 0)  /* use suggested aspect ratio, default size */
        {
            // 1 log unit = .01 mm.
            // (# of log units in imageWid pixels)/xExt;
            xScale = 100L * (long) pImg->cxWidth *
                            hSize/hRes/-Picture.xExt;
            // (# of log units in imageHgt pixels)/yExt;
            yScale = 100L * (long) pImg->cyHeight *
                            vSize/vRes/-Picture.yExt;
            // choose the minimum to accomodate the entire image
            Scale = min(xScale, yScale);
            // use scaled Pixels Per log unit.
            *pWidth = ((long)-Picture.xExt * Scale *
                            hRes/hSize / 100);
            *pHeight = ((long)-Picture.yExt * Scale *
                            vRes/vSize / 100);
        }
        fResult = TRUE;
    }

Error:
    if (MapModeOld)
        SetMapMode(hDC, MapModeOld);    /* select the old mapping mode */
    RestoreDC(hDC, -1);
    return fResult;
}

BOOL PlayMetafileIntoDC(
    HANDLE hMF,
    RECT *pRect,
    HDC hDC)
{
    HBRUSH      hbrBackground;
    METAFILEPICT FAR *lpMfp;

    if (!(lpMfp = (METAFILEPICT FAR *)GlobalLock(hMF)))
        return FALSE;

    SaveDC(hDC);

        /* Setup background color for the bitmap */
    hbrBackground = CreateSolidBrush(crRight);

    if (hbrBackground)
    {
        FillRect(hDC, pRect, hbrBackground);
        DeleteObject(hbrBackground);
    }

    SetMapMode(hDC, lpMfp->mm);
    if (lpMfp->mm == MM_ISOTROPIC || lpMfp->mm == MM_ANISOTROPIC)
        SetViewportExtEx(hDC, pRect->right-pRect->left, pRect->bottom-pRect->top,
            NULL);
    PlayMetaFile(hDC, lpMfp->hMF);
    GlobalUnlock(hMF);
    RestoreDC(hDC, -1);
    return TRUE;
}