Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/thebes/PrintTarget.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 "PrintTarget.h"
7
8
#include "cairo.h"
9
#ifdef CAIRO_HAS_QUARTZ_SURFACE
10
#include "cairo-quartz.h"
11
#endif
12
#ifdef CAIRO_HAS_WIN32_SURFACE
13
#include "cairo-win32.h"
14
#endif
15
#include "mozilla/gfx/2D.h"
16
#include "mozilla/gfx/HelpersCairo.h"
17
#include "mozilla/gfx/Logging.h"
18
#include "nsReadableUtils.h"
19
#include "nsString.h"
20
#include "nsUTF8Utils.h"
21
22
// IPP spec disallow the job-name which is over 255 characters.
23
// RFC: https://tools.ietf.org/html/rfc2911#section-4.1.2
24
0
#define IPP_JOB_NAME_LIMIT_LENGTH 255
25
26
namespace mozilla {
27
namespace gfx {
28
29
PrintTarget::PrintTarget(cairo_surface_t* aCairoSurface, const IntSize& aSize)
30
  : mCairoSurface(aCairoSurface)
31
  , mSize(aSize)
32
  , mIsFinished(false)
33
#ifdef DEBUG
34
  , mHasActivePage(false)
35
#endif
36
37
0
{
38
#if 0
39
  // aCairoSurface is null when our PrintTargetThebes subclass's ctor calls us.
40
  // Once PrintTargetThebes is removed, enable this assertion.
41
  MOZ_ASSERT(aCairoSurface && !cairo_surface_status(aCairoSurface),
42
             "CreateOrNull factory methods should not call us without a "
43
             "valid cairo_surface_t*");
44
#endif
45
46
0
  // CreateOrNull factory methods hand over ownership of aCairoSurface,
47
0
  // so we don't call cairo_surface_reference(aSurface) here.
48
0
49
0
  // This code was copied from gfxASurface::Init:
50
0
#ifdef MOZ_TREE_CAIRO
51
0
  if (mCairoSurface &&
52
0
      cairo_surface_get_content(mCairoSurface) != CAIRO_CONTENT_COLOR) {
53
0
    cairo_surface_set_subpixel_antialiasing(mCairoSurface,
54
0
                                            CAIRO_SUBPIXEL_ANTIALIASING_DISABLED);
55
0
  }
56
0
#endif
57
0
}
58
59
PrintTarget::~PrintTarget()
60
0
{
61
0
  // null surfaces are allowed here
62
0
  cairo_surface_destroy(mCairoSurface);
63
0
  mCairoSurface = nullptr;
64
0
}
65
66
already_AddRefed<DrawTarget>
67
PrintTarget::MakeDrawTarget(const IntSize& aSize,
68
                            DrawEventRecorder* aRecorder)
69
0
{
70
0
  MOZ_ASSERT(mCairoSurface,
71
0
             "We shouldn't have been constructed without a cairo surface");
72
0
73
0
  // This should not be called outside of BeginPage()/EndPage() calls since
74
0
  // some backends can only provide a valid DrawTarget at that time.
75
0
  MOZ_ASSERT(mHasActivePage, "We can't guarantee a valid DrawTarget");
76
0
77
0
  if (cairo_surface_status(mCairoSurface)) {
78
0
    return nullptr;
79
0
  }
80
0
81
0
  // Note than aSize may not be the same as mSize (the size of mCairoSurface).
82
0
  // See the comments in our header.  If the sizes are different a clip will
83
0
  // be applied to mCairoSurface.
84
0
  RefPtr<DrawTarget> dt =
85
0
    Factory::CreateDrawTargetForCairoSurface(mCairoSurface, aSize);
86
0
  if (!dt || !dt->IsValid()) {
87
0
    return nullptr;
88
0
  }
89
0
90
0
  if (aRecorder) {
91
0
    dt = CreateWrapAndRecordDrawTarget(aRecorder, dt);
92
0
    if (!dt || !dt->IsValid()) {
93
0
      return nullptr;
94
0
    }
95
0
  }
96
0
97
0
  return dt.forget();
98
0
}
99
100
already_AddRefed<DrawTarget>
101
PrintTarget::GetReferenceDrawTarget()
102
0
{
103
0
  if (!mRefDT) {
104
0
    const IntSize size(1, 1);
105
0
106
0
    cairo_surface_t* similar;
107
0
    switch (cairo_surface_get_type(mCairoSurface)) {
108
#ifdef CAIRO_HAS_WIN32_SURFACE
109
    case CAIRO_SURFACE_TYPE_WIN32:
110
      similar = cairo_win32_surface_create_with_dib(
111
        CairoContentToCairoFormat(cairo_surface_get_content(mCairoSurface)),
112
        size.width, size.height);
113
      break;
114
#endif
115
#ifdef CAIRO_HAS_QUARTZ_SURFACE
116
    case CAIRO_SURFACE_TYPE_QUARTZ:
117
      similar = cairo_quartz_surface_create_cg_layer(
118
                  mCairoSurface, cairo_surface_get_content(mCairoSurface),
119
                  size.width, size.height);
120
      break;
121
#endif
122
0
    default:
123
0
      similar = cairo_surface_create_similar(
124
0
                  mCairoSurface, cairo_surface_get_content(mCairoSurface),
125
0
                  size.width, size.height);
126
0
      break;
127
0
    }
128
0
129
0
    if (cairo_surface_status(similar)) {
130
0
      return nullptr;
131
0
    }
132
0
133
0
    RefPtr<DrawTarget> dt =
134
0
      Factory::CreateDrawTargetForCairoSurface(similar, size);
135
0
136
0
    // The DT addrefs the surface, so we need drop our own reference to it:
137
0
    cairo_surface_destroy(similar);
138
0
139
0
    if (!dt || !dt->IsValid()) {
140
0
      return nullptr;
141
0
    }
142
0
    mRefDT = dt.forget();
143
0
  }
144
0
145
0
  return do_AddRef(mRefDT);
146
0
}
147
148
/* static */
149
void
150
PrintTarget::AdjustPrintJobNameForIPP(const nsAString& aJobName,
151
                                      nsCString& aAdjustedJobName)
152
0
{
153
0
  CopyUTF16toUTF8(aJobName, aAdjustedJobName);
154
0
155
0
  if (aAdjustedJobName.Length() > IPP_JOB_NAME_LIMIT_LENGTH) {
156
0
    uint32_t length =
157
0
      RewindToPriorUTF8Codepoint(aAdjustedJobName.get(),
158
0
                                 (IPP_JOB_NAME_LIMIT_LENGTH - 3U));
159
0
    aAdjustedJobName.SetLength(length);
160
0
    aAdjustedJobName.AppendLiteral("...");
161
0
  }
162
0
}
163
164
/* static */
165
void
166
PrintTarget::AdjustPrintJobNameForIPP(const nsAString& aJobName,
167
                                      nsString& aAdjustedJobName)
168
0
{
169
0
  nsAutoCString jobName;
170
0
  AdjustPrintJobNameForIPP(aJobName, jobName);
171
0
172
0
  CopyUTF8toUTF16(jobName, aAdjustedJobName);
173
0
}
174
175
/* static */ already_AddRefed<DrawTarget>
176
PrintTarget::CreateWrapAndRecordDrawTarget(DrawEventRecorder* aRecorder,
177
                                       DrawTarget* aDrawTarget)
178
0
{
179
0
  MOZ_ASSERT(aRecorder);
180
0
  MOZ_ASSERT(aDrawTarget);
181
0
182
0
  RefPtr<DrawTarget> dt;
183
0
184
0
  if (aRecorder) {
185
0
    // It doesn't really matter what we pass as the DrawTarget here.
186
0
    dt = gfx::Factory::CreateWrapAndRecordDrawTarget(aRecorder, aDrawTarget);
187
0
  }
188
0
189
0
  if (!dt || !dt->IsValid()) {
190
0
    gfxCriticalNote
191
0
      << "Failed to create a recording DrawTarget for PrintTarget";
192
0
    return nullptr;
193
0
  }
194
0
195
0
  return dt.forget();
196
0
}
197
198
void
199
PrintTarget::Finish()
200
0
{
201
0
  if (mIsFinished) {
202
0
    return;
203
0
  }
204
0
  mIsFinished = true;
205
0
206
0
  // null surfaces are allowed here
207
0
  cairo_surface_finish(mCairoSurface);
208
0
}
209
210
void
211
PrintTarget::RegisterPageDoneCallback(PageDoneCallback&& aCallback)
212
0
{
213
0
  MOZ_ASSERT(aCallback && !IsSyncPagePrinting());
214
0
  mPageDoneCallback = std::move(aCallback);
215
0
}
216
217
void
218
PrintTarget::UnregisterPageDoneCallback()
219
0
{
220
0
  mPageDoneCallback = nullptr;
221
0
}
222
223
} // namespace gfx
224
} // namespace mozilla