Coverage Report

Created: 2018-09-25 14:53

/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