summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjoshia@google.com <joshia@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-06 21:34:43 +0000
committerjoshia@google.com <joshia@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-06 21:34:43 +0000
commite6da7c850491960c5fe7dcf737db19d49c00784d (patch)
treeaf3f904d9b36d1d0e465dede56aa97faa75993f6
parenta45efa0f820f622a3d2dbf8e42bea70cefbed2d6 (diff)
downloadchromium_src-e6da7c850491960c5fe7dcf737db19d49c00784d.zip
chromium_src-e6da7c850491960c5fe7dcf737db19d49c00784d.tar.gz
chromium_src-e6da7c850491960c5fe7dcf737db19d49c00784d.tar.bz2
Make canvas code a bit more resilient to crashes.
* Initialize PAINTSTRUCT to prevent crash if BeginPaint fails. * Sanitize width-height for empty bitmaps. * Return failure from initialize instead of crashing at that point. BUG=3795 Review URL: http://codereview.chromium.org/9459 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4914 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/gfx/bitmap_platform_device_win.cc45
-rw-r--r--base/gfx/platform_canvas_win.cc49
-rw-r--r--base/gfx/platform_canvas_win.h17
-rw-r--r--base/gfx/vector_canvas.cc9
-rw-r--r--base/gfx/vector_canvas.h2
5 files changed, 73 insertions, 49 deletions
diff --git a/base/gfx/bitmap_platform_device_win.cc b/base/gfx/bitmap_platform_device_win.cc
index 0df57c2..85597ae 100644
--- a/base/gfx/bitmap_platform_device_win.cc
+++ b/base/gfx/bitmap_platform_device_win.cc
@@ -6,7 +6,6 @@
#include "base/gfx/gdi_util.h"
#include "base/logging.h"
-#include "base/process_util.h"
#include "SkMatrix.h"
#include "SkRegion.h"
#include "SkUtils.h"
@@ -99,33 +98,6 @@ void FixupAlphaBeforeCompositing(uint32_t* pixel) {
*pixel |= 0xFF000000;
}
-// Crashes the process. This is called when a bitmap allocation fails, and this
-// function tries to determine why it might have failed, and crash on different
-// lines. This allows us to see in crash dumps the most likely reason for the
-// failure. It takes the size of the bitmap we were trying to allocate as its
-// arguments so we can check that as well.
-void CrashForBitmapAllocationFailure(int w, int h) {
- // The maximum number of GDI objects per process is 10K. If we're very close
- // to that, it's probably the problem.
- const int kLotsOfGDIObjs = 9990;
- CHECK(GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS) < kLotsOfGDIObjs);
-
- // If the bitmap is ginormous, then we probably can't allocate it.
- // We use 64M pixels = 256MB @ 4 bytes per pixel.
- const int64 kGinormousBitmapPxl = 64000000;
- CHECK(static_cast<int64>(w) * static_cast<int64>(h) < kGinormousBitmapPxl);
-
- // If we're using a crazy amount of virtual address space, then maybe there
- // isn't enough for our bitmap.
- const int64 kLotsOfMem = 1500000000; // 1.5GB.
- scoped_ptr<process_util::ProcessMetrics> process_metrics(
- process_util::ProcessMetrics::CreateProcessMetrics(GetCurrentProcess()));
- CHECK(process_metrics->GetPagefileUsage() < kLotsOfMem);
-
- // Everything else.
- CHECK(0);
-}
-
} // namespace
class BitmapPlatformDeviceWin::BitmapPlatformDeviceWinData
@@ -263,16 +235,16 @@ BitmapPlatformDeviceWin* BitmapPlatformDeviceWin::create(HDC screen_dc,
SkBitmap bitmap;
// CreateDIBSection appears to get unhappy if we create an empty bitmap, so
- // we just expand it here.
- if (width == 0)
+ // just create a minimal bitmap
+ if ((width == 0) || (height == 0)) {
width = 1;
- if (height == 0)
height = 1;
+ }
- BITMAPINFOHEADER hdr;
+ BITMAPINFOHEADER hdr = {0};
CreateBitmapHeader(width, height, &hdr);
- void* data;
+ void* data = NULL;
HBITMAP hbitmap = CreateDIBSection(screen_dc,
reinterpret_cast<BITMAPINFO*>(&hdr), 0,
&data,
@@ -282,8 +254,11 @@ BitmapPlatformDeviceWin* BitmapPlatformDeviceWin::create(HDC screen_dc,
// bitmap here. This will cause us to crash later because the data pointer is
// NULL. To make sure that we can assign blame for those crashes to this code,
// we deliberately crash here, even in release mode.
- if (!hbitmap)
- CrashForBitmapAllocationFailure(width, height);
+ if (!hbitmap) {
+ DWORD error = GetLastError();
+ LOG(ERROR) << "CreateDIBSection Failed. Error: " << error << "\n";
+ return NULL;
+ }
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
bitmap.setPixels(data);
diff --git a/base/gfx/platform_canvas_win.cc b/base/gfx/platform_canvas_win.cc
index b22a097..f2c69ac 100644
--- a/base/gfx/platform_canvas_win.cc
+++ b/base/gfx/platform_canvas_win.cc
@@ -6,6 +6,7 @@
#include "base/gfx/bitmap_platform_device_win.h"
#include "base/logging.h"
+#include "base/process_util.h"
#ifdef ARCH_CPU_64_BITS
#error This code does not work on x64. Please make sure all the base unit tests\
@@ -14,12 +15,42 @@
namespace gfx {
+// Crashes the process. This is called when a bitmap allocation fails, and this
+// function tries to determine why it might have failed, and crash on different
+// lines. This allows us to see in crash dumps the most likely reason for the
+// failure. It takes the size of the bitmap we were trying to allocate as its
+// arguments so we can check that as well.
+void CrashForBitmapAllocationFailure(int w, int h) {
+ // The maximum number of GDI objects per process is 10K. If we're very close
+ // to that, it's probably the problem.
+ const int kLotsOfGDIObjs = 9990;
+ CHECK(GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS) < kLotsOfGDIObjs);
+
+ // If the bitmap is ginormous, then we probably can't allocate it.
+ // We use 64M pixels = 256MB @ 4 bytes per pixel.
+ const int64 kGinormousBitmapPxl = 64000000;
+ CHECK(static_cast<int64>(w) * static_cast<int64>(h) < kGinormousBitmapPxl);
+
+ // If we're using a crazy amount of virtual address space, then maybe there
+ // isn't enough for our bitmap.
+ const int64 kLotsOfMem = 1500000000; // 1.5GB.
+ scoped_ptr<process_util::ProcessMetrics> process_metrics(
+ process_util::ProcessMetrics::CreateProcessMetrics(GetCurrentProcess()));
+ CHECK(process_metrics->GetPagefileUsage() < kLotsOfMem);
+
+ // Everything else.
+ CHECK(0);
+}
+
+
PlatformCanvasWin::PlatformCanvasWin() : SkCanvas() {
}
PlatformCanvasWin::PlatformCanvasWin(int width, int height, bool is_opaque)
: SkCanvas() {
- initialize(width, height, is_opaque, NULL);
+ bool initialized = initialize(width, height, is_opaque, NULL);
+ if (!initialized)
+ CrashForBitmapAllocationFailure(width, height);
}
PlatformCanvasWin::PlatformCanvasWin(int width,
@@ -27,20 +58,26 @@ PlatformCanvasWin::PlatformCanvasWin(int width,
bool is_opaque,
HANDLE shared_section)
: SkCanvas() {
- initialize(width, height, is_opaque, shared_section);
+ bool initialized = initialize(width, height, is_opaque, shared_section);
+ if (!initialized)
+ CrashForBitmapAllocationFailure(width, height);
}
PlatformCanvasWin::~PlatformCanvasWin() {
}
-void PlatformCanvasWin::initialize(int width,
- int height,
- bool is_opaque,
- HANDLE shared_section) {
+bool PlatformCanvasWin::initialize(int width,
+ int height,
+ bool is_opaque,
+ HANDLE shared_section) {
SkDevice* device =
createPlatformDevice(width, height, is_opaque, shared_section);
+ if (!device)
+ return false;
+
setDevice(device);
device->unref(); // was created with refcount 1, and setDevice also refs
+ return true;
}
HDC PlatformCanvasWin::beginPlatformPaint() {
diff --git a/base/gfx/platform_canvas_win.h b/base/gfx/platform_canvas_win.h
index 20f9276..b5f1e73 100644
--- a/base/gfx/platform_canvas_win.h
+++ b/base/gfx/platform_canvas_win.h
@@ -29,7 +29,7 @@ class PlatformCanvasWin : public SkCanvas {
virtual ~PlatformCanvasWin();
// For two-part init, call if you use the no-argument constructor above
- void initialize(int width, int height, bool is_opaque, HANDLE shared_section);
+ bool initialize(int width, int height, bool is_opaque, HANDLE shared_section);
// These calls should surround calls to platform drawing routines, the DC
// returned by beginPlatformPaint is the DC that can be used to draw into.
@@ -93,11 +93,14 @@ class PlatformCanvasWin : public SkCanvas {
template <class T>
class CanvasPaintT : public T {
public:
- CanvasPaintT(HWND hwnd) : hwnd_(hwnd), for_paint_(true) {
+ CanvasPaintT(HWND hwnd) : hwnd_(hwnd), paint_dc_(NULL), for_paint_(true) {
+ memset(&ps_, 0, sizeof(ps_));
initPaint(true);
}
- CanvasPaintT(HWND hwnd, bool opaque) : hwnd_(hwnd), for_paint_(true) {
+ CanvasPaintT(HWND hwnd, bool opaque) : hwnd_(hwnd), paint_dc_(NULL),
+ for_paint_(true) {
+ memset(&ps_, 0, sizeof(ps_));
initPaint(opaque);
}
@@ -163,8 +166,12 @@ class CanvasPaintT : public T {
// painting by one pixel so that the boundaries will be correct (ClearType
// text can depend on the adjacent pixel). Then we would paint just the
// inset pixels to the screen.
- initialize(ps_.rcPaint.right - ps_.rcPaint.left,
- ps_.rcPaint.bottom - ps_.rcPaint.top, opaque, NULL);
+ const int width = ps_.rcPaint.right - ps_.rcPaint.left;
+ const int height = ps_.rcPaint.bottom - ps_.rcPaint.top;
+ if (!initialize(width, height, opaque, NULL)) {
+ // Cause a deliberate crash;
+ *(char*) 0 = 0;
+ }
// This will bring the canvas into the screen coordinate system for the
// dirty rect
diff --git a/base/gfx/vector_canvas.cc b/base/gfx/vector_canvas.cc
index c9165eb..440ee64 100644
--- a/base/gfx/vector_canvas.cc
+++ b/base/gfx/vector_canvas.cc
@@ -13,16 +13,21 @@ VectorCanvas::VectorCanvas() {
}
VectorCanvas::VectorCanvas(HDC dc, int width, int height) {
- initialize(dc, width, height);
+ bool initialized = initialize(dc, width, height);
+ CHECK(initialized);
}
VectorCanvas::~VectorCanvas() {
}
-void VectorCanvas::initialize(HDC context, int width, int height) {
+bool VectorCanvas::initialize(HDC context, int width, int height) {
SkDevice* device = createPlatformDevice(width, height, true, context);
+ if (!device)
+ return false;
+
setDevice(device);
device->unref(); // was created with refcount 1, and setDevice also refs
+ return true;
}
SkBounder* VectorCanvas::setBounder(SkBounder* bounder) {
diff --git a/base/gfx/vector_canvas.h b/base/gfx/vector_canvas.h
index 3d8b97e..8538366 100644
--- a/base/gfx/vector_canvas.h
+++ b/base/gfx/vector_canvas.h
@@ -21,7 +21,7 @@ class VectorCanvas : public PlatformCanvasWin {
virtual ~VectorCanvas();
// For two-part init, call if you use the no-argument constructor above
- void initialize(HDC context, int width, int height);
+ bool initialize(HDC context, int width, int height);
virtual SkBounder* setBounder(SkBounder*);
virtual SkDevice* createDevice(SkBitmap::Config config,