mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 22:32:58 +00:00
[MSPAINT] Improve behaviour on memory shortage (#7780)
Improve UX on memory shortage. JIRA issue: CORE-20020 - Clear history on memory shortage. - Improve CCanvasWindow::OnPaint on memory shortage. - Add null check in CCanvasWindow::DoDraw. - Retire using of cache in CCanvasWindow.
This commit is contained in:
parent
c930c8c464
commit
9563c07146
5 changed files with 47 additions and 18 deletions
|
@ -16,16 +16,11 @@ CCanvasWindow::CCanvasWindow()
|
||||||
, m_hitCanvasSizeBox(HIT_NONE)
|
, m_hitCanvasSizeBox(HIT_NONE)
|
||||||
, m_ptOrig { -1, -1 }
|
, m_ptOrig { -1, -1 }
|
||||||
{
|
{
|
||||||
m_ahbmCached[0] = m_ahbmCached[1] = NULL;
|
|
||||||
m_rcResizing.SetRectEmpty();
|
m_rcResizing.SetRectEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
CCanvasWindow::~CCanvasWindow()
|
CCanvasWindow::~CCanvasWindow()
|
||||||
{
|
{
|
||||||
if (m_ahbmCached[0])
|
|
||||||
::DeleteObject(m_ahbmCached[0]);
|
|
||||||
if (m_ahbmCached[1])
|
|
||||||
::DeleteObject(m_ahbmCached[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RECT CCanvasWindow::GetBaseRect()
|
RECT CCanvasWindow::GetBaseRect()
|
||||||
|
@ -119,16 +114,30 @@ VOID CCanvasWindow::zoomTo(INT newZoom, LONG left, LONG top)
|
||||||
Invalidate(TRUE);
|
Invalidate(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID CCanvasWindow::DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint)
|
BOOL CCanvasWindow::DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint)
|
||||||
{
|
{
|
||||||
// This is the target area we have to draw on
|
// This is the target area we have to draw on
|
||||||
CRect rcCanvasDraw;
|
CRect rcCanvasDraw;
|
||||||
rcCanvasDraw.IntersectRect(&rcClient, &rcPaint);
|
rcCanvasDraw.IntersectRect(&rcClient, &rcPaint);
|
||||||
|
|
||||||
|
// Calculate image size
|
||||||
|
CRect rcImage;
|
||||||
|
GetImageRect(rcImage);
|
||||||
|
SIZE sizeImage = { imageModel.GetWidth(), imageModel.GetHeight() };
|
||||||
|
|
||||||
// We use a memory bitmap to reduce flickering
|
// We use a memory bitmap to reduce flickering
|
||||||
|
HBITMAP hbmCache1 = CreateDIBWithProperties(rcClient.right, rcClient.bottom);
|
||||||
|
if (!hbmCache1)
|
||||||
|
return FALSE; // Out of memory
|
||||||
|
HBITMAP hbmCache2 = CreateDIBWithProperties(sizeImage.cx, sizeImage.cy);
|
||||||
|
if (!hbmCache2)
|
||||||
|
{
|
||||||
|
::DeleteObject(hbmCache1);
|
||||||
|
return FALSE; // Out of memory
|
||||||
|
}
|
||||||
|
|
||||||
HDC hdcMem0 = ::CreateCompatibleDC(hDC);
|
HDC hdcMem0 = ::CreateCompatibleDC(hDC);
|
||||||
m_ahbmCached[0] = CachedBufferDIB(m_ahbmCached[0], rcClient.right, rcClient.bottom);
|
HGDIOBJ hbm0Old = ::SelectObject(hdcMem0, hbmCache1);
|
||||||
HGDIOBJ hbm0Old = ::SelectObject(hdcMem0, m_ahbmCached[0]);
|
|
||||||
|
|
||||||
// Fill the background on hdcMem0
|
// Fill the background on hdcMem0
|
||||||
::FillRect(hdcMem0, &rcCanvasDraw, (HBRUSH)(COLOR_APPWORKSPACE + 1));
|
::FillRect(hdcMem0, &rcCanvasDraw, (HBRUSH)(COLOR_APPWORKSPACE + 1));
|
||||||
|
@ -138,11 +147,6 @@ VOID CCanvasWindow::DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint)
|
||||||
if (!selectionModel.m_bShow && !::IsWindowVisible(textEditWindow))
|
if (!selectionModel.m_bShow && !::IsWindowVisible(textEditWindow))
|
||||||
drawSizeBoxes(hdcMem0, &rcBase, FALSE, &rcCanvasDraw);
|
drawSizeBoxes(hdcMem0, &rcBase, FALSE, &rcCanvasDraw);
|
||||||
|
|
||||||
// Calculate image size
|
|
||||||
CRect rcImage;
|
|
||||||
GetImageRect(rcImage);
|
|
||||||
SIZE sizeImage = { imageModel.GetWidth(), imageModel.GetHeight() };
|
|
||||||
|
|
||||||
// Calculate the target area on the image
|
// Calculate the target area on the image
|
||||||
CRect rcImageDraw = rcCanvasDraw;
|
CRect rcImageDraw = rcCanvasDraw;
|
||||||
CanvasToImage(rcImageDraw);
|
CanvasToImage(rcImageDraw);
|
||||||
|
@ -154,8 +158,7 @@ VOID CCanvasWindow::DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint)
|
||||||
|
|
||||||
// hdcMem1 <-- imageModel
|
// hdcMem1 <-- imageModel
|
||||||
HDC hdcMem1 = ::CreateCompatibleDC(hDC);
|
HDC hdcMem1 = ::CreateCompatibleDC(hDC);
|
||||||
m_ahbmCached[1] = CachedBufferDIB(m_ahbmCached[1], sizeImage.cx, sizeImage.cy);
|
HGDIOBJ hbm1Old = ::SelectObject(hdcMem1, hbmCache2);
|
||||||
HGDIOBJ hbm1Old = ::SelectObject(hdcMem1, m_ahbmCached[1]);
|
|
||||||
::BitBlt(hdcMem1, rcImageDraw.left, rcImageDraw.top, rcImageDraw.Width(), rcImageDraw.Height(),
|
::BitBlt(hdcMem1, rcImageDraw.left, rcImageDraw.top, rcImageDraw.Width(), rcImageDraw.Height(),
|
||||||
imageModel.GetDC(), rcImageDraw.left, rcImageDraw.top, SRCCOPY);
|
imageModel.GetDC(), rcImageDraw.left, rcImageDraw.top, SRCCOPY);
|
||||||
|
|
||||||
|
@ -208,6 +211,10 @@ VOID CCanvasWindow::DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint)
|
||||||
// Clean up hdcMem0
|
// Clean up hdcMem0
|
||||||
::SelectObject(hdcMem0, hbm0Old);
|
::SelectObject(hdcMem0, hbm0Old);
|
||||||
::DeleteDC(hdcMem0);
|
::DeleteDC(hdcMem0);
|
||||||
|
::DeleteObject(hbmCache2);
|
||||||
|
::DeleteObject(hbmCache1);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID CCanvasWindow::updateScrollRange()
|
VOID CCanvasWindow::updateScrollRange()
|
||||||
|
@ -691,9 +698,22 @@ LRESULT CCanvasWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
|
||||||
RECT rcClient;
|
RECT rcClient;
|
||||||
GetClientRect(&rcClient);
|
GetClientRect(&rcClient);
|
||||||
|
|
||||||
|
static BOOL s_bShowedOutOfMemory = FALSE; // Don't show "Out Of Memory" message multiple time
|
||||||
|
|
||||||
PAINTSTRUCT ps;
|
PAINTSTRUCT ps;
|
||||||
HDC hDC = BeginPaint(&ps);
|
HDC hDC = BeginPaint(&ps);
|
||||||
DoDraw(hDC, rcClient, ps.rcPaint);
|
|
||||||
|
if (DoDraw(hDC, rcClient, ps.rcPaint))
|
||||||
|
{
|
||||||
|
s_bShowedOutOfMemory = FALSE;
|
||||||
|
}
|
||||||
|
else if (!s_bShowedOutOfMemory)
|
||||||
|
{
|
||||||
|
ShowOutOfMemory();
|
||||||
|
s_bShowedOutOfMemory = TRUE;
|
||||||
|
imageModel.ClearHistory(); // Reduce memory usage
|
||||||
|
}
|
||||||
|
|
||||||
EndPaint(&ps);
|
EndPaint(&ps);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,12 +57,11 @@ public:
|
||||||
protected:
|
protected:
|
||||||
HITTEST m_hitCanvasSizeBox;
|
HITTEST m_hitCanvasSizeBox;
|
||||||
POINT m_ptOrig; // The origin of drag start
|
POINT m_ptOrig; // The origin of drag start
|
||||||
HBITMAP m_ahbmCached[2]; // The cached buffer bitmaps
|
|
||||||
CRect m_rcResizing; // Resizing rectagle
|
CRect m_rcResizing; // Resizing rectagle
|
||||||
|
|
||||||
HITTEST CanvasHitTest(POINT pt);
|
HITTEST CanvasHitTest(POINT pt);
|
||||||
RECT GetBaseRect();
|
RECT GetBaseRect();
|
||||||
VOID DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint);
|
BOOL DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint);
|
||||||
VOID OnHVScroll(WPARAM wParam, INT fnBar);
|
VOID OnHVScroll(WPARAM wParam, INT fnBar);
|
||||||
|
|
||||||
LRESULT OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
LRESULT OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||||
|
|
|
@ -230,6 +230,7 @@ HBITMAP InitializeImage(LPCWSTR name, LPWIN32_FIND_DATAW pFound, BOOL isFile)
|
||||||
if (hBitmap == NULL)
|
if (hBitmap == NULL)
|
||||||
{
|
{
|
||||||
ShowOutOfMemory();
|
ShowOutOfMemory();
|
||||||
|
imageModel.ClearHistory();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,7 @@ void ImageModel::PushImageForUndo()
|
||||||
if (hbm == NULL)
|
if (hbm == NULL)
|
||||||
{
|
{
|
||||||
ShowOutOfMemory();
|
ShowOutOfMemory();
|
||||||
|
ClearHistory();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +144,7 @@ void ImageModel::PushImageForUndo(HBITMAP hbm)
|
||||||
if (hbm == NULL)
|
if (hbm == NULL)
|
||||||
{
|
{
|
||||||
ShowOutOfMemory();
|
ShowOutOfMemory();
|
||||||
|
ClearHistory();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,6 +203,7 @@ void ImageModel::Crop(int nWidth, int nHeight, int nOffsetX, int nOffsetY)
|
||||||
if (!hbmNew)
|
if (!hbmNew)
|
||||||
{
|
{
|
||||||
ShowOutOfMemory();
|
ShowOutOfMemory();
|
||||||
|
ClearHistory();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -957,9 +957,14 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
|
||||||
HBITMAP hbmCopy = selectionModel.GetSelectionContents();
|
HBITMAP hbmCopy = selectionModel.GetSelectionContents();
|
||||||
HGLOBAL hGlobal = BitmapToClipboardDIB(hbmCopy);
|
HGLOBAL hGlobal = BitmapToClipboardDIB(hbmCopy);
|
||||||
if (hGlobal)
|
if (hGlobal)
|
||||||
|
{
|
||||||
::SetClipboardData(CF_DIB, hGlobal);
|
::SetClipboardData(CF_DIB, hGlobal);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
ShowOutOfMemory();
|
ShowOutOfMemory();
|
||||||
|
imageModel.ClearHistory();
|
||||||
|
}
|
||||||
::DeleteObject(hbmCopy);
|
::DeleteObject(hbmCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1093,6 +1098,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
|
||||||
if (!hbmSelection)
|
if (!hbmSelection)
|
||||||
{
|
{
|
||||||
ShowOutOfMemory();
|
ShowOutOfMemory();
|
||||||
|
imageModel.ClearHistory();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SaveDIBToFile(hbmSelection, szFileName, FALSE);
|
SaveDIBToFile(hbmSelection, szFileName, FALSE);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue