PrintTargetPDF.cpp 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  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 "PrintTargetPDF.h"
  6. #include "cairo.h"
  7. #include "cairo-pdf.h"
  8. namespace mozilla {
  9. namespace gfx {
  10. static cairo_status_t
  11. write_func(void *closure, const unsigned char *data, unsigned int length)
  12. {
  13. nsCOMPtr<nsIOutputStream> out = reinterpret_cast<nsIOutputStream*>(closure);
  14. do {
  15. uint32_t wrote = 0;
  16. if (NS_FAILED(out->Write((const char*)data, length, &wrote))) {
  17. break;
  18. }
  19. data += wrote; length -= wrote;
  20. } while (length > 0);
  21. NS_ASSERTION(length == 0, "not everything was written to the file");
  22. return CAIRO_STATUS_SUCCESS;
  23. }
  24. PrintTargetPDF::PrintTargetPDF(cairo_surface_t* aCairoSurface,
  25. const IntSize& aSize,
  26. nsIOutputStream *aStream)
  27. : PrintTarget(aCairoSurface, aSize)
  28. , mStream(aStream)
  29. {
  30. }
  31. PrintTargetPDF::~PrintTargetPDF()
  32. {
  33. // We get called first, then PrintTarget's dtor. That means that mStream
  34. // is destroyed before PrintTarget's dtor calls cairo_surface_destroy. This
  35. // can be a problem if Finish() hasn't been called on us, since
  36. // cairo_surface_destroy will then call cairo_surface_finish and that will
  37. // end up invoking write_func above with the by now dangling pointer mStream
  38. // that mCairoSurface stored. To prevent that from happening we must call
  39. // Flush here before mStream is deleted.
  40. Finish();
  41. }
  42. /* static */ already_AddRefed<PrintTargetPDF>
  43. PrintTargetPDF::CreateOrNull(nsIOutputStream *aStream,
  44. const IntSize& aSizeInPoints)
  45. {
  46. cairo_surface_t* surface =
  47. cairo_pdf_surface_create_for_stream(write_func, (void*)aStream,
  48. aSizeInPoints.width,
  49. aSizeInPoints.height);
  50. if (cairo_surface_status(surface)) {
  51. return nullptr;
  52. }
  53. // The new object takes ownership of our surface reference.
  54. RefPtr<PrintTargetPDF> target = new PrintTargetPDF(surface, aSizeInPoints,
  55. aStream);
  56. return target.forget();
  57. }
  58. nsresult
  59. PrintTargetPDF::EndPage()
  60. {
  61. cairo_surface_show_page(mCairoSurface);
  62. return NS_OK;
  63. }
  64. void
  65. PrintTargetPDF::Finish()
  66. {
  67. if (mIsFinished) {
  68. return; // We don't want to call Close() on mStream more than once
  69. }
  70. PrintTarget::Finish();
  71. mStream->Close();
  72. }
  73. } // namespace gfx
  74. } // namespace mozilla