Bug 1019063 - Check for ::CreateDCW failing when printing. r=dvander a=rkent THUNDERBIRD_38_VERBRANCH
authorMilan Sreckovic <milan@mozilla.com>
Fri, 29 Apr 2016 12:57:12 -0700
branchTHUNDERBIRD_38_VERBRANCH
changeset 261027 c20c9e43efa67c82431e04773180d07e6c06e910
parent 261026 9e4409a087db1451830d17fda812356801086948
child 261028 02840486a7a9e3580819ce0028efe0945967c258
push id321
push userkent@caspia.com
push dateFri, 29 Apr 2016 21:03:17 +0000
treeherdermozilla-esr38@8cc8fa60f0f6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander, rkent
bugs1019063
milestone38.8.0esrpre
Bug 1019063 - Check for ::CreateDCW failing when printing. r=dvander a=rkent
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
@@ -3150,16 +3150,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
@@ -2499,16 +2499,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
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "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
@@ -945,29 +946,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 "prlog.h"
 #ifdef PR_LOGGING 
 PRLogModuleInfo * kWidgetPrintingLogMod = PR_NewLogModule("printing-widget");
 #define PR_PL(_p1)  PR_LOG(kWidgetPrintingLogMod, PR_LOG_DEBUG, _p1)
 #else
 #define PR_PL(_p1)
 #endif
 
@@ -280,16 +282,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;
@@ -299,19 +305,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;
   }