diff options
author | joshia@google.com <joshia@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-06 21:34:43 +0000 |
---|---|---|
committer | joshia@google.com <joshia@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-06 21:34:43 +0000 |
commit | e6da7c850491960c5fe7dcf737db19d49c00784d (patch) | |
tree | af3f904d9b36d1d0e465dede56aa97faa75993f6 | |
parent | a45efa0f820f622a3d2dbf8e42bea70cefbed2d6 (diff) | |
download | chromium_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.cc | 45 | ||||
-rw-r--r-- | base/gfx/platform_canvas_win.cc | 49 | ||||
-rw-r--r-- | base/gfx/platform_canvas_win.h | 17 | ||||
-rw-r--r-- | base/gfx/vector_canvas.cc | 9 | ||||
-rw-r--r-- | base/gfx/vector_canvas.h | 2 |
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, |