Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/2d/DrawTargetTiled.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "DrawTargetTiled.h"
8
#include "Logging.h"
9
#include "PathHelpers.h"
10
11
using namespace std;
12
13
namespace mozilla {
14
namespace gfx {
15
16
DrawTargetTiled::DrawTargetTiled()
17
0
{
18
0
}
19
20
bool
21
DrawTargetTiled::Init(const TileSet& aTiles)
22
0
{
23
0
  if (!aTiles.mTileCount) {
24
0
    return false;
25
0
  }
26
0
27
0
  mTiles.reserve(aTiles.mTileCount);
28
0
  for (size_t i = 0; i < aTiles.mTileCount; ++i) {
29
0
    mTiles.push_back(TileInternal(aTiles.mTiles[i]));
30
0
    if (!aTiles.mTiles[i].mDrawTarget) {
31
0
      return false;
32
0
    }
33
0
    if (mTiles[0].mDrawTarget->GetFormat() != mTiles.back().mDrawTarget->GetFormat() ||
34
0
        mTiles[0].mDrawTarget->GetBackendType() != mTiles.back().mDrawTarget->GetBackendType()) {
35
0
      return false;
36
0
    }
37
0
    uint32_t newXMost = max(mRect.XMost(),
38
0
                            mTiles[i].mTileOrigin.x + mTiles[i].mDrawTarget->GetSize().width);
39
0
    uint32_t newYMost = max(mRect.YMost(),
40
0
                            mTiles[i].mTileOrigin.y + mTiles[i].mDrawTarget->GetSize().height);
41
0
    if (i == 0) {
42
0
      mRect.MoveTo(mTiles[0].mTileOrigin.x, mTiles[0].mTileOrigin.y);
43
0
    } else {
44
0
      mRect.MoveTo(min(mRect.X(), mTiles[i].mTileOrigin.x),
45
0
                   min(mRect.Y(), mTiles[i].mTileOrigin.y));
46
0
    }
47
0
    mRect.SetRightEdge(newXMost);
48
0
    mRect.SetBottomEdge(newYMost);
49
0
    mTiles[i].mDrawTarget->SetTransform(Matrix::Translation(-mTiles[i].mTileOrigin.x,
50
0
                                                            -mTiles[i].mTileOrigin.y));
51
0
  }
52
0
  mFormat = mTiles[0].mDrawTarget->GetFormat();
53
0
  SetPermitSubpixelAA(IsOpaque(mFormat));
54
0
  return true;
55
0
}
56
57
already_AddRefed<SourceSurface>
58
DrawTargetTiled::Snapshot()
59
0
{
60
0
  return MakeAndAddRef<SnapshotTiled>(mTiles, mRect);
61
0
}
62
63
void
64
DrawTargetTiled::DetachAllSnapshots()
65
0
{}
66
67
// Skip the mClippedOut check since this is only used for Flush() which
68
// should happen even if we're clipped.
69
#define TILED_COMMAND(command) \
70
  void \
71
  DrawTargetTiled::command() \
72
0
  { \
73
0
    for (size_t i = 0; i < mTiles.size(); i++) { \
74
0
      mTiles[i].mDrawTarget->command(); \
75
0
    } \
76
0
  }
77
#define TILED_COMMAND1(command, type1) \
78
  void \
79
  DrawTargetTiled::command(type1 arg1) \
80
0
  { \
81
0
    for (size_t i = 0; i < mTiles.size(); i++) { \
82
0
      if (!mTiles[i].mClippedOut) \
83
0
        mTiles[i].mDrawTarget->command(arg1); \
84
0
    } \
85
0
  }
86
#define TILED_COMMAND3(command, type1, type2, type3) \
87
  void \
88
  DrawTargetTiled::command(type1 arg1, type2 arg2, type3 arg3) \
89
0
  { \
90
0
    for (size_t i = 0; i < mTiles.size(); i++) { \
91
0
      if (!mTiles[i].mClippedOut) \
92
0
        mTiles[i].mDrawTarget->command(arg1, arg2, arg3); \
93
0
    } \
94
0
  }
95
#define TILED_COMMAND4(command, type1, type2, type3, type4) \
96
  void \
97
  DrawTargetTiled::command(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
98
0
  { \
99
0
    for (size_t i = 0; i < mTiles.size(); i++) { \
100
0
      if (!mTiles[i].mClippedOut) \
101
0
        mTiles[i].mDrawTarget->command(arg1, arg2, arg3, arg4); \
102
0
    } \
103
0
  }
Unexecuted instantiation: mozilla::gfx::DrawTargetTiled::DrawFilter(mozilla::gfx::FilterNode*, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, mozilla::gfx::PointTyped<mozilla::gfx::UnknownUnits, float> const&, mozilla::gfx::DrawOptions const&)
Unexecuted instantiation: mozilla::gfx::DrawTargetTiled::MaskSurface(mozilla::gfx::Pattern const&, mozilla::gfx::SourceSurface*, mozilla::gfx::PointTyped<mozilla::gfx::UnknownUnits, float>, mozilla::gfx::DrawOptions const&)
Unexecuted instantiation: mozilla::gfx::DrawTargetTiled::FillGlyphs(mozilla::gfx::ScaledFont*, mozilla::gfx::GlyphBuffer const&, mozilla::gfx::Pattern const&, mozilla::gfx::DrawOptions const&)
104
#define TILED_COMMAND5(command, type1, type2, type3, type4, type5) \
105
  void \
106
  DrawTargetTiled::command(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
107
  { \
108
    for (size_t i = 0; i < mTiles.size(); i++) { \
109
      if (!mTiles[i].mClippedOut) \
110
        mTiles[i].mDrawTarget->command(arg1, arg2, arg3, arg4, arg5); \
111
    } \
112
  }
113
114
TILED_COMMAND(Flush)
115
TILED_COMMAND4(DrawFilter, FilterNode*, const Rect&, const Point&, const DrawOptions&)
116
TILED_COMMAND1(ClearRect, const Rect&)
117
TILED_COMMAND4(MaskSurface, const Pattern&, SourceSurface*, Point, const DrawOptions&)
118
TILED_COMMAND4(FillGlyphs, ScaledFont*, const GlyphBuffer&, const Pattern&, const DrawOptions&)
119
TILED_COMMAND3(Mask, const Pattern&, const Pattern&, const DrawOptions&)
120
121
void
122
DrawTargetTiled::PushClip(const Path* aPath)
123
0
{
124
0
  if (!mClippedOutTilesStack.append(std::vector<bool>(mTiles.size()))) {
125
0
    MOZ_CRASH("out of memory");
126
0
  }
127
0
  std::vector<bool>& clippedTiles = mClippedOutTilesStack.back();
128
0
129
0
  Rect deviceRect = aPath->GetBounds(mTransform);
130
0
131
0
  for (size_t i = 0; i < mTiles.size(); i++) {
132
0
    if (!mTiles[i].mClippedOut) {
133
0
      if (deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
134
0
                                   mTiles[i].mTileOrigin.y,
135
0
                                   mTiles[i].mDrawTarget->GetSize().width,
136
0
                                   mTiles[i].mDrawTarget->GetSize().height))) {
137
0
        mTiles[i].mDrawTarget->PushClip(aPath);
138
0
      } else {
139
0
        mTiles[i].mClippedOut = true;
140
0
        clippedTiles[i] = true;
141
0
      }
142
0
    }
143
0
  }
144
0
}
145
146
void
147
DrawTargetTiled::PushClipRect(const Rect& aRect)
148
0
{
149
0
  if (!mClippedOutTilesStack.append(std::vector<bool>(mTiles.size()))) {
150
0
    MOZ_CRASH("out of memory");
151
0
  }
152
0
  std::vector<bool>& clippedTiles = mClippedOutTilesStack.back();
153
0
154
0
  Rect deviceRect = mTransform.TransformBounds(aRect);
155
0
156
0
  for (size_t i = 0; i < mTiles.size(); i++) {
157
0
    if (!mTiles[i].mClippedOut) {
158
0
      if (deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
159
0
                                   mTiles[i].mTileOrigin.y,
160
0
                                   mTiles[i].mDrawTarget->GetSize().width,
161
0
                                   mTiles[i].mDrawTarget->GetSize().height))) {
162
0
        mTiles[i].mDrawTarget->PushClipRect(aRect);
163
0
      } else {
164
0
        mTiles[i].mClippedOut = true;
165
0
        clippedTiles[i] = true;
166
0
      }
167
0
    }
168
0
  }
169
0
}
170
171
void
172
DrawTargetTiled::PopClip()
173
0
{
174
0
  std::vector<bool>& clippedTiles = mClippedOutTilesStack.back();
175
0
  MOZ_ASSERT(clippedTiles.size() == mTiles.size());
176
0
  for (size_t i = 0; i < mTiles.size(); i++) {
177
0
    if (!mTiles[i].mClippedOut) {
178
0
      mTiles[i].mDrawTarget->PopClip();
179
0
    } else if (clippedTiles[i]) {
180
0
      mTiles[i].mClippedOut = false;
181
0
    }
182
0
  }
183
0
184
0
  mClippedOutTilesStack.popBack();
185
0
}
186
187
void
188
DrawTargetTiled::CopySurface(SourceSurface *aSurface,
189
                             const IntRect &aSourceRect,
190
                             const IntPoint &aDestination)
191
0
{
192
0
  for (size_t i = 0; i < mTiles.size(); i++) {
193
0
    IntPoint tileOrigin = mTiles[i].mTileOrigin;
194
0
    IntSize tileSize = mTiles[i].mDrawTarget->GetSize();
195
0
    if (!IntRect(aDestination, aSourceRect.Size()).Intersects(IntRect(tileOrigin, tileSize))) {
196
0
      continue;
197
0
    }
198
0
    // CopySurface ignores the transform, account for that here.
199
0
    mTiles[i].mDrawTarget->CopySurface(aSurface, aSourceRect, aDestination - tileOrigin);
200
0
  }
201
0
}
202
203
void
204
DrawTargetTiled::SetTransform(const Matrix& aTransform)
205
0
{
206
0
  for (size_t i = 0; i < mTiles.size(); i++) {
207
0
    Matrix mat = aTransform;
208
0
    mat.PostTranslate(Float(-mTiles[i].mTileOrigin.x), Float(-mTiles[i].mTileOrigin.y));
209
0
    mTiles[i].mDrawTarget->SetTransform(mat);
210
0
  }
211
0
  DrawTarget::SetTransform(aTransform);
212
0
}
213
214
void
215
DrawTargetTiled::SetPermitSubpixelAA(bool aPermitSubpixelAA)
216
0
{
217
0
  DrawTarget::SetPermitSubpixelAA(aPermitSubpixelAA);
218
0
  for (size_t i = 0; i < mTiles.size(); i++) {
219
0
    mTiles[i].mDrawTarget->SetPermitSubpixelAA(aPermitSubpixelAA);
220
0
  }
221
0
}
222
223
void
224
DrawTargetTiled::DrawSurface(SourceSurface* aSurface, const Rect& aDest, const Rect& aSource, const DrawSurfaceOptions& aSurfaceOptions, const DrawOptions& aDrawOptions)
225
0
{
226
0
  Rect deviceRect = mTransform.TransformBounds(aDest);
227
0
  for (size_t i = 0; i < mTiles.size(); i++) {
228
0
    if (!mTiles[i].mClippedOut &&
229
0
        deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
230
0
                                   mTiles[i].mTileOrigin.y,
231
0
                                   mTiles[i].mDrawTarget->GetSize().width,
232
0
                                   mTiles[i].mDrawTarget->GetSize().height))) {
233
0
      mTiles[i].mDrawTarget->DrawSurface(aSurface, aDest, aSource, aSurfaceOptions, aDrawOptions);
234
0
    }
235
0
  }
236
0
}
237
238
void
239
DrawTargetTiled::FillRect(const Rect& aRect, const Pattern& aPattern, const DrawOptions& aDrawOptions)
240
0
{
241
0
  Rect deviceRect = mTransform.TransformBounds(aRect);
242
0
  for (size_t i = 0; i < mTiles.size(); i++) {
243
0
    if (!mTiles[i].mClippedOut &&
244
0
        deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
245
0
                                   mTiles[i].mTileOrigin.y,
246
0
                                   mTiles[i].mDrawTarget->GetSize().width,
247
0
                                   mTiles[i].mDrawTarget->GetSize().height))) {
248
0
      mTiles[i].mDrawTarget->FillRect(aRect, aPattern, aDrawOptions);
249
0
    }
250
0
  }
251
0
}
252
253
void
254
DrawTargetTiled::Stroke(const Path* aPath, const Pattern& aPattern, const StrokeOptions& aStrokeOptions, const DrawOptions& aDrawOptions)
255
0
{
256
0
  // Approximate the stroke extents, since Path::GetStrokeExtents can be slow
257
0
  Rect deviceRect = aPath->GetBounds(mTransform);
258
0
  deviceRect.Inflate(MaxStrokeExtents(aStrokeOptions, mTransform));
259
0
  for (size_t i = 0; i < mTiles.size(); i++) {
260
0
    if (!mTiles[i].mClippedOut &&
261
0
        deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
262
0
                                   mTiles[i].mTileOrigin.y,
263
0
                                   mTiles[i].mDrawTarget->GetSize().width,
264
0
                                   mTiles[i].mDrawTarget->GetSize().height))) {
265
0
      mTiles[i].mDrawTarget->Stroke(aPath, aPattern, aStrokeOptions, aDrawOptions);
266
0
    }
267
0
  }
268
0
}
269
270
void
271
DrawTargetTiled::StrokeRect(const Rect& aRect, const Pattern& aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions& aDrawOptions)
272
0
{
273
0
  Rect deviceRect = mTransform.TransformBounds(aRect);
274
0
  Margin strokeMargin = MaxStrokeExtents(aStrokeOptions, mTransform);
275
0
  Rect outerRect = deviceRect;
276
0
  outerRect.Inflate(strokeMargin);
277
0
  Rect innerRect;
278
0
  if (mTransform.IsRectilinear()) {
279
0
    // If rects are mapped to rects, we can compute the inner rect
280
0
    // of the stroked rect.
281
0
    innerRect = deviceRect;
282
0
    innerRect.Deflate(strokeMargin);
283
0
  }
284
0
  for (size_t i = 0; i < mTiles.size(); i++) {
285
0
    if (mTiles[i].mClippedOut) {
286
0
      continue;
287
0
    }
288
0
    Rect tileRect(mTiles[i].mTileOrigin.x,
289
0
                  mTiles[i].mTileOrigin.y,
290
0
                  mTiles[i].mDrawTarget->GetSize().width,
291
0
                  mTiles[i].mDrawTarget->GetSize().height);
292
0
    if (outerRect.Intersects(tileRect) && !innerRect.Contains(tileRect)) {
293
0
      mTiles[i].mDrawTarget->StrokeRect(aRect, aPattern, aStrokeOptions, aDrawOptions);
294
0
    }
295
0
  }
296
0
}
297
298
void
299
DrawTargetTiled::StrokeLine(const Point& aStart, const Point& aEnd, const Pattern& aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions& aDrawOptions)
300
0
{
301
0
  Rect lineBounds = Rect(aStart, Size()).UnionEdges(Rect(aEnd, Size()));
302
0
  Rect deviceRect = mTransform.TransformBounds(lineBounds);
303
0
  deviceRect.Inflate(MaxStrokeExtents(aStrokeOptions, mTransform));
304
0
  for (size_t i = 0; i < mTiles.size(); i++) {
305
0
    if (!mTiles[i].mClippedOut &&
306
0
        deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
307
0
                                   mTiles[i].mTileOrigin.y,
308
0
                                   mTiles[i].mDrawTarget->GetSize().width,
309
0
                                   mTiles[i].mDrawTarget->GetSize().height))) {
310
0
      mTiles[i].mDrawTarget->StrokeLine(aStart, aEnd, aPattern, aStrokeOptions, aDrawOptions);
311
0
    }
312
0
  }
313
0
}
314
315
void
316
DrawTargetTiled::Fill(const Path* aPath, const Pattern& aPattern, const DrawOptions& aDrawOptions)
317
0
{
318
0
  Rect deviceRect = aPath->GetBounds(mTransform);
319
0
  for (size_t i = 0; i < mTiles.size(); i++) {
320
0
    if (!mTiles[i].mClippedOut &&
321
0
        deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
322
0
                                   mTiles[i].mTileOrigin.y,
323
0
                                   mTiles[i].mDrawTarget->GetSize().width,
324
0
                                   mTiles[i].mDrawTarget->GetSize().height))) {
325
0
      mTiles[i].mDrawTarget->Fill(aPath, aPattern, aDrawOptions);
326
0
    }
327
0
  }
328
0
}
329
330
void
331
DrawTargetTiled::PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask,
332
                           const Matrix& aMaskTransform, const IntRect& aBounds,
333
                           bool aCopyBackground)
334
0
{
335
0
  // XXX - not sure this is what we want or whether we want to continue drawing to a larger
336
0
  // intermediate surface, that would require tweaking the code in here a little though.
337
0
  for (size_t i = 0; i < mTiles.size(); i++) {
338
0
    if (!mTiles[i].mClippedOut) {
339
0
      IntRect bounds = aBounds;
340
0
      bounds.MoveBy(-mTiles[i].mTileOrigin);
341
0
      mTiles[i].mDrawTarget->PushLayer(aOpaque, aOpacity, aMask, aMaskTransform, bounds, aCopyBackground);
342
0
    }
343
0
  }
344
0
345
0
  PushedLayer layer(GetPermitSubpixelAA());
346
0
  mPushedLayers.push_back(layer);
347
0
  SetPermitSubpixelAA(aOpaque);
348
0
}
349
350
void
351
DrawTargetTiled::PushLayerWithBlend(bool aOpaque, Float aOpacity,
352
                                    SourceSurface* aMask,
353
                                    const Matrix& aMaskTransform,
354
                                    const IntRect& aBounds,
355
                                    bool aCopyBackground,
356
                                    CompositionOp aOp)
357
0
{
358
0
  // XXX - not sure this is what we want or whether we want to continue drawing to a larger
359
0
  // intermediate surface, that would require tweaking the code in here a little though.
360
0
  for (size_t i = 0; i < mTiles.size(); i++) {
361
0
    if (!mTiles[i].mClippedOut) {
362
0
      IntRect bounds = aBounds;
363
0
      bounds.MoveBy(-mTiles[i].mTileOrigin);
364
0
      mTiles[i].mDrawTarget->PushLayerWithBlend(aOpaque, aOpacity, aMask, aMaskTransform, bounds, aCopyBackground, aOp);
365
0
    }
366
0
  }
367
0
368
0
  PushedLayer layer(GetPermitSubpixelAA());
369
0
  mPushedLayers.push_back(layer);
370
0
  SetPermitSubpixelAA(aOpaque);
371
0
}
372
373
void
374
DrawTargetTiled::PopLayer()
375
0
{
376
0
  // XXX - not sure this is what we want or whether we want to continue drawing to a larger
377
0
  // intermediate surface, that would require tweaking the code in here a little though.
378
0
  for (size_t i = 0; i < mTiles.size(); i++) {
379
0
    if (!mTiles[i].mClippedOut) {
380
0
      mTiles[i].mDrawTarget->PopLayer();
381
0
    }
382
0
  }
383
0
384
0
  MOZ_ASSERT(mPushedLayers.size());
385
0
  const PushedLayer& layer = mPushedLayers.back();
386
0
  SetPermitSubpixelAA(layer.mOldPermitSubpixelAA);
387
0
  mPushedLayers.pop_back();
388
0
}
389
390
void
391
DrawTargetTiled::PadEdges(const IntRegion& aRegion)
392
0
{
393
0
  for (size_t i = 0; i < mTiles.size(); i++) {
394
0
    if (mTiles[i].mClippedOut) {
395
0
      continue;
396
0
    }
397
0
398
0
    auto tileRect = RoundedOut(Rect(mTiles[i].mTileOrigin.x,
399
0
                                    mTiles[i].mTileOrigin.y,
400
0
                                    mTiles[i].mDrawTarget->GetSize().width,
401
0
                                    mTiles[i].mDrawTarget->GetSize().height));
402
0
403
0
    // We only need to pad edges on tiles that intersect the edge of the region
404
0
    if (aRegion.Intersects(tileRect) && !aRegion.Contains(tileRect)) {
405
0
      IntRegion padRegion = aRegion;
406
0
      padRegion.MoveBy(-mTiles[i].mTileOrigin);
407
0
      padRegion.AndWith(IntRect(0, 0, mTiles[i].mDrawTarget->GetSize().width, mTiles[i].mDrawTarget->GetSize().height));
408
0
      mTiles[i].mDrawTarget->PadEdges(padRegion);
409
0
    }
410
0
  }
411
0
}
412
413
} // namespace gfx
414
} // namespace mozilla