tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

PrintTargetWindows.cpp (6135B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "PrintTargetWindows.h"
      7 
      8 #include "cairo-win32.h"
      9 #include "mozilla/gfx/HelpersCairo.h"
     10 #include "mozilla/StaticPrefs_browser.h"
     11 #include "mozilla/WidgetUtils.h"
     12 #include "nsCoord.h"
     13 #include "nsIContentAnalysis.h"
     14 #include "nsIWidget.h"
     15 #include "nsIWindowMediator.h"
     16 #include "nsPIDOMWindow.h"
     17 #include "nsServiceManagerUtils.h"
     18 #include "nsString.h"
     19 
     20 namespace mozilla {
     21 namespace gfx {
     22 
     23 PrintTargetWindows::PrintTargetWindows(cairo_surface_t* aCairoSurface,
     24                                       const IntSize& aSize, HDC aDC)
     25    : PrintTarget(aCairoSurface, aSize), mDC(aDC) {
     26  // TODO: At least add basic memory reporting.
     27  // 4 * mSize.width * mSize.height + sizeof(PrintTargetWindows) ?
     28 }
     29 
     30 /* static */
     31 already_AddRefed<PrintTargetWindows> PrintTargetWindows::CreateOrNull(HDC aDC) {
     32  // Figure out the paper size, the actual surface size will be the printable
     33  // area which is likely smaller, but the size here is later used to create the
     34  // draw target where the full page size is needed.
     35  // Note: we only scale the printing using the LOGPIXELSY,
     36  // so we use that when calculating the surface width as well as the height.
     37  int32_t heightDPI = ::GetDeviceCaps(aDC, LOGPIXELSY);
     38  float width =
     39      (::GetDeviceCaps(aDC, PHYSICALWIDTH) * POINTS_PER_INCH_FLOAT) / heightDPI;
     40  float height =
     41      (::GetDeviceCaps(aDC, PHYSICALHEIGHT) * POINTS_PER_INCH_FLOAT) /
     42      heightDPI;
     43  IntSize size = IntSize::Truncate(width, height);
     44 
     45  if (!Factory::CheckSurfaceSize(size)) {
     46    return nullptr;
     47  }
     48 
     49  // TODO(emilio): Use SkPDF rather than cairo if possible? See bug 1503537 and
     50  // bug 2001909 for some EMF code which was supposed to deal with some of this.
     51  cairo_surface_t* surface = cairo_win32_printing_surface_create(aDC);
     52 
     53  if (cairo_surface_status(surface)) {
     54    return nullptr;
     55  }
     56 
     57  // The new object takes ownership of our surface reference.
     58  RefPtr<PrintTargetWindows> target =
     59      new PrintTargetWindows(surface, size, aDC);
     60 
     61  return target.forget();
     62 }
     63 
     64 LazyLogModule gPrintingLog("printing");
     65 
     66 nsresult PrintTargetWindows::BeginPrinting(const nsAString& aTitle,
     67                                           const nsAString& aPrintToFileName,
     68                                           int32_t aStartPage,
     69                                           int32_t aEndPage) {
     70  const uint32_t DOC_TITLE_LENGTH = MAX_PATH - 1;
     71 
     72  DOCINFOW docinfo;
     73 
     74  nsString titleStr(aTitle);
     75  if (titleStr.Length() > DOC_TITLE_LENGTH) {
     76    titleStr.SetLength(DOC_TITLE_LENGTH - 3);
     77    titleStr.AppendLiteral("...");
     78  }
     79 
     80  nsString docName(aPrintToFileName);
     81  docinfo.cbSize = sizeof(docinfo);
     82  docinfo.lpszDocName =
     83      titleStr.Length() > 0 ? titleStr.get() : L"Mozilla Document";
     84  docinfo.lpszOutput = docName.Length() > 0 ? docName.get() : nullptr;
     85  docinfo.lpszDatatype = nullptr;
     86  docinfo.fwType = 0;
     87 
     88  // If we just did content analysis on this print request, it may have popped
     89  // up a dialog, and this can prevent StartDocW() from working properly if the
     90  // printer wants to pop up a dialog window (to get a file name to save to, for
     91  // example). Setting the foreground window to any browser window seems to work
     92  // around this. See bug 1980225.
     93  if (nsIContentAnalysis::MightBeActive() &&
     94      StaticPrefs::browser_contentanalysis_print_set_foreground_window()) {
     95    nsCOMPtr<nsIWindowMediator> winMediator =
     96        do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
     97    if (winMediator) {
     98      nsCOMPtr<mozIDOMWindowProxy> domWindow;
     99      nsresult rv =
    100          winMediator->GetMostRecentBrowserWindow(getter_AddRefs(domWindow));
    101      if (NS_SUCCEEDED(rv) && domWindow) {
    102        nsPIDOMWindowOuter* win = nsPIDOMWindowOuter::From(domWindow);
    103        if (win) {
    104          nsCOMPtr<nsIWidget> widget =
    105              widget::WidgetUtils::DOMWindowToWidget(win);
    106          if (widget) {
    107            HWND hwnd =
    108                static_cast<HWND>(widget->GetNativeData(NS_NATIVE_WINDOW));
    109            BOOL foregroundReturn = ::SetForegroundWindow(hwnd);
    110            MOZ_LOG(gPrintingLog, mozilla::LogLevel::Debug,
    111                    ("Called SetForegroundWindow(), which returned %d",
    112                     foregroundReturn));
    113          }
    114        }
    115      }
    116    }
    117  }
    118  // If the user selected Microsoft Print to PDF or XPS Document Printer, then
    119  // the following StartDoc call will put up a dialog window to prompt the
    120  // user to provide the name and location of the file to be saved.  A zero or
    121  // negative return value indicates failure.  In that case we want to check
    122  // whether that is because the user hit Cancel, since we want to treat that
    123  // specially to avoid notifying the user that the print "failed" in that
    124  // case.
    125  // XXX We should perhaps introduce a new NS_ERROR_USER_CANCELLED errer.
    126  int result = ::StartDocW(mDC, &docinfo);
    127  if (result <= 0) {
    128    DWORD lastError = ::GetLastError();
    129    if (lastError == ERROR_CANCELLED) {
    130      return NS_ERROR_ABORT;
    131    }
    132    return NS_ERROR_FAILURE;
    133  }
    134  return NS_OK;
    135 }
    136 
    137 nsresult PrintTargetWindows::EndPrinting() {
    138  int result = ::EndDoc(mDC);
    139  return (result <= 0) ? NS_ERROR_FAILURE : NS_OK;
    140 }
    141 
    142 nsresult PrintTargetWindows::AbortPrinting() {
    143  PrintTarget::AbortPrinting();
    144  int result = ::AbortDoc(mDC);
    145  return (result <= 0) ? NS_ERROR_FAILURE : NS_OK;
    146 }
    147 
    148 nsresult PrintTargetWindows::BeginPage(const IntSize& aSizeInPoints) {
    149  MOZ_ALWAYS_SUCCEEDS(PrintTarget::BeginPage(aSizeInPoints));
    150  int result = ::StartPage(mDC);
    151  return (result <= 0) ? NS_ERROR_FAILURE : NS_OK;
    152 }
    153 
    154 nsresult PrintTargetWindows::EndPage() {
    155  cairo_surface_show_page(mCairoSurface);
    156  bool cairoFailure = cairo_surface_status(mCairoSurface);
    157  MOZ_ALWAYS_SUCCEEDS(PrintTarget::EndPage());
    158  int result = ::EndPage(mDC);
    159  return (result <= 0 || cairoFailure) ? NS_ERROR_FAILURE : NS_OK;
    160 }
    161 
    162 }  // namespace gfx
    163 }  // namespace mozilla