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 "PrintTargetPS.h"
7 :
8 : #include "cairo.h"
9 : #include "cairo-ps.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 : PrintTargetPS::PrintTargetPS(cairo_surface_t* aCairoSurface,
30 : const IntSize& aSize,
31 : nsIOutputStream *aStream,
32 0 : PageOrientation aOrientation)
33 : : PrintTarget(aCairoSurface, aSize)
34 : , mStream(aStream)
35 0 : , mOrientation(aOrientation)
36 : {
37 0 : }
38 :
39 0 : PrintTargetPS::~PrintTargetPS()
40 : {
41 : // We get called first, then PrintTarget's dtor. That means that mStream
42 : // is destroyed before PrintTarget's dtor calls cairo_surface_destroy. This
43 : // can be a problem if Finish() hasn't been called on us, since
44 : // cairo_surface_destroy will then call cairo_surface_finish and that will
45 : // end up invoking write_func above with the by now dangling pointer mStream
46 : // that mCairoSurface stored. To prevent that from happening we must call
47 : // Flush here before mStream is deleted.
48 0 : Finish();
49 0 : }
50 :
51 : /* static */ already_AddRefed<PrintTargetPS>
52 0 : PrintTargetPS::CreateOrNull(nsIOutputStream *aStream,
53 : IntSize aSizeInPoints,
54 : PageOrientation aOrientation)
55 : {
56 : // The PS output does not specify the page size so to print landscape we need
57 : // to rotate the drawing 90 degrees and print on portrait paper. If printing
58 : // landscape, swap the width/height supplied to cairo to select a portrait
59 : // print area. Our consumers are responsible for checking
60 : // RotateForLandscape() and applying a rotation transform if true.
61 0 : if (aOrientation == LANDSCAPE) {
62 0 : Swap(aSizeInPoints.width, aSizeInPoints.height);
63 : }
64 :
65 : cairo_surface_t* surface =
66 0 : cairo_ps_surface_create_for_stream(write_func, (void*)aStream,
67 0 : aSizeInPoints.width,
68 0 : aSizeInPoints.height);
69 0 : if (cairo_surface_status(surface)) {
70 0 : return nullptr;
71 : }
72 0 : cairo_ps_surface_restrict_to_level(surface, CAIRO_PS_LEVEL_2);
73 :
74 : // The new object takes ownership of our surface reference.
75 : RefPtr<PrintTargetPS> target = new PrintTargetPS(surface, aSizeInPoints,
76 0 : aStream, aOrientation);
77 0 : return target.forget();
78 : }
79 :
80 : nsresult
81 0 : PrintTargetPS::BeginPrinting(const nsAString& aTitle,
82 : const nsAString& aPrintToFileName,
83 : int32_t aStartPage,
84 : int32_t aEndPage)
85 : {
86 0 : if (mOrientation == PORTRAIT) {
87 0 : cairo_ps_surface_dsc_comment(mCairoSurface, "%%Orientation: Portrait");
88 : } else {
89 0 : cairo_ps_surface_dsc_comment(mCairoSurface, "%%Orientation: Landscape");
90 : }
91 0 : return NS_OK;
92 : }
93 :
94 : nsresult
95 0 : PrintTargetPS::EndPage()
96 : {
97 0 : cairo_surface_show_page(mCairoSurface);
98 0 : return NS_OK;
99 : }
100 :
101 : void
102 0 : PrintTargetPS::Finish()
103 : {
104 0 : if (mIsFinished) {
105 0 : return; // We don't want to call Close() on mStream more than once
106 : }
107 0 : PrintTarget::Finish();
108 0 : mStream->Close();
109 : }
110 :
111 : } // namespace gfx
112 : } // namespace mozilla
|