windows-nt/Source/XPSP1/NT/shell/osshell/accesory/mspaint/imgbrush.cpp
2020-09-26 16:20:57 +08:00

580 lines
17 KiB
C++

#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 "imgbrush.h"
#include "imgwell.h"
#include "imgtools.h"
#include "t_fhsel.h"
#include "toolbox.h"
#include "mmsystem.h"
#ifdef _DEBUG
#undef THIS_FILE
static CHAR BASED_CODE THIS_FILE[] = __FILE__;
#endif
#include "memtrace.h"
CImgBrush theImgBrush;
CImgBrush::CImgBrush() : m_bCuttingFromImage(FALSE), m_bOpaque(TRUE)
{
}
CImgBrush::~CImgBrush()
{
// cleanup old region if exists
if (m_cRgnPolyFreeHandSel.GetSafeHandle() != NULL)
m_cRgnPolyFreeHandSel.DeleteObject();
if (m_cRgnPolyFreeHandSelBorder.GetSafeHandle() != NULL)
m_cRgnPolyFreeHandSelBorder.DeleteObject();
if (m_hbmOld)
m_dc.SelectObject( CBitmap::FromHandle( m_hbmOld ) );
if (m_hbmMaskOld)
m_dc.SelectObject( CBitmap::FromHandle( m_hbmMaskOld ) );
m_dc.DeleteDC();
m_bitmap.DeleteObject();
m_maskDC.DeleteDC();
m_maskBitmap.DeleteObject();
}
BOOL CImgBrush::CopyTo(CImgBrush& destBrush)
{
if (destBrush.m_hbmOld)
destBrush.m_dc.SelectObject( CBitmap::FromHandle( destBrush.m_hbmOld ) );
if (destBrush.m_hbmMaskOld)
destBrush.m_maskDC.SelectObject( CBitmap::FromHandle( destBrush.m_hbmMaskOld ) );
destBrush.m_hbmOld = NULL;
destBrush.m_hbmMaskOld = NULL;
destBrush.m_dc.DeleteDC();
destBrush.m_bitmap.DeleteObject();
destBrush.m_maskDC.DeleteDC();
destBrush.m_maskBitmap.DeleteObject();
if (m_dc.m_hDC != NULL)
{
if (! destBrush.m_dc.CreateCompatibleDC( NULL )
|| ! destBrush.m_bitmap.CreateCompatibleBitmap(&m_dc, m_size.cx, m_size.cy))
{
theApp.SetGdiEmergency(FALSE);
return FALSE;
}
destBrush.m_hbmOld = (HBITMAP)((destBrush.m_dc.SelectObject( &destBrush.m_bitmap ))->GetSafeHandle());
CPalette* ppalOldSrc = SetBrushPalette( &m_dc, TRUE ); // Background ??
CPalette* ppalOldDest = SetBrushPalette( &destBrush.m_dc, TRUE ); // Background ??
destBrush.m_dc.BitBlt( 0, 0, m_size.cx, m_size.cy, &m_dc, 0, 0, SRCCOPY );
if (ppalOldSrc)
m_dc.SelectPalette( ppalOldSrc, TRUE ); // Background ??
if (ppalOldDest)
destBrush.m_dc.SelectPalette( ppalOldDest, TRUE ); // Background ??
}
if (m_maskDC.m_hDC != NULL)
{
if (! destBrush.m_maskDC.CreateCompatibleDC(NULL)
|| ! destBrush.m_maskBitmap.CreateCompatibleBitmap(&m_maskDC, m_size.cx,
m_size.cy))
{
theApp.SetGdiEmergency(FALSE);
return FALSE;
}
destBrush.m_hbmMaskOld = (HBITMAP)((destBrush.m_maskDC.SelectObject(
&destBrush.m_maskBitmap))->GetSafeHandle());
destBrush.m_maskDC.BitBlt(0, 0, m_size.cx, m_size.cy, &m_maskDC, 0, 0, SRCCOPY);
}
destBrush.m_size = m_size;
destBrush.m_bFirstDrag = m_bFirstDrag;
destBrush.m_bLastDragWasASmear = m_bLastDragWasASmear;
destBrush.m_bLastDragWasFirst = m_bLastDragWasFirst;
destBrush.m_bMakingSelection = m_bMakingSelection;
destBrush.m_bMoveSel = m_bMoveSel;
destBrush.m_bSmearSel = m_bSmearSel;
destBrush.m_bOpaque = m_bOpaque;
destBrush.m_rcDraggedFrom = m_rcDraggedFrom;
destBrush.m_pImg = m_pImg;
destBrush.m_rcSelection = m_rcSelection;
destBrush.m_handle = m_handle;
return TRUE;
}
void CImgBrush::CenterHandle()
{
m_handle.cx = m_size.cx / 2;
m_handle.cy = m_size.cy / 2;
}
void CImgBrush::TopLeftHandle()
{
m_handle.cx = 0;
m_handle.cy = 0;
}
CPalette* CImgBrush::SetBrushPalette( CDC* pdc, BOOL bForce )
{
CPalette* ppal = NULL;
CPalette* ppalOld = NULL;
if (theApp.m_pPalette
&& theApp.m_pPalette->m_hObject)
ppal = theApp.m_pPalette;
if (ppal != NULL)
{
ppalOld = pdc->SelectPalette( ppal, bForce );
pdc->RealizePalette();
}
return ppalOld;
}
HPALETTE CImgBrush::SetBrushPalette( HDC hdc, BOOL bForce )
{
CPalette* ppal = NULL;
HPALETTE hpalOld = NULL;
if (theApp.m_pPalette
&& theApp.m_pPalette->m_hObject)
ppal = theApp.m_pPalette;
if (ppal != NULL)
{
hpalOld = ::SelectPalette( hdc, (HPALETTE)ppal->m_hObject, bForce );
RealizePalette( hdc );
}
return hpalOld;
}
BOOL CImgBrush::SetSize( CSize newSize, BOOL bStretchToFit )
{
BOOL bFlipX;
BOOL bFlipY;
if (newSize.cx == m_size.cx
&& newSize.cy == m_size.cy)
return TRUE;
if (bFlipX = (newSize.cx < 0))
newSize.cx = -newSize.cx;
if (bFlipY = (newSize.cy < 0))
newSize.cy = -newSize.cy;
if (newSize.cx == 0)
newSize.cx = 1;
if (newSize.cy == 0)
newSize.cy = 1;
if (CImgTool::GetCurrentID() != IDMX_TEXTTOOL)
{
CDC newDC;
CBitmap newBitmap;
CDC newMaskDC;
CBitmap newMaskBitmap;
//REARCHITECT Potential for DC && Bitmap leaks here on partial failure!!
if (! newDC.CreateCompatibleDC ( &m_dc )
|| ! newBitmap.CreateCompatibleBitmap( &m_dc, newSize.cx, newSize.cy )
|| ! newMaskDC.CreateCompatibleDC ( &m_dc )
|| ! newMaskBitmap.CreateBitmap(newSize.cx, newSize.cy, 1, 1, NULL ))
return FALSE;
CBitmap* pbmOld = newDC.SelectObject( &newBitmap );
CPalette* ppalOldSrc = SetBrushPalette( &m_dc, FALSE );
CPalette* ppalOldDest = SetBrushPalette( &newDC, FALSE );
newDC.SetStretchBltMode(COLORONCOLOR);
if (bStretchToFit)
{
StretchCopy( newDC.m_hDC, bFlipX ? newSize.cx : 0,
bFlipY ? newSize.cy : 0,
bFlipX ? -newSize.cx : newSize.cx,
bFlipY ? -newSize.cy : newSize.cy,
m_dc.m_hDC, 0, 0, m_size.cx, m_size.cy );
}
else
{
StretchCopy( newDC.m_hDC, bFlipX ? newSize.cx : 0,
bFlipY ? newSize.cy : 0,
m_size.cx, m_size.cy,
m_dc.m_hDC, 0, 0, m_size.cx, m_size.cy );
}
COLORREF crOldBk = newDC.SetBkColor( crRight );
CBitmap* pbmOldMask = newMaskDC.SelectObject( &newMaskBitmap );
if (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL)
{
CFreehandSelectTool* pTool = (CFreehandSelectTool*)CImgTool::GetCurrent();
if (pTool->ExpandPolyRegion( newSize.cx, newSize.cy ))
{
newMaskDC.PatBlt( 0, 0, newSize.cx, newSize.cy, BLACKNESS );
if (m_cRgnPolyFreeHandSel.GetSafeHandle())
newMaskDC.FillRgn( &m_cRgnPolyFreeHandSel,
CBrush::FromHandle( (HBRUSH)::GetStockObject( WHITE_BRUSH ) ) );
}
}
else
{
newMaskDC.PatBlt( 0, 0, newSize.cx, newSize.cy, WHITENESS );
}
newMaskDC.BitBlt( 0, 0, newSize.cx, newSize.cy, &newDC, 0, 0, DSna );
newDC.SetBkColor( crOldBk );
if (ppalOldSrc)
m_dc.SelectPalette( ppalOldSrc, FALSE );
if (ppalOldDest)
newDC.SelectPalette( ppalOldDest, FALSE );
if (m_hbmOld)
m_dc.SelectObject( CBitmap::FromHandle( m_hbmOld ) );
if (m_hbmMaskOld)
m_maskDC.SelectObject( CBitmap::FromHandle( m_hbmMaskOld ) );
m_dc.DeleteDC();
m_maskDC.DeleteDC();
m_bitmap.DeleteObject();
m_maskBitmap.DeleteObject();
m_dc.Attach( newDC.Detach() );
m_bitmap.Attach( newBitmap.Detach() );
m_maskDC.Attach( newMaskDC.Detach() );
m_maskBitmap.Attach( newMaskBitmap.Detach() );
m_hbmOld = (HBITMAP)(pbmOld->GetSafeHandle());
m_hbmMaskOld = (HBITMAP)(pbmOldMask->GetSafeHandle());
}
m_size.cx = newSize.cx;
m_size.cy = newSize.cy;
return TRUE;
}
#if defined(DEBUGSHOWBITMAPS)
void DebugShowBitmap(HDC hdcSrc, int x, int y, int wid, int hgt)
{
HDC hdcDst = GetDC(NULL);
BitBlt(hdcDst, 0, 0, wid, hgt, hdcSrc, x, y, SRCCOPY);
ReleaseDC(NULL, hdcDst);
}
#endif
BOOL QuickColorToMono(CDC* pdcMono, int xMono, int yMono, int cx, int cy,
CDC *pdcColor, int xColor, int yColor, DWORD dwROP, COLORREF crTrans)
{
RGBQUAD rgb[256];
int nColors = GetDIBColorTable(pdcColor->m_hDC, 0, 256, &rgb[0]);
if (nColors == 0)
{
return(FALSE);
}
RGBQUAD rgbWhite;
rgbWhite.rgbRed = 255;
rgbWhite.rgbGreen = 255;
rgbWhite.rgbBlue = 255;
rgbWhite.rgbReserved = 0;
RGBQUAD rgbBlack;
rgbBlack.rgbRed = 0;
rgbBlack.rgbGreen = 0;
rgbBlack.rgbBlue = 0;
rgbBlack.rgbReserved = 0;
RGBQUAD rgbTemp[256];
switch ((BYTE)((crTrans)>>24))
{
case 0:
case 2:
{
RGBQUAD rgbTrans;
rgbTrans.rgbRed = GetRValue(crTrans);
rgbTrans.rgbGreen = GetGValue(crTrans);
rgbTrans.rgbBlue = GetBValue(crTrans);
rgbTrans.rgbReserved = 0;
for (int nColor=nColors-1; nColor>=0; --nColor)
{
if (memcmp(&rgb[nColor], &rgbTrans, sizeof(rgbTrans)) == 0)
{
rgbTemp[nColor] = rgbWhite;
}
else
{
rgbTemp[nColor] = rgbBlack;
}
}
break;
}
// We can put support for different COLORREF formats here
default:
return(FALSE);
}
SetDIBColorTable(pdcColor->m_hDC, 0, nColors, &rgbTemp[0]);
pdcMono->BitBlt(xMono, yMono, cx, cy, pdcColor, xColor, yColor, dwROP);
SetDIBColorTable(pdcColor->m_hDC, 0, nColors, &rgb[0]);
return(TRUE);
}
#define COLORTOMONOBUG
#ifdef COLORTOMONOBUG
void CImgBrush::ColorToMonoBitBlt(CDC* pdcMono, int xMono, int yMono, int cx, int cy,
CDC *pdcColor, int xColor, int yColor, DWORD dwROP, COLORREF transparentColor)
{
if (QuickColorToMono(pdcMono, xMono, yMono, cx, cy,
pdcColor, xColor, yColor, dwROP, transparentColor))
{
return;
}
CDC dcColor;
CTempBitmap bmColor;
CBitmap* pbmOldColor = NULL;
// Use a moderate-sized intermediate bitmap
int cyStep = 0xffff / cx;
cyStep = max(1, min(cy, cyStep));
HDC hdcScreen = GetDC(NULL);
BOOL bError = (!dcColor.CreateCompatibleDC(NULL)
|| !bmColor.CreateCompatibleBitmap(CDC::FromHandle(hdcScreen), cx, cyStep)
|| (pbmOldColor = dcColor.SelectObject(&bmColor))==NULL);
ReleaseDC(NULL, hdcScreen);
if (bError)
{
theApp.SetGdiEmergency(FALSE);
return;
}
CPalette* ppalOld = SetBrushPalette( pdcColor, FALSE );
CPalette* ppalOldColor = SetBrushPalette( &dcColor, FALSE );
dcColor.SetBkColor( transparentColor );
int yStep;
for (yStep=0; yStep<cy; yStep+=cyStep)
{
if (cyStep > cy - yStep)
{
cyStep = cy - yStep;
}
dcColor.BitBlt(0, 0, cx, cyStep, pdcColor, xColor, yColor+yStep, SRCCOPY);
pdcMono->BitBlt(xMono, yMono+yStep, cx, cyStep, &dcColor, 0, 0, dwROP);
DebugShowBitmap(pdcMono->m_hDC, xMono, yMono, cx, cy);
}
if (ppalOld)
{
pdcColor->SelectPalette( ppalOld, FALSE );
}
dcColor.SelectObject(pbmOldColor);
if (ppalOldColor)
{
dcColor.SelectPalette( ppalOldColor, FALSE );
}
}
#endif // COLORTOMONOBUG
void CImgBrush::RecalcMask( COLORREF transparentColor )
{
if (! m_dc.GetSafeHdc() || ! m_maskDC.m_hDC)
return;
#ifndef COLORTOMONOBUG
CPalette* ppalOld = SetBrushPalette( &m_dc, FALSE );
COLORREF oldBkColor = m_dc.SetBkColor( transparentColor );
#endif // COLORTOMONOBUG
if (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL)
{
m_maskDC.PatBlt( 0, 0, m_size.cx, m_size.cy, BLACKNESS );
if (m_cRgnPolyFreeHandSel.GetSafeHandle())
m_maskDC.FillRgn( &m_cRgnPolyFreeHandSel,
CBrush::FromHandle( (HBRUSH)::GetStockObject( WHITE_BRUSH ) ) );
if (! m_bOpaque) // can't test true, since bitfield
#ifdef COLORTOMONOBUG
ColorToMonoBitBlt(&m_maskDC, 0, 0, m_size.cx, m_size.cy,
&m_dc, 0, 0, DSna, transparentColor);
#else // COLORTOMONOBUG
m_maskDC.BitBlt( 0, 0, m_size.cx, m_size.cy, &m_dc, 0, 0, DSna );
#endif // COLORTOMONOBUG
}
else
{
#ifdef COLORTOMONOBUG
ColorToMonoBitBlt(&m_maskDC, 0, 0, m_size.cx, m_size.cy,
&m_dc, 0, 0, NOTSRCCOPY, transparentColor);
#else // COLORTOMONOBUG
m_maskDC.BitBlt( 0, 0, m_size.cx, m_size.cy, &m_dc, 0, 0, NOTSRCCOPY );
#endif // COLORTOMONOBUG
}
#ifndef COLORTOMONOBUG
m_dc.SetBkColor( oldBkColor );
if (ppalOld)
m_dc.SelectPalette( ppalOld, FALSE );
#endif // COLORTOMONOBUG
}
void GetMonoBltColors(HDC hDC, HBITMAP hBM, COLORREF& crNewBk, COLORREF& crNewText)
{
crNewBk = RGB(0xff, 0xff, 0xff);
crNewText = RGB(0x00, 0x00, 0x00);
RGBQUAD rq;
if (GetDIBColorTable(hDC, 0, 1, &rq) == 1)
{
if (hBM == NULL)
{
hBM = (HBITMAP) GetCurrentObject(hDC, OBJ_BITMAP);
}
WORD nMaxIndex = 0xff;
BITMAP bm;
if (GetObject(hBM, sizeof(bm), &bm))
{
nMaxIndex = (1 << bm.bmBitsPixel) - 1;
}
crNewBk = DIBINDEX(nMaxIndex);
crNewText = DIBINDEX(0x00);
}
}
// This handles drawing the brush with Draw Opaque turned off.
//
void CImgBrush::BltMatte(IMG* pimg, CPoint topLeft)
{
COLORREF crNewBk, crNewText;
GetMonoBltColors(pimg->hDC, pimg->hBitmap, crNewBk, crNewText);
COLORREF crOldBk = SetBkColor(pimg->hDC, crNewBk);
COLORREF crOldText = SetTextColor(pimg->hDC, crNewText);
CPalette* ppalOld = SetBrushPalette( &m_dc, FALSE ); // Background ??
// Copying from a bitmap...
DebugShowBitmap(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy);
BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy,
m_dc.m_hDC, 0, 0, DSx);
DebugShowBitmap(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy);
BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy,
m_maskDC.m_hDC, 0, 0, DSna);
DebugShowBitmap(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy);
BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy,
m_dc.m_hDC, 0, 0, DSx);
DebugShowBitmap(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy);
if (ppalOld)
m_dc.SelectPalette( ppalOld, FALSE ); // Background ??
SetBkColor(pimg->hDC, crOldBk);
SetTextColor(pimg->hDC, crOldText);
}
// This handles drawing the brush with Draw Opaque turned on.
//
void CImgBrush::BltReplace(IMG* pimg, CPoint topLeft)
{
int iToolID = CImgTool::GetCurrentID();
if (iToolID == IDMB_PICKRGNTOOL)
{
BltMatte( pimg, topLeft );
}
else
{
CPalette* ppalOld = SetBrushPalette( &m_dc, FALSE ); // Background ??
BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy,
m_dc.m_hDC, 0, 0, SRCCOPY);
if (ppalOld)
m_dc.SelectPalette( ppalOld, FALSE ); // Background ??
}
}
// This handles erasing with the brush (draws mask in solid color).
//
void CImgBrush::BltColor(IMG* pimg, CPoint topLeft, COLORREF color)
{
COLORREF crOldBk = SetBkColor(pimg->hDC, color);
COLORREF crOldText = SetTextColor(pimg->hDC, RGB(0, 0, 0));
BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy,
m_maskDC.m_hDC, 0, 0, DSx);
SetBkColor(pimg->hDC, RGB(255, 255, 255));
BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy,
m_maskDC.m_hDC, 0, 0, DSna);
SetBkColor(pimg->hDC, color);
BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy,
m_maskDC.m_hDC, 0, 0, DSx);
SetTextColor(pimg->hDC, crOldText);
SetBkColor(pimg->hDC, crOldBk);
}