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