/* 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 "nsPrintSettingsWin.h"

#include "nsCRT.h"
#include "nsDeviceContextSpecWin.h"
#include "nsPrintSettingsImpl.h"
#include "WinUtils.h"

using namespace mozilla;

// Using paper sizes from wingdi.h and the units given there, plus a little
// extra research for the ones it doesn't give. Looks like the list hasn't
// changed since Windows 2000, so should be fairly stable now.
const short kPaperSizeUnits[] = {
    nsIPrintSettings::kPaperSizeMillimeters,  // Not Used default to mm as
                                              // DEVMODE uses tenths of mm, just
                                              // in case
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_LETTER
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_LETTERSMALL
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_TABLOID
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_LEDGER
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_LEGAL
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_STATEMENT
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_EXECUTIVE
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A3
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A4
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A4SMALL
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A5
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_B4
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_B5
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_FOLIO
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_QUARTO
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_10X14
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_11X17
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_NOTE
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_ENV_9
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_ENV_10
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_ENV_11
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_ENV_12
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_ENV_14
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_CSHEET
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_DSHEET
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_ESHEET
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_ENV_DL
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_ENV_C5
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_ENV_C3
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_ENV_C4
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_ENV_C6
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_ENV_C65
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_ENV_B4
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_ENV_B5
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_ENV_B6
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_ENV_ITALY
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_ENV_MONARCH
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_ENV_PERSONAL
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_FANFOLD_US
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_FANFOLD_STD_GERMAN
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_FANFOLD_LGL_GERMAN
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_ISO_B4
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_JAPANESE_POSTCARD
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_9X11
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_10X11
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_15X11
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_ENV_INVITE
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_RESERVED_48
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_RESERVED_49
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_LETTER_EXTRA
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_LEGAL_EXTRA
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_TABLOID_EXTRA
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_A4_EXTRA
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_LETTER_TRANSVERSE
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A4_TRANSVERSE
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_LETTER_EXTRA_TRANSVERSE
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A_PLUS
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_B_PLUS
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_LETTER_PLUS
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A4_PLUS
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A5_TRANSVERSE
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_B5_TRANSVERSE
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A3_EXTRA
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A5_EXTRA
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_B5_EXTRA
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A2
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A3_TRANSVERSE
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A3_EXTRA_TRANSVERSE
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_DBL_JAPANESE_POSTCARD
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A6
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_JENV_KAKU2
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_JENV_KAKU3
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_JENV_CHOU3
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_JENV_CHOU4
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_LETTER_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A3_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A4_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A5_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_B4_JIS_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_B5_JIS_ROTATED
    nsIPrintSettings::
        kPaperSizeMillimeters,  // DMPAPER_JAPANESE_POSTCARD_ROTATED
    nsIPrintSettings::
        kPaperSizeMillimeters,  // DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_A6_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_JENV_KAKU2_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_JENV_KAKU3_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_JENV_CHOU3_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_JENV_CHOU4_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_B6_JIS
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_B6_JIS_ROTATED
    nsIPrintSettings::kPaperSizeInches,       // DMPAPER_12X11
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_JENV_YOU4
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_JENV_YOU4_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_P16K
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_P32K
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_P32KBIG
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_1
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_2
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_3
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_4
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_5
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_6
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_7
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_8
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_9
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_10
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_P16K_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_P32K_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_P32KBIG_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_1_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_2_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_3_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_4_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_5_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_6_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_7_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_8_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_9_ROTATED
    nsIPrintSettings::kPaperSizeMillimeters,  // DMPAPER_PENV_10_ROTATED
};

NS_IMPL_ISUPPORTS_INHERITED(nsPrintSettingsWin, nsPrintSettings,
                            nsIPrintSettingsWin)

/** ---------------------------------------------------
 *  See documentation in nsPrintSettingsWin.h
 *	@update
 */
nsPrintSettingsWin::nsPrintSettingsWin()
    : nsPrintSettings(),
      mDeviceName(nullptr),
      mDriverName(nullptr),
      mDevMode(nullptr) {}

/** ---------------------------------------------------
 *  See documentation in nsPrintSettingsWin.h
 *	@update
 */
nsPrintSettingsWin::nsPrintSettingsWin(const nsPrintSettingsWin& aPS)
    : mDevMode(nullptr) {
  *this = aPS;
}

/* static */
void nsPrintSettingsWin::PaperSizeUnitFromDmPaperSize(short aPaperSize,
                                                      int16_t& aPaperSizeUnit) {
  if (aPaperSize > 0 && aPaperSize < int32_t(std::size(kPaperSizeUnits))) {
    aPaperSizeUnit = kPaperSizeUnits[aPaperSize];
  }
}

void nsPrintSettingsWin::InitWithInitializer(
    const PrintSettingsInitializer& aSettings) {
  nsPrintSettings::InitWithInitializer(aSettings);

  if (aSettings.mDevmodeWStorage.Length() < sizeof(DEVMODEW)) {
    return;
  }

  auto* devmode =
      reinterpret_cast<const DEVMODEW*>(aSettings.mDevmodeWStorage.Elements());
  if (devmode->dmSize != sizeof(DEVMODEW) ||
      devmode->dmSize + devmode->dmDriverExtra >
          aSettings.mDevmodeWStorage.Length()) {
    return;
  }

  // SetDevMode copies the DEVMODE.
  SetDevMode(const_cast<DEVMODEW*>(devmode));

  if (mDevMode->dmFields & DM_SCALE) {
    // Since we do the scaling, grab the DEVMODE value and reset it back to 100.
    double scale = double(mDevMode->dmScale) / 100.0f;
    if (mScaling == 1.0 || scale != 1.0) {
      SetScaling(scale);
    }
    mDevMode->dmScale = 100;
  }
}

already_AddRefed<nsIPrintSettings> CreatePlatformPrintSettings(
    const PrintSettingsInitializer& aSettings) {
  RefPtr<nsPrintSettings> settings = aSettings.mPrintSettings.get();
  if (!settings) {
    settings = MakeRefPtr<nsPrintSettingsWin>();
  }
  settings->InitWithInitializer(aSettings);
  return settings.forget();
}

/** ---------------------------------------------------
 *  See documentation in nsPrintSettingsWin.h
 *	@update
 */
nsPrintSettingsWin::~nsPrintSettingsWin() {
  if (mDevMode) ::HeapFree(::GetProcessHeap(), 0, mDevMode);
}

NS_IMETHODIMP nsPrintSettingsWin::SetDeviceName(const nsAString& aDeviceName) {
  mDeviceName = aDeviceName;
  return NS_OK;
}
NS_IMETHODIMP nsPrintSettingsWin::GetDeviceName(nsAString& aDeviceName) {
  aDeviceName = mDeviceName;
  return NS_OK;
}

NS_IMETHODIMP nsPrintSettingsWin::SetDriverName(const nsAString& aDriverName) {
  mDriverName = aDriverName;
  return NS_OK;
}
NS_IMETHODIMP nsPrintSettingsWin::GetDriverName(nsAString& aDriverName) {
  aDriverName = mDriverName;
  return NS_OK;
}

void nsPrintSettingsWin::CopyDevMode(DEVMODEW* aInDevMode,
                                     DEVMODEW*& aOutDevMode) {
  aOutDevMode = nullptr;
  size_t size = aInDevMode->dmSize + aInDevMode->dmDriverExtra;
  aOutDevMode =
      (LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, size);
  if (aOutDevMode) {
    memcpy(aOutDevMode, aInDevMode, size);
  }
}

NS_IMETHODIMP nsPrintSettingsWin::GetDevMode(DEVMODEW** aDevMode) {
  NS_ENSURE_ARG_POINTER(aDevMode);

  if (mDevMode) {
    CopyDevMode(mDevMode, *aDevMode);
  } else {
    *aDevMode = nullptr;
  }
  return NS_OK;
}

NS_IMETHODIMP nsPrintSettingsWin::SetDevMode(DEVMODEW* aDevMode) {
  if (mDevMode) {
    ::HeapFree(::GetProcessHeap(), 0, mDevMode);
    mDevMode = nullptr;
  }

  if (aDevMode) {
    CopyDevMode(aDevMode, mDevMode);
  }
  return NS_OK;
}

void nsPrintSettingsWin::InitUnwriteableMargin(HDC aHdc) {
  mozilla::gfx::MarginDouble margin =
      mozilla::widget::WinUtils::GetUnwriteableMarginsForDeviceInInches(aHdc);

  mUnwriteableMargin.SizeTo(NS_INCHES_TO_INT_TWIPS(margin.top),
                            NS_INCHES_TO_INT_TWIPS(margin.right),
                            NS_INCHES_TO_INT_TWIPS(margin.bottom),
                            NS_INCHES_TO_INT_TWIPS(margin.left));
}

void nsPrintSettingsWin::CopyFromNative(HDC aHdc, DEVMODEW* aDevMode) {
  MOZ_ASSERT(aHdc);
  MOZ_ASSERT(aDevMode);

  mIsInitedFromPrinter = true;
  if (aDevMode->dmFields & DM_ORIENTATION) {
    const bool areSheetsOfPaperPortraitMode =
        (aDevMode->dmOrientation == DMORIENT_PORTRAIT);

    // If our Windows print settings say that we're producing portrait-mode
    // sheets of paper, then our page format must also be portrait-mode; unless
    // we've got a pages-per-sheet value with orthogonal pages/sheets, in which
    // case it's reversed.
    const bool arePagesPortraitMode =
        (areSheetsOfPaperPortraitMode != HasOrthogonalPagesPerSheet());

    // Record the orientation of the pages (determined above) in mOrientation:
    mOrientation = int32_t(arePagesPortraitMode ? kPortraitOrientation
                                                : kLandscapeOrientation);
  }

  if (aDevMode->dmFields & DM_COPIES) {
    mNumCopies = aDevMode->dmCopies;
  }

  if (aDevMode->dmFields & DM_DUPLEX) {
    switch (aDevMode->dmDuplex) {
      default:
        MOZ_FALLTHROUGH_ASSERT("bad value for dmDuplex field");
      case DMDUP_SIMPLEX:
        mDuplex = kDuplexNone;
        break;
      case DMDUP_VERTICAL:
        mDuplex = kDuplexFlipOnLongEdge;
        break;
      case DMDUP_HORIZONTAL:
        mDuplex = kDuplexFlipOnShortEdge;
        break;
    }
  }

  // Since we do the scaling, grab their value and reset back to 100.
  if (aDevMode->dmFields & DM_SCALE) {
    double scale = double(aDevMode->dmScale) / 100.0f;
    if (mScaling == 1.0 || scale != 1.0) {
      mScaling = scale;
    }
    aDevMode->dmScale = 100;
  }

  if (aDevMode->dmFields & DM_PAPERSIZE) {
    mPaperId.Truncate(0);
    mPaperId.AppendInt(aDevMode->dmPaperSize);
    // If it is not a paper size we know about, the unit will remain unchanged.
    PaperSizeUnitFromDmPaperSize(aDevMode->dmPaperSize, mPaperSizeUnit);
  }

  if (aDevMode->dmFields & DM_COLOR) {
    mPrintInColor = aDevMode->dmColor == DMCOLOR_COLOR;
  }

  InitUnwriteableMargin(aHdc);

  int pixelsPerInchY = ::GetDeviceCaps(aHdc, LOGPIXELSY);
  int physicalHeight = ::GetDeviceCaps(aHdc, PHYSICALHEIGHT);
  double physicalHeightInch = double(physicalHeight) / pixelsPerInchY;
  int pixelsPerInchX = ::GetDeviceCaps(aHdc, LOGPIXELSX);
  int physicalWidth = ::GetDeviceCaps(aHdc, PHYSICALWIDTH);
  double physicalWidthInch = double(physicalWidth) / pixelsPerInchX;

  // Get the paper size from the device context rather than the DEVMODE, because
  // it is always available.
  double paperHeightInch = mOrientation == kPortraitOrientation
                               ? physicalHeightInch
                               : physicalWidthInch;
  mPaperHeight = mPaperSizeUnit == kPaperSizeInches
                     ? paperHeightInch
                     : paperHeightInch * MM_PER_INCH_FLOAT;

  double paperWidthInch = mOrientation == kPortraitOrientation
                              ? physicalWidthInch
                              : physicalHeightInch;
  mPaperWidth = mPaperSizeUnit == kPaperSizeInches
                    ? paperWidthInch
                    : paperWidthInch * MM_PER_INCH_FLOAT;

  // Using LOGPIXELSY to match existing code for print scaling calculations.
  mResolution = pixelsPerInchY;
}

void nsPrintSettingsWin::CopyToNative(DEVMODEW* aDevMode) {
  MOZ_ASSERT(aDevMode);

  if (!mPaperId.IsEmpty()) {
    aDevMode->dmPaperSize = _wtoi((const wchar_t*)mPaperId.get());
    aDevMode->dmFields |= DM_PAPERSIZE;
  } else {
    aDevMode->dmPaperSize = 0;
    aDevMode->dmFields &= ~DM_PAPERSIZE;
  }

  aDevMode->dmFields |= DM_COLOR;
  aDevMode->dmColor = mPrintInColor ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME;

  // The length and width in DEVMODE are always in tenths of a millimeter.
  double tenthsOfAmmPerSizeUnit =
      mPaperSizeUnit == kPaperSizeInches ? MM_PER_INCH_FLOAT * 10.0 : 10.0;

  // Note: small page sizes can be required here for sticker, label and slide
  // printers etc. see bug 1271900.
  if (mPaperHeight > 0) {
    aDevMode->dmPaperLength = std::round(mPaperHeight * tenthsOfAmmPerSizeUnit);
    aDevMode->dmFields |= DM_PAPERLENGTH;
  } else {
    aDevMode->dmPaperLength = 0;
    aDevMode->dmFields &= ~DM_PAPERLENGTH;
  }

  if (mPaperWidth > 0) {
    aDevMode->dmPaperWidth = std::round(mPaperWidth * tenthsOfAmmPerSizeUnit);
    aDevMode->dmFields |= DM_PAPERWIDTH;
  } else {
    aDevMode->dmPaperWidth = 0;
    aDevMode->dmFields &= ~DM_PAPERWIDTH;
  }

  // Setup Orientation
  aDevMode->dmOrientation = GetSheetOrientation() == kPortraitOrientation
                                ? DMORIENT_PORTRAIT
                                : DMORIENT_LANDSCAPE;
  aDevMode->dmFields |= DM_ORIENTATION;

  // Setup Number of Copies
  aDevMode->dmCopies = mNumCopies;
  aDevMode->dmFields |= DM_COPIES;

  // Setup Simplex/Duplex mode
  switch (mDuplex) {
    case kDuplexNone:
      aDevMode->dmDuplex = DMDUP_SIMPLEX;
      aDevMode->dmFields |= DM_DUPLEX;
      break;
    case kDuplexFlipOnLongEdge:
      aDevMode->dmDuplex = DMDUP_VERTICAL;
      aDevMode->dmFields |= DM_DUPLEX;
      break;
    case kDuplexFlipOnShortEdge:
      aDevMode->dmDuplex = DMDUP_HORIZONTAL;
      aDevMode->dmFields |= DM_DUPLEX;
      break;
    default:
      MOZ_ASSERT_UNREACHABLE("bad value for duplex option");
      break;
  }
}

//-------------------------------------------
nsresult nsPrintSettingsWin::_Clone(nsIPrintSettings** _retval) {
  auto printSettings = MakeRefPtr<nsPrintSettingsWin>(*this);
  printSettings.forget(_retval);
  return NS_OK;
}

//-------------------------------------------
nsPrintSettingsWin& nsPrintSettingsWin::operator=(
    const nsPrintSettingsWin& rhs) {
  if (this == &rhs) {
    return *this;
  }

  ((nsPrintSettings&)*this) = rhs;

  // Use free because we used the native malloc to create the memory
  if (mDevMode) {
    ::HeapFree(::GetProcessHeap(), 0, mDevMode);
  }

  mDeviceName = rhs.mDeviceName;
  mDriverName = rhs.mDriverName;

  if (rhs.mDevMode) {
    CopyDevMode(rhs.mDevMode, mDevMode);
  } else {
    mDevMode = nullptr;
  }

  return *this;
}

//-------------------------------------------
nsresult nsPrintSettingsWin::_Assign(nsIPrintSettings* aPS) {
  nsPrintSettingsWin* psWin = static_cast<nsPrintSettingsWin*>(aPS);
  *this = *psWin;
  return NS_OK;
}
