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