nsDeviceContextSpecProxy.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /* -*- Mode: C++; tab-width: 8; 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. #include "nsDeviceContextSpecProxy.h"
  6. #include "gfxASurface.h"
  7. #include "gfxPlatform.h"
  8. #include "mozilla/gfx/DrawEventRecorder.h"
  9. #include "mozilla/gfx/PrintTargetThebes.h"
  10. #include "mozilla/layout/RemotePrintJobChild.h"
  11. #include "mozilla/RefPtr.h"
  12. #include "mozilla/Unused.h"
  13. #include "nsComponentManagerUtils.h"
  14. #include "nsAppDirectoryServiceDefs.h"
  15. #include "nsDirectoryServiceUtils.h"
  16. #include "nsIPrintSession.h"
  17. #include "nsIPrintSettings.h"
  18. #include "nsIUUIDGenerator.h"
  19. using mozilla::Unused;
  20. using namespace mozilla;
  21. using namespace mozilla::gfx;
  22. NS_IMPL_ISUPPORTS(nsDeviceContextSpecProxy, nsIDeviceContextSpec)
  23. NS_IMETHODIMP
  24. nsDeviceContextSpecProxy::Init(nsIWidget* aWidget,
  25. nsIPrintSettings* aPrintSettings,
  26. bool aIsPrintPreview)
  27. {
  28. nsresult rv;
  29. mRealDeviceContextSpec =
  30. do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv);
  31. if (NS_WARN_IF(NS_FAILED(rv))) {
  32. return rv;
  33. }
  34. mRealDeviceContextSpec->Init(nullptr, aPrintSettings, aIsPrintPreview);
  35. if (NS_WARN_IF(NS_FAILED(rv))) {
  36. mRealDeviceContextSpec = nullptr;
  37. return rv;
  38. }
  39. mPrintSettings = aPrintSettings;
  40. if (aIsPrintPreview) {
  41. return NS_OK;
  42. }
  43. // nsIPrintSettings only has a weak reference to nsIPrintSession, so we hold
  44. // it to make sure it's available for the lifetime of the print.
  45. rv = mPrintSettings->GetPrintSession(getter_AddRefs(mPrintSession));
  46. if (NS_FAILED(rv) || !mPrintSession) {
  47. NS_WARNING("We can't print via the parent without an nsIPrintSession.");
  48. return NS_ERROR_FAILURE;
  49. }
  50. rv = mPrintSession->GetRemotePrintJob(getter_AddRefs(mRemotePrintJob));
  51. if (NS_FAILED(rv) || !mRemotePrintJob) {
  52. NS_WARNING("We can't print via the parent without a RemotePrintJobChild.");
  53. return NS_ERROR_FAILURE;
  54. }
  55. rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
  56. getter_AddRefs(mRecordingDir));
  57. if (NS_WARN_IF(NS_FAILED(rv))) {
  58. return rv;
  59. }
  60. mUuidGenerator = do_GetService("@mozilla.org/uuid-generator;1", &rv);
  61. if (NS_WARN_IF(NS_FAILED(rv))) {
  62. return rv;
  63. }
  64. return NS_OK;
  65. }
  66. already_AddRefed<PrintTarget>
  67. nsDeviceContextSpecProxy::MakePrintTarget()
  68. {
  69. MOZ_ASSERT(mRealDeviceContextSpec);
  70. double width, height;
  71. nsresult rv = mPrintSettings->GetEffectivePageSize(&width, &height);
  72. if (NS_WARN_IF(NS_FAILED(rv)) || width <= 0 || height <= 0) {
  73. return nullptr;
  74. }
  75. // convert twips to points
  76. width /= TWIPS_PER_POINT_FLOAT;
  77. height /= TWIPS_PER_POINT_FLOAT;
  78. RefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->
  79. CreateOffscreenSurface(mozilla::gfx::IntSize::Truncate(width, height),
  80. mozilla::gfx::SurfaceFormat::A8R8G8B8_UINT32);
  81. if (!surface) {
  82. return nullptr;
  83. }
  84. // The type of PrintTarget that we return here shouldn't really matter since
  85. // our implementation of GetDrawEventRecorder returns an object, which means
  86. // the DrawTarget returned by the PrintTarget will be a DrawTargetRecording.
  87. // The recording will be serialized and sent over to the parent process where
  88. // PrintTranslator::TranslateRecording will call MakePrintTarget (indirectly
  89. // via PrintTranslator::CreateDrawTarget) on whatever type of
  90. // nsIDeviceContextSpecProxy is created for the platform that we are running
  91. // on. It is that DrawTarget that the recording will be replayed on to
  92. // print.
  93. // XXX(jwatt): The above isn't quite true. We do want to use a
  94. // PrintTargetRecording here, but we can't until bug 1280324 is figured out
  95. // and fixed otherwise we will cause bug 1280181 to happen again.
  96. RefPtr<PrintTarget> target = PrintTargetThebes::CreateOrNull(surface);
  97. return target.forget();
  98. }
  99. NS_IMETHODIMP
  100. nsDeviceContextSpecProxy::GetDrawEventRecorder(mozilla::gfx::DrawEventRecorder** aDrawEventRecorder)
  101. {
  102. MOZ_ASSERT(aDrawEventRecorder);
  103. RefPtr<mozilla::gfx::DrawEventRecorder> result = mRecorder;
  104. result.forget(aDrawEventRecorder);
  105. return NS_OK;
  106. }
  107. float
  108. nsDeviceContextSpecProxy::GetDPI()
  109. {
  110. MOZ_ASSERT(mRealDeviceContextSpec);
  111. return mRealDeviceContextSpec->GetDPI();
  112. }
  113. float
  114. nsDeviceContextSpecProxy::GetPrintingScale()
  115. {
  116. MOZ_ASSERT(mRealDeviceContextSpec);
  117. return mRealDeviceContextSpec->GetPrintingScale();
  118. }
  119. nsresult
  120. nsDeviceContextSpecProxy::CreateUniqueTempPath(nsACString& aFilePath)
  121. {
  122. MOZ_ASSERT(mRecordingDir);
  123. MOZ_ASSERT(mUuidGenerator);
  124. nsID uuid;
  125. nsresult rv = mUuidGenerator->GenerateUUIDInPlace(&uuid);
  126. if (NS_WARN_IF(NS_FAILED(rv))) {
  127. return rv;
  128. }
  129. char uuidChars[NSID_LENGTH];
  130. uuid.ToProvidedString(uuidChars);
  131. mRecordingFileName.AssignASCII(uuidChars);
  132. nsCOMPtr<nsIFile> recordingFile;
  133. rv = mRecordingDir->Clone(getter_AddRefs(recordingFile));
  134. if (NS_WARN_IF(NS_FAILED(rv))) {
  135. return rv;
  136. }
  137. rv = recordingFile->AppendNative(mRecordingFileName);
  138. if (NS_WARN_IF(NS_FAILED(rv))) {
  139. return rv;
  140. }
  141. return recordingFile->GetNativePath(aFilePath);
  142. }
  143. NS_IMETHODIMP
  144. nsDeviceContextSpecProxy::BeginDocument(const nsAString& aTitle,
  145. const nsAString& aPrintToFileName,
  146. int32_t aStartPage, int32_t aEndPage)
  147. {
  148. nsAutoCString recordingPath;
  149. nsresult rv = CreateUniqueTempPath(recordingPath);
  150. if (NS_FAILED(rv)) {
  151. return rv;
  152. }
  153. mRecorder = new mozilla::gfx::DrawEventRecorderFile(recordingPath.get());
  154. return mRemotePrintJob->InitializePrint(nsString(aTitle),
  155. nsString(aPrintToFileName),
  156. aStartPage, aEndPage);
  157. }
  158. NS_IMETHODIMP
  159. nsDeviceContextSpecProxy::EndDocument()
  160. {
  161. Unused << mRemotePrintJob->SendFinalizePrint();
  162. return NS_OK;
  163. }
  164. NS_IMETHODIMP
  165. nsDeviceContextSpecProxy::AbortDocument()
  166. {
  167. Unused << mRemotePrintJob->SendAbortPrint(NS_OK);
  168. return NS_OK;
  169. }
  170. NS_IMETHODIMP
  171. nsDeviceContextSpecProxy::BeginPage()
  172. {
  173. // Reopen the file, if necessary, ready for the next page.
  174. if (!mRecorder->IsOpen()) {
  175. nsAutoCString recordingPath;
  176. nsresult rv = CreateUniqueTempPath(recordingPath);
  177. if (NS_FAILED(rv)) {
  178. return rv;
  179. }
  180. mRecorder->OpenNew(recordingPath.get());
  181. }
  182. return NS_OK;
  183. }
  184. NS_IMETHODIMP
  185. nsDeviceContextSpecProxy::EndPage()
  186. {
  187. // Send the page recording to the parent.
  188. mRecorder->Close();
  189. mRemotePrintJob->ProcessPage(mRecordingFileName);
  190. return NS_OK;
  191. }