Bug 1019063 - Check for ::CreateDCW failing when printing. r=dvander
authorMilan Sreckovic <milan@mozilla.com>
Thu, 18 Jun 2015 08:18:00 +0200
changeset 282096 f57fc897b7bb154a6ac2f56698702fded7a2ac1e
parent 282095 403078fbf2e2d06917878355cf4276238deb0453
child 282097 a20ac0cedc1bfc09b82148d35eccf68022b3c1f1
push id897
push userjlund@mozilla.com
push dateMon, 14 Sep 2015 18:56:12 +0000
treeherdermozilla-release@9411e2d2b214 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs1019063
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1019063 - Check for ::CreateDCW failing when printing. r=dvander
gfx/src/nsDeviceContext.cpp
gfx/src/nsDeviceContext.h
gfx/thebes/gfxASurface.cpp
gfx/thebes/gfxWindowsSurface.cpp
layout/base/nsPresShell.cpp
layout/printing/nsPrintEngine.cpp
widget/nsPrintSettingsImpl.cpp
widget/windows/nsDeviceContextSpecWin.cpp
--- a/gfx/src/nsDeviceContext.cpp
+++ b/gfx/src/nsDeviceContext.cpp
@@ -30,16 +30,17 @@
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
 #include "nsIWidget.h"                  // for nsIWidget, NS_NATIVE_WINDOW
 #include "nsRect.h"                     // for nsRect
 #include "nsServiceManagerUtils.h"      // for do_GetService
 #include "nsString.h"               // for nsDependentString
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl
 #include "nsThreadUtils.h"              // for NS_IsMainThread
+#include "mozilla/gfx/Logging.h"
 
 #if !XP_MACOSX
 #include "gfxPDFSurface.h"
 #endif
 
 #ifdef MOZ_WIDGET_GTK
 #include "gfxPSSurface.h"
 #elif XP_WIN
@@ -388,16 +389,18 @@ nsDeviceContext::Init(nsIWidget *aWidget
     mScreenManager = do_GetService("@mozilla.org/gfx/screenmanager;1", &rv);
 
     return rv;
 }
 
 already_AddRefed<gfxContext>
 nsDeviceContext::CreateRenderingContext()
 {
+    MOZ_ASSERT(mWidth > 0 && mHeight > 0);
+
     nsRefPtr<gfxASurface> printingSurface = mPrintingSurface;
 #ifdef XP_MACOSX
     // CreateRenderingContext() can be called (on reflow) after EndPage()
     // but before BeginPage().  On OS X (and only there) mPrintingSurface
     // will in this case be null, because OS X printing surfaces are
     // per-page, and therefore only truly valid between calls to BeginPage()
     // and EndPage().  But we can get away with fudging things here, if need
     // be, by using a cached copy.
@@ -405,16 +408,21 @@ nsDeviceContext::CreateRenderingContext(
       printingSurface = mCachedPrintingSurface;
     }
 #endif
 
     RefPtr<gfx::DrawTarget> dt =
       gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(printingSurface,
                                                              gfx::IntSize(mWidth, mHeight));
 
+    if (!dt) {
+        gfxCriticalError() << "Failed to create draw target in device context sized " << mWidth << "x" << mHeight << " and pointers " << hexa(mPrintingSurface) << " and " << hexa(printingSurface);
+        MOZ_CRASH("Cannot CreateDrawTargetForSurface");
+    }
+
 #ifdef XP_MACOSX
     dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr);
 #endif
     dt->AddUserData(&sDisablePixelSnapping, (void*)0x1, nullptr);
 
     nsRefPtr<gfxContext> pContext = new gfxContext(dt);
     pContext->SetMatrix(gfxMatrix::Scaling(mPrintingScale, mPrintingScale));
     return pContext.forget();
@@ -489,17 +497,19 @@ nsDeviceContext::InitForPrinting(nsIDevi
     mDeviceContextSpec = aDevice;
 
     nsresult rv = aDevice->GetSurfaceForPrinter(getter_AddRefs(mPrintingSurface));
     if (NS_FAILED(rv))
         return NS_ERROR_FAILURE;
 
     Init(nullptr);
 
-    CalcPrintingSize();
+    if (!CalcPrintingSize()) {
+        return NS_ERROR_FAILURE;
+    }
 
     return NS_OK;
 }
 
 nsresult
 nsDeviceContext::BeginDocument(const nsAString& aTitle,
                                char16_t*       aPrintToFileName,
                                int32_t          aStartPage,
@@ -657,21 +667,22 @@ nsDeviceContext::FindScreen(nsIScreen** 
         mScreenManager->ScreenForNativeWidget(mWidget->GetNativeData(NS_NATIVE_WINDOW),
                                               outScreen);
     }
     else {
         mScreenManager->GetPrimaryScreen(outScreen);
     }
 }
 
-void
+bool
 nsDeviceContext::CalcPrintingSize()
 {
-    if (!mPrintingSurface)
-        return;
+    if (!mPrintingSurface) {
+        return (mWidth > 0 && mHeight > 0);
+    }
 
     bool inPoints = true;
 
     gfxSize size(0, 0);
     switch (mPrintingSurface->GetType()) {
     case gfxSurfaceType::Image:
         inPoints = false;
         size = reinterpret_cast<gfxImageSurface*>(mPrintingSurface.get())->GetSize();
@@ -711,28 +722,31 @@ nsDeviceContext::CalcPrintingSize()
             mDepth = (uint32_t)::GetDeviceCaps(dc, BITSPIXEL);
             if (dc != reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC())
                 ReleaseDC((HWND)mWidget->GetNativeData(NS_NATIVE_WIDGET), dc);
             break;
         }
 #endif
 
     default:
+        gfxCriticalError() << "Printing to unknown surface type " << (int)mPrintingSurface->GetType();
         NS_ERROR("trying to print to unknown surface type");
     }
 
     if (inPoints) {
         // For printing, CSS inches and physical inches are identical
         // so it doesn't matter which we use here
         mWidth = NSToCoordRound(float(size.width) * AppUnitsPerPhysicalInch() / 72);
         mHeight = NSToCoordRound(float(size.height) * AppUnitsPerPhysicalInch() / 72);
     } else {
         mWidth = NSToIntRound(size.width);
         mHeight = NSToIntRound(size.height);
     }
+
+    return (mWidth > 0 && mHeight > 0);
 }
 
 bool nsDeviceContext::CheckDPIChange() {
     int32_t oldDevPixels = mAppUnitsPerDevPixelAtUnitFullZoom;
     int32_t oldInches = mAppUnitsPerPhysicalInch;
 
     SetDPI();
 
--- a/gfx/src/nsDeviceContext.h
+++ b/gfx/src/nsDeviceContext.h
@@ -254,17 +254,19 @@ public:
 private:
     // Private destructor, to discourage deletion outside of Release():
     ~nsDeviceContext();
 
     void SetDPI();
     void ComputeClientRectUsingScreen(nsRect *outRect);
     void ComputeFullAreaUsingScreen(nsRect *outRect);
     void FindScreen(nsIScreen **outScreen);
-    void CalcPrintingSize();
+
+    // Return false if the surface is not right
+    bool CalcPrintingSize();
     void UpdateAppUnitsForFullZoom();
 
     nscoord  mWidth;
     nscoord  mHeight;
     uint32_t mDepth;
     int32_t  mAppUnitsPerDevPixel;
     int32_t  mAppUnitsPerDevPixelAtUnitFullZoom;
     int32_t  mAppUnitsPerPhysicalInch;
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -7,16 +7,17 @@
 #include "nsMemory.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Base64.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsISupportsImpl.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Logging.h"
 #include "gfx2DGlue.h"
 
 #include "gfxASurface.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "gfxPlatform.h"
 #include "gfxRect.h"
 
@@ -212,16 +213,19 @@ gfxASurface::Wrap (cairo_surface_t *csur
 
 void
 gfxASurface::Init(cairo_surface_t* surface, bool existingSurface)
 {
     SetSurfaceWrapper(surface, this);
 
     mSurface = surface;
     mSurfaceValid = surface && !cairo_surface_status(surface);
+    if (!mSurfaceValid) {
+        gfxWarning() << "ASurface Init failed with Cairo status " << cairo_surface_status(surface) << " on " << hexa(surface);
+    }
 
     if (existingSurface || !mSurfaceValid) {
         mFloatingRefs = 0;
     } else {
         mFloatingRefs = 1;
 #ifdef MOZ_TREE_CAIRO
         if (cairo_surface_get_content(surface) != CAIRO_CONTENT_COLOR) {
             cairo_surface_set_subpixel_antialiasing(surface, CAIRO_SUBPIXEL_ANTIALIASING_DISABLED);
--- a/gfx/thebes/gfxWindowsSurface.cpp
+++ b/gfx/thebes/gfxWindowsSurface.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gfxWindowsSurface.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
+#include "mozilla/gfx/Logging.h"
 
 #include "cairo.h"
 #include "cairo-win32.h"
 
 #include "nsString.h"
 
 gfxWindowsSurface::gfxWindowsSurface(HWND wnd, uint32_t flags) :
     mOwnsDC(true), mForPrinting(false), mWnd(wnd)
@@ -24,16 +25,19 @@ gfxWindowsSurface::gfxWindowsSurface(HDC
 {
     if (flags & FLAG_TAKE_DC)
         mOwnsDC = true;
 
 #ifdef NS_PRINTING
     if (flags & FLAG_FOR_PRINTING) {
         Init(cairo_win32_printing_surface_create(mDC));
         mForPrinting = true;
+        if (!mSurfaceValid) {
+            gfxCriticalError(gfxCriticalError::DefaultOptions(false)) << "Invalid printing surface";
+        }
     } else
 #endif
     InitWithDC(flags);
 }
 
 gfxWindowsSurface::gfxWindowsSurface(IDirect3DSurface9 *surface, uint32_t flags) :
     mOwnsDC(false), mForPrinting(false), mDC(0), mWnd(nullptr)
 {
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -2874,16 +2874,17 @@ PresShell::ClearFrameRefs(nsIFrame* aFra
 already_AddRefed<gfxContext>
 PresShell::CreateReferenceRenderingContext()
 {
   nsDeviceContext* devCtx = mPresContext->DeviceContext();
   nsRefPtr<gfxContext> rc;
   if (mPresContext->IsScreen()) {
     rc = new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
   } else {
+    // We assume the devCtx has positive width and height for this call
     rc = devCtx->CreateRenderingContext();
   }
 
   MOZ_ASSERT(rc, "shouldn't break promise to return non-null");
   return rc.forget();
 }
 
 nsresult
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -2493,16 +2493,17 @@ nsPrintEngine::DoPrint(nsPrintObject * a
       GetDisplayTitleAndURL(aPO, docTitleStr, docURLStr, eDocTitleDefBlank);
 
       if (nsIPrintSettings::kRangeSelection == printRangeType) {
         CloneSelection(aPO->mDocument->GetOriginalDocument(), aPO->mDocument);
 
         poPresContext->SetIsRenderingOnlySelection(true);
         // temporarily creating rendering context
         // which is needed to find the selection frames
+        // mPrintDC must have positive width and height for this call
         nsRenderingContext rc(mPrt->mPrintDC->CreateRenderingContext());
 
         // find the starting and ending page numbers
         // via the selection
         nsIFrame* startFrame;
         nsIFrame* endFrame;
         int32_t   startPageNum;
         int32_t   endPageNum;
--- a/widget/nsPrintSettingsImpl.cpp
+++ b/widget/nsPrintSettingsImpl.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsPrintSettingsImpl.h"
 #include "nsReadableUtils.h"
 #include "nsIPrintSession.h"
 #include "nsRefPtr.h"
+#include "mozilla/gfx/Logging.h"
 
 #define DEFAULT_MARGIN_WIDTH 0.5
 
 NS_IMPL_ISUPPORTS(nsPrintSettings, nsIPrintSettings)
 
 /** ---------------------------------------------------
  *  See documentation in nsPrintSettingsImpl.h
  *	@update 6/21/00 dwc
@@ -859,29 +860,35 @@ NS_IMETHODIMP nsPrintSettings::GetPaperW
 {
   NS_ENSURE_ARG_POINTER(aPaperWidth);
   *aPaperWidth = mPaperWidth;
   return NS_OK;
 }
 NS_IMETHODIMP nsPrintSettings::SetPaperWidth(double aPaperWidth)
 {
   mPaperWidth = aPaperWidth;
+  if (mPaperWidth <= 0) {
+    gfxCriticalError(gfxCriticalError::DefaultOptions(false)) << "Setting paper width to bad value " << mPaperWidth;
+  }
   return NS_OK;
 }
 
 /* attribute double paperHeight; */
 NS_IMETHODIMP nsPrintSettings::GetPaperHeight(double *aPaperHeight)
 {
   NS_ENSURE_ARG_POINTER(aPaperHeight);
   *aPaperHeight = mPaperHeight;
   return NS_OK;
 }
 NS_IMETHODIMP nsPrintSettings::SetPaperHeight(double aPaperHeight)
 {
   mPaperHeight = aPaperHeight;
+  if (mPaperHeight <= 0) {
+    gfxCriticalError(gfxCriticalError::DefaultOptions(false)) << "Setting paper height to bad value " << mPaperHeight;
+  }
   return NS_OK;
 }
 
 /* attribute short PaperSizeUnit; */
 NS_IMETHODIMP nsPrintSettings::GetPaperSizeUnit(int16_t *aPaperSizeUnit)
 {
   NS_ENSURE_ARG_POINTER(aPaperSizeUnit);
   *aPaperSizeUnit = mPaperSizeUnit;
--- a/widget/windows/nsDeviceContextSpecWin.cpp
+++ b/widget/windows/nsDeviceContextSpecWin.cpp
@@ -36,16 +36,18 @@
 #include "nsNativeCharsetUtils.h"
 
 // File Picker
 #include "nsIFile.h"
 #include "nsIFilePicker.h"
 #include "nsIStringBundle.h"
 #define NS_ERROR_GFX_PRINTER_BUNDLE_URL "chrome://global/locale/printing.properties"
 
+#include "mozilla/gfx/Logging.h"
+
 #include "mozilla/Logging.h"
 PRLogModuleInfo * kWidgetPrintingLogMod = PR_NewLogModule("printing-widget");
 #define PR_PL(_p1)  MOZ_LOG(kWidgetPrintingLogMod, mozilla::LogLevel::Debug, _p1)
 
 using namespace mozilla;
 
 //----------------------------------------------------------------------------------
 // The printer data is shared between the PrinterEnumerator and the nsDeviceContextSpecWin
@@ -276,16 +278,20 @@ NS_IMETHODIMP nsDeviceContextSpecWin::Ge
   }
 
   if (outputFormat == nsIPrintSettings::kOutputFormatPDF) {
     nsXPIDLString filename;
     mPrintSettings->GetToFileName(getter_Copies(filename));
 
     double width, height;
     mPrintSettings->GetEffectivePageSize(&width, &height);
+    if (width <= 0 || height <= 0) {
+      return NS_ERROR_FAILURE;
+    }
+
     // convert twips to points
     width  /= TWIPS_PER_POINT_FLOAT;
     height /= TWIPS_PER_POINT_FLOAT;
 
     nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1");
     nsresult rv = file->InitWithPath(filename);
     if (NS_FAILED(rv))
       return rv;
@@ -295,19 +301,27 @@ NS_IMETHODIMP nsDeviceContextSpecWin::Ge
     if (NS_FAILED(rv))
       return rv;
 
     newSurface = new gfxPDFSurface(stream, gfxSize(width, height));
   } else {
     if (mDevMode) {
       NS_WARN_IF_FALSE(mDriverName, "No driver!");
       HDC dc = ::CreateDCW(mDriverName, mDeviceName, nullptr, mDevMode);
+      if (!dc) {
+        gfxCriticalError(gfxCriticalError::DefaultOptions(false)) << "Failed to create device context in GetSurfaceForPrinter";
+        return NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
+      }
 
       // have this surface take over ownership of this DC
       newSurface = new gfxWindowsSurface(dc, gfxWindowsSurface::FLAG_TAKE_DC | gfxWindowsSurface::FLAG_FOR_PRINTING);
+      if (newSurface->GetType() == (gfxSurfaceType)-1) {
+        gfxCriticalError() << "Invalid windows surface from " << gfx::hexa(dc);
+        newSurface = nullptr;
+      }
     }
   }
 
   if (newSurface) {
     *surface = newSurface;
     NS_ADDREF(*surface);
     return NS_OK;
   }