Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/painting/DisplayItemClip.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 "DisplayItemClip.h"
8
9
#include "gfxContext.h"
10
#include "gfxUtils.h"
11
#include "mozilla/gfx/2D.h"
12
#include "mozilla/gfx/PathHelpers.h"
13
#include "mozilla/layers/StackingContextHelper.h"
14
#include "mozilla/webrender/WebRenderTypes.h"
15
#include "nsPresContext.h"
16
#include "nsCSSRendering.h"
17
#include "nsLayoutUtils.h"
18
#include "nsRegion.h"
19
20
using namespace mozilla::gfx;
21
22
namespace mozilla {
23
24
void
25
DisplayItemClip::SetTo(const nsRect& aRect)
26
0
{
27
0
  SetTo(aRect, nullptr);
28
0
}
29
30
void
31
DisplayItemClip::SetTo(const nsRect& aRect, const nscoord* aRadii)
32
0
{
33
0
  mHaveClipRect = true;
34
0
  mClipRect = aRect;
35
0
  if (aRadii) {
36
0
    mRoundedClipRects.SetLength(1);
37
0
    mRoundedClipRects[0].mRect = aRect;
38
0
    memcpy(mRoundedClipRects[0].mRadii, aRadii, sizeof(nscoord) * 8);
39
0
  } else {
40
0
    mRoundedClipRects.Clear();
41
0
  }
42
0
}
43
44
void
45
DisplayItemClip::SetTo(const nsRect& aRect,
46
                       const nsRect& aRoundedRect,
47
                       const nscoord* aRadii)
48
0
{
49
0
  mHaveClipRect = true;
50
0
  mClipRect = aRect;
51
0
  mRoundedClipRects.SetLength(1);
52
0
  mRoundedClipRects[0].mRect = aRoundedRect;
53
0
  memcpy(mRoundedClipRects[0].mRadii, aRadii, sizeof(nscoord) * 8);
54
0
}
55
56
bool
57
DisplayItemClip::MayIntersect(const nsRect& aRect) const
58
0
{
59
0
  if (!mHaveClipRect) {
60
0
    return !aRect.IsEmpty();
61
0
  }
62
0
  nsRect r = aRect.Intersect(mClipRect);
63
0
  if (r.IsEmpty()) {
64
0
    return false;
65
0
  }
66
0
  for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
67
0
    const RoundedRect& rr = mRoundedClipRects[i];
68
0
    if (!nsLayoutUtils::RoundedRectIntersectsRect(rr.mRect, rr.mRadii, r)) {
69
0
      return false;
70
0
    }
71
0
  }
72
0
  return true;
73
0
}
74
75
void
76
DisplayItemClip::IntersectWith(const DisplayItemClip& aOther)
77
0
{
78
0
  if (!aOther.mHaveClipRect) {
79
0
    return;
80
0
  }
81
0
  if (!mHaveClipRect) {
82
0
    *this = aOther;
83
0
    return;
84
0
  }
85
0
  if (!mClipRect.IntersectRect(mClipRect, aOther.mClipRect)) {
86
0
    mRoundedClipRects.Clear();
87
0
    return;
88
0
  }
89
0
  mRoundedClipRects.AppendElements(aOther.mRoundedClipRects);
90
0
}
91
92
void
93
DisplayItemClip::ApplyTo(gfxContext* aContext, int32_t A2D) const
94
0
{
95
0
  ApplyRectTo(aContext, A2D);
96
0
  ApplyRoundedRectClipsTo(aContext, A2D, 0, mRoundedClipRects.Length());
97
0
}
98
99
void
100
DisplayItemClip::ApplyRectTo(gfxContext* aContext, int32_t A2D) const
101
0
{
102
0
  aContext->NewPath();
103
0
  gfxRect clip = nsLayoutUtils::RectToGfxRect(mClipRect, A2D);
104
0
  aContext->Rectangle(clip, true);
105
0
  aContext->Clip();
106
0
}
107
108
void
109
DisplayItemClip::ApplyRoundedRectClipsTo(gfxContext* aContext,
110
                                         int32_t A2D,
111
                                         uint32_t aBegin,
112
                                         uint32_t aEnd) const
113
0
{
114
0
  DrawTarget& aDrawTarget = *aContext->GetDrawTarget();
115
0
116
0
  aEnd = std::min<uint32_t>(aEnd, mRoundedClipRects.Length());
117
0
118
0
  for (uint32_t i = aBegin; i < aEnd; ++i) {
119
0
    RefPtr<Path> roundedRect =
120
0
      MakeRoundedRectPath(aDrawTarget, A2D, mRoundedClipRects[i]);
121
0
    aContext->Clip(roundedRect);
122
0
  }
123
0
}
124
125
void
126
DisplayItemClip::FillIntersectionOfRoundedRectClips(
127
  gfxContext* aContext,
128
  const Color& aColor,
129
  int32_t aAppUnitsPerDevPixel) const
130
0
{
131
0
  DrawTarget& aDrawTarget = *aContext->GetDrawTarget();
132
0
133
0
  uint32_t end = mRoundedClipRects.Length();
134
0
  if (!end) {
135
0
    return;
136
0
  }
137
0
138
0
  // Push clips for any rects that come BEFORE the rect at |aEnd - 1|, if any:
139
0
  ApplyRoundedRectClipsTo(aContext, aAppUnitsPerDevPixel, 0, end - 1);
140
0
141
0
  // Now fill the rect at |aEnd - 1|:
142
0
  RefPtr<Path> roundedRect = MakeRoundedRectPath(
143
0
    aDrawTarget, aAppUnitsPerDevPixel, mRoundedClipRects[end - 1]);
144
0
  ColorPattern color(ToDeviceColor(aColor));
145
0
  aDrawTarget.Fill(roundedRect, color);
146
0
147
0
  // Finally, pop any clips that we may have pushed:
148
0
  for (uint32_t i = 0; i < end - 1; ++i) {
149
0
    aContext->PopClip();
150
0
  }
151
0
}
152
153
already_AddRefed<Path>
154
DisplayItemClip::MakeRoundedRectPath(DrawTarget& aDrawTarget,
155
                                     int32_t A2D,
156
                                     const RoundedRect& aRoundRect) const
157
0
{
158
0
  RectCornerRadii pixelRadii;
159
0
  nsCSSRendering::ComputePixelRadii(aRoundRect.mRadii, A2D, &pixelRadii);
160
0
161
0
  Rect rect = NSRectToSnappedRect(aRoundRect.mRect, A2D, aDrawTarget);
162
0
163
0
  return MakePathForRoundedRect(aDrawTarget, rect, pixelRadii);
164
0
}
165
166
nsRect
167
DisplayItemClip::ApproximateIntersectInward(const nsRect& aRect) const
168
0
{
169
0
  nsRect r = aRect;
170
0
  if (mHaveClipRect) {
171
0
    r.IntersectRect(r, mClipRect);
172
0
  }
173
0
  for (uint32_t i = 0, iEnd = mRoundedClipRects.Length(); i < iEnd; ++i) {
174
0
    const RoundedRect& rr = mRoundedClipRects[i];
175
0
    nsRegion rgn =
176
0
      nsLayoutUtils::RoundedRectIntersectRect(rr.mRect, rr.mRadii, r);
177
0
    r = rgn.GetLargestRectangle();
178
0
  }
179
0
  return r;
180
0
}
181
182
// Test if (aXPoint, aYPoint) is in the ellipse with center (aXCenter, aYCenter)
183
// and radii aXRadius, aYRadius.
184
static bool
185
IsInsideEllipse(nscoord aXRadius,
186
                nscoord aXCenter,
187
                nscoord aXPoint,
188
                nscoord aYRadius,
189
                nscoord aYCenter,
190
                nscoord aYPoint)
191
0
{
192
0
  float scaledX = float(aXPoint - aXCenter) / float(aXRadius);
193
0
  float scaledY = float(aYPoint - aYCenter) / float(aYRadius);
194
0
  return scaledX * scaledX + scaledY * scaledY < 1.0f;
195
0
}
196
197
bool
198
DisplayItemClip::IsRectClippedByRoundedCorner(const nsRect& aRect) const
199
0
{
200
0
  if (mRoundedClipRects.IsEmpty())
201
0
    return false;
202
0
203
0
  nsRect rect;
204
0
  rect.IntersectRect(aRect, NonRoundedIntersection());
205
0
  for (uint32_t i = 0, iEnd = mRoundedClipRects.Length(); i < iEnd; ++i) {
206
0
    const RoundedRect& rr = mRoundedClipRects[i];
207
0
    // top left
208
0
    if (rect.x < rr.mRect.x + rr.mRadii[eCornerTopLeftX] &&
209
0
        rect.y < rr.mRect.y + rr.mRadii[eCornerTopLeftY]) {
210
0
      if (!IsInsideEllipse(rr.mRadii[eCornerTopLeftX],
211
0
                           rr.mRect.x + rr.mRadii[eCornerTopLeftX],
212
0
                           rect.x,
213
0
                           rr.mRadii[eCornerTopLeftY],
214
0
                           rr.mRect.y + rr.mRadii[eCornerTopLeftY],
215
0
                           rect.y)) {
216
0
        return true;
217
0
      }
218
0
    }
219
0
    // top right
220
0
    if (rect.XMost() > rr.mRect.XMost() - rr.mRadii[eCornerTopRightX] &&
221
0
        rect.y < rr.mRect.y + rr.mRadii[eCornerTopRightY]) {
222
0
      if (!IsInsideEllipse(rr.mRadii[eCornerTopRightX],
223
0
                           rr.mRect.XMost() - rr.mRadii[eCornerTopRightX],
224
0
                           rect.XMost(),
225
0
                           rr.mRadii[eCornerTopRightY],
226
0
                           rr.mRect.y + rr.mRadii[eCornerTopRightY],
227
0
                           rect.y)) {
228
0
        return true;
229
0
      }
230
0
    }
231
0
    // bottom left
232
0
    if (rect.x < rr.mRect.x + rr.mRadii[eCornerBottomLeftX] &&
233
0
        rect.YMost() > rr.mRect.YMost() - rr.mRadii[eCornerBottomLeftY]) {
234
0
      if (!IsInsideEllipse(rr.mRadii[eCornerBottomLeftX],
235
0
                           rr.mRect.x + rr.mRadii[eCornerBottomLeftX],
236
0
                           rect.x,
237
0
                           rr.mRadii[eCornerBottomLeftY],
238
0
                           rr.mRect.YMost() - rr.mRadii[eCornerBottomLeftY],
239
0
                           rect.YMost())) {
240
0
        return true;
241
0
      }
242
0
    }
243
0
    // bottom right
244
0
    if (rect.XMost() > rr.mRect.XMost() - rr.mRadii[eCornerBottomRightX] &&
245
0
        rect.YMost() > rr.mRect.YMost() - rr.mRadii[eCornerBottomRightY]) {
246
0
      if (!IsInsideEllipse(rr.mRadii[eCornerBottomRightX],
247
0
                           rr.mRect.XMost() - rr.mRadii[eCornerBottomRightX],
248
0
                           rect.XMost(),
249
0
                           rr.mRadii[eCornerBottomRightY],
250
0
                           rr.mRect.YMost() - rr.mRadii[eCornerBottomRightY],
251
0
                           rect.YMost())) {
252
0
        return true;
253
0
      }
254
0
    }
255
0
  }
256
0
  return false;
257
0
}
258
259
nsRect
260
DisplayItemClip::NonRoundedIntersection() const
261
0
{
262
0
  NS_ASSERTION(mHaveClipRect, "Must have a clip rect!");
263
0
  nsRect result = mClipRect;
264
0
  for (uint32_t i = 0, iEnd = mRoundedClipRects.Length(); i < iEnd; ++i) {
265
0
    result.IntersectRect(result, mRoundedClipRects[i].mRect);
266
0
  }
267
0
  return result;
268
0
}
269
270
bool
271
DisplayItemClip::IsRectAffectedByClip(const nsRect& aRect) const
272
0
{
273
0
  if (mHaveClipRect && !mClipRect.Contains(aRect)) {
274
0
    return true;
275
0
  }
276
0
  for (uint32_t i = 0, iEnd = mRoundedClipRects.Length(); i < iEnd; ++i) {
277
0
    const RoundedRect& rr = mRoundedClipRects[i];
278
0
    nsRegion rgn =
279
0
      nsLayoutUtils::RoundedRectIntersectRect(rr.mRect, rr.mRadii, aRect);
280
0
    if (!rgn.Contains(aRect)) {
281
0
      return true;
282
0
    }
283
0
  }
284
0
  return false;
285
0
}
286
287
bool
288
DisplayItemClip::IsRectAffectedByClip(const nsIntRect& aRect,
289
                                      float aXScale,
290
                                      float aYScale,
291
                                      int32_t A2D) const
292
0
{
293
0
  if (mHaveClipRect) {
294
0
    nsIntRect pixelClipRect =
295
0
      mClipRect.ScaleToNearestPixels(aXScale, aYScale, A2D);
296
0
    if (!pixelClipRect.Contains(aRect)) {
297
0
      return true;
298
0
    }
299
0
  }
300
0
301
0
  // Rounded rect clipping only snaps to user-space pixels, not device space.
302
0
  nsIntRect unscaled = aRect;
303
0
  unscaled.Scale(1 / aXScale, 1 / aYScale);
304
0
305
0
  for (uint32_t i = 0, iEnd = mRoundedClipRects.Length(); i < iEnd; ++i) {
306
0
    const RoundedRect& rr = mRoundedClipRects[i];
307
0
308
0
    nsIntRect pixelRect = rr.mRect.ToNearestPixels(A2D);
309
0
310
0
    RectCornerRadii pixelRadii;
311
0
    nsCSSRendering::ComputePixelRadii(rr.mRadii, A2D, &pixelRadii);
312
0
313
0
    nsIntRegion rgn = nsLayoutUtils::RoundedRectIntersectIntRect(
314
0
      pixelRect, pixelRadii, unscaled);
315
0
    if (!rgn.Contains(unscaled)) {
316
0
      return true;
317
0
    }
318
0
  }
319
0
  return false;
320
0
}
321
322
nsRect
323
DisplayItemClip::ApplyNonRoundedIntersection(const nsRect& aRect) const
324
0
{
325
0
  if (!mHaveClipRect) {
326
0
    return aRect;
327
0
  }
328
0
329
0
  nsRect result = aRect.Intersect(mClipRect);
330
0
  for (uint32_t i = 0, iEnd = mRoundedClipRects.Length(); i < iEnd; ++i) {
331
0
    result = result.Intersect(mRoundedClipRects[i].mRect);
332
0
  }
333
0
  return result;
334
0
}
335
336
void
337
DisplayItemClip::RemoveRoundedCorners()
338
0
{
339
0
  if (mRoundedClipRects.IsEmpty())
340
0
    return;
341
0
342
0
  mClipRect = NonRoundedIntersection();
343
0
  mRoundedClipRects.Clear();
344
0
}
345
346
// Computes the difference between aR1 and aR2, limited to aBounds.
347
static void
348
AccumulateRectDifference(const nsRect& aR1,
349
                         const nsRect& aR2,
350
                         const nsRect& aBounds,
351
                         nsRegion* aOut)
352
0
{
353
0
  if (aR1.IsEqualInterior(aR2))
354
0
    return;
355
0
  nsRegion r;
356
0
  r.Xor(aR1, aR2);
357
0
  r.And(r, aBounds);
358
0
  aOut->Or(*aOut, r);
359
0
}
360
361
static void
362
AccumulateRoundedRectDifference(const DisplayItemClip::RoundedRect& aR1,
363
                                const DisplayItemClip::RoundedRect& aR2,
364
                                const nsRect& aBounds,
365
                                const nsRect& aOtherBounds,
366
                                nsRegion* aOut)
367
0
{
368
0
  const nsRect& rect1 = aR1.mRect;
369
0
  const nsRect& rect2 = aR2.mRect;
370
0
371
0
  // If the two rectangles are totally disjoint, just add them both - otherwise
372
0
  // we'd end up adding one big enclosing rect
373
0
  if (!rect1.Intersects(rect2) ||
374
0
      memcmp(aR1.mRadii, aR2.mRadii, sizeof(aR1.mRadii))) {
375
0
    aOut->Or(*aOut, rect1.Intersect(aBounds));
376
0
    aOut->Or(*aOut, rect2.Intersect(aOtherBounds));
377
0
    return;
378
0
  }
379
0
380
0
  nscoord lowestBottom = std::max(rect1.YMost(), rect2.YMost());
381
0
  nscoord highestTop = std::min(rect1.Y(), rect2.Y());
382
0
  nscoord maxRight = std::max(rect1.XMost(), rect2.XMost());
383
0
  nscoord minLeft = std::min(rect1.X(), rect2.X());
384
0
385
0
  // At this point, we know that the radii haven't changed, and that the bounds
386
0
  // are different in some way. To explain how this works, consider the case
387
0
  // where the rounded rect has just been translated along the X direction.
388
0
  // |          ______________________ _ _ _ _ _ _            |
389
0
  // |        /           /            \           \          |
390
0
  // |       |                          |                     |
391
0
  // |       |     aR1   |              |     aR2   |         |
392
0
  // |       |                          |                     |
393
0
  // |        \ __________\___________ / _ _ _ _ _ /          |
394
0
  // |                                                        |
395
0
  // The invalidation region will be as if we lopped off the left rounded part
396
0
  // of aR2, and the right rounded part of aR1, and XOR'd them:
397
0
  // |          ______________________ _ _ _ _ _ _            |
398
0
  // |       -/-----------/-          -\-----------\-         |
399
0
  // |       |--------------          --|------------         |
400
0
  // |       |-----aR1---|--          --|-----aR2---|         |
401
0
  // |       |--------------          --|------------         |
402
0
  // |       -\ __________\-__________-/ _ _ _ _ _ /-          |
403
0
  // |                                                        |
404
0
  // The logic below just implements this idea, but generalized to both the
405
0
  // X and Y dimensions. The "(...)Adjusted(...)" values represent the lopped
406
0
  // off sides.
407
0
  nscoord highestAdjustedBottom = std::min(
408
0
    rect1.YMost() - aR1.mRadii[eCornerBottomLeftY],
409
0
    std::min(rect1.YMost() - aR1.mRadii[eCornerBottomRightY],
410
0
             std::min(rect2.YMost() - aR2.mRadii[eCornerBottomLeftY],
411
0
                      rect2.YMost() - aR2.mRadii[eCornerBottomRightY])));
412
0
  nscoord lowestAdjustedTop =
413
0
    std::max(rect1.Y() + aR1.mRadii[eCornerTopLeftY],
414
0
             std::max(rect1.Y() + aR1.mRadii[eCornerTopRightY],
415
0
                      std::max(rect2.Y() + aR2.mRadii[eCornerTopLeftY],
416
0
                               rect2.Y() + aR2.mRadii[eCornerTopRightY])));
417
0
418
0
  nscoord minAdjustedRight = std::min(
419
0
    rect1.XMost() - aR1.mRadii[eCornerTopRightX],
420
0
    std::min(rect1.XMost() - aR1.mRadii[eCornerBottomRightX],
421
0
             std::min(rect2.XMost() - aR2.mRadii[eCornerTopRightX],
422
0
                      rect2.XMost() - aR2.mRadii[eCornerBottomRightX])));
423
0
  nscoord maxAdjustedLeft =
424
0
    std::max(rect1.X() + aR1.mRadii[eCornerTopLeftX],
425
0
             std::max(rect1.X() + aR1.mRadii[eCornerBottomLeftX],
426
0
                      std::max(rect2.X() + aR2.mRadii[eCornerTopLeftX],
427
0
                               rect2.X() + aR2.mRadii[eCornerBottomLeftX])));
428
0
429
0
  // We only want to add an invalidation rect if the bounds have changed. If we
430
0
  // always added all of the 4 rects below, we would always be invalidating a
431
0
  // border around the rects, even in cases where we just translated along the X
432
0
  // or Y axis.
433
0
  nsRegion r;
434
0
  // First, or with the Y delta rects, wide along the X axis
435
0
  if (rect1.Y() != rect2.Y()) {
436
0
    r.Or(r,
437
0
         nsRect(minLeft,
438
0
                highestTop,
439
0
                maxRight - minLeft,
440
0
                lowestAdjustedTop - highestTop));
441
0
  }
442
0
  if (rect1.YMost() != rect2.YMost()) {
443
0
    r.Or(r,
444
0
         nsRect(minLeft,
445
0
                highestAdjustedBottom,
446
0
                maxRight - minLeft,
447
0
                lowestBottom - highestAdjustedBottom));
448
0
  }
449
0
  // Then, or with the X delta rects, narrow along the Y axis
450
0
  if (rect1.X() != rect2.X()) {
451
0
    r.Or(r,
452
0
         nsRect(minLeft,
453
0
                lowestAdjustedTop,
454
0
                maxAdjustedLeft - minLeft,
455
0
                highestAdjustedBottom - lowestAdjustedTop));
456
0
  }
457
0
  if (rect1.XMost() != rect2.XMost()) {
458
0
    r.Or(r,
459
0
         nsRect(minAdjustedRight,
460
0
                lowestAdjustedTop,
461
0
                maxRight - minAdjustedRight,
462
0
                highestAdjustedBottom - lowestAdjustedTop));
463
0
  }
464
0
465
0
  r.And(r, aBounds.Union(aOtherBounds));
466
0
  aOut->Or(*aOut, r);
467
0
}
468
469
void
470
DisplayItemClip::AddOffsetAndComputeDifference(const nsPoint& aOffset,
471
                                               const nsRect& aBounds,
472
                                               const DisplayItemClip& aOther,
473
                                               const nsRect& aOtherBounds,
474
                                               nsRegion* aDifference)
475
0
{
476
0
  if (mHaveClipRect != aOther.mHaveClipRect ||
477
0
      mRoundedClipRects.Length() != aOther.mRoundedClipRects.Length()) {
478
0
    aDifference->Or(*aDifference, aBounds);
479
0
    aDifference->Or(*aDifference, aOtherBounds);
480
0
    return;
481
0
  }
482
0
  if (mHaveClipRect) {
483
0
    AccumulateRectDifference(mClipRect + aOffset,
484
0
                             aOther.mClipRect,
485
0
                             aBounds.Union(aOtherBounds),
486
0
                             aDifference);
487
0
  }
488
0
  for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
489
0
    if (mRoundedClipRects[i] + aOffset != aOther.mRoundedClipRects[i]) {
490
0
      AccumulateRoundedRectDifference(mRoundedClipRects[i] + aOffset,
491
0
                                      aOther.mRoundedClipRects[i],
492
0
                                      aBounds,
493
0
                                      aOtherBounds,
494
0
                                      aDifference);
495
0
    }
496
0
  }
497
0
}
498
499
void
500
DisplayItemClip::AppendRoundedRects(nsTArray<RoundedRect>* aArray) const
501
0
{
502
0
  aArray->AppendElements(mRoundedClipRects.Elements(),
503
0
                         mRoundedClipRects.Length());
504
0
}
505
506
bool
507
DisplayItemClip::ComputeRegionInClips(const DisplayItemClip* aOldClip,
508
                                      const nsPoint& aShift,
509
                                      nsRegion* aCombined) const
510
0
{
511
0
  if (!mHaveClipRect || (aOldClip && !aOldClip->mHaveClipRect)) {
512
0
    return false;
513
0
  }
514
0
515
0
  if (aOldClip) {
516
0
    *aCombined = aOldClip->NonRoundedIntersection();
517
0
    aCombined->MoveBy(aShift);
518
0
    aCombined->Or(*aCombined, NonRoundedIntersection());
519
0
  } else {
520
0
    *aCombined = NonRoundedIntersection();
521
0
  }
522
0
  return true;
523
0
}
524
525
void
526
DisplayItemClip::MoveBy(const nsPoint& aPoint)
527
0
{
528
0
  if (!mHaveClipRect)
529
0
    return;
530
0
  mClipRect += aPoint;
531
0
  for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
532
0
    mRoundedClipRects[i].mRect += aPoint;
533
0
  }
534
0
}
535
536
static DisplayItemClip* gNoClip;
537
538
const DisplayItemClip&
539
DisplayItemClip::NoClip()
540
0
{
541
0
  if (!gNoClip) {
542
0
    gNoClip = new DisplayItemClip();
543
0
  }
544
0
  return *gNoClip;
545
0
}
546
547
void
548
DisplayItemClip::Shutdown()
549
0
{
550
0
  delete gNoClip;
551
0
  gNoClip = nullptr;
552
0
}
553
554
nsCString
555
DisplayItemClip::ToString() const
556
0
{
557
0
  nsAutoCString str;
558
0
  if (mHaveClipRect) {
559
0
    str.AppendPrintf("%d,%d,%d,%d",
560
0
                     mClipRect.x,
561
0
                     mClipRect.y,
562
0
                     mClipRect.width,
563
0
                     mClipRect.height);
564
0
    for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
565
0
      const RoundedRect& r = mRoundedClipRects[i];
566
0
      str.AppendPrintf(" [%d,%d,%d,%d corners %d,%d,%d,%d,%d,%d,%d,%d]",
567
0
                       r.mRect.x,
568
0
                       r.mRect.y,
569
0
                       r.mRect.width,
570
0
                       r.mRect.height,
571
0
                       r.mRadii[0],
572
0
                       r.mRadii[1],
573
0
                       r.mRadii[2],
574
0
                       r.mRadii[3],
575
0
                       r.mRadii[4],
576
0
                       r.mRadii[5],
577
0
                       r.mRadii[6],
578
0
                       r.mRadii[7]);
579
0
    }
580
0
  }
581
0
  return std::move(str);
582
0
}
583
584
void
585
DisplayItemClip::ToComplexClipRegions(
586
  int32_t aAppUnitsPerDevPixel,
587
  const layers::StackingContextHelper& aSc,
588
  nsTArray<wr::ComplexClipRegion>& aOutArray) const
589
0
{
590
0
  for (uint32_t i = 0; i < mRoundedClipRects.Length(); i++) {
591
0
    wr::ComplexClipRegion* region = aOutArray.AppendElement();
592
0
    region->rect = wr::ToRoundedLayoutRect(LayoutDeviceRect::FromAppUnits(
593
0
      mRoundedClipRects[i].mRect, aAppUnitsPerDevPixel));
594
0
    const nscoord* radii = mRoundedClipRects[i].mRadii;
595
0
    region->radii = wr::ToBorderRadius(
596
0
      LayoutDeviceSize::FromAppUnits(
597
0
        nsSize(radii[eCornerTopLeftX], radii[eCornerTopLeftY]),
598
0
        aAppUnitsPerDevPixel),
599
0
      LayoutDeviceSize::FromAppUnits(
600
0
        nsSize(radii[eCornerTopRightX], radii[eCornerTopRightY]),
601
0
        aAppUnitsPerDevPixel),
602
0
      LayoutDeviceSize::FromAppUnits(
603
0
        nsSize(radii[eCornerBottomLeftX], radii[eCornerBottomLeftY]),
604
0
        aAppUnitsPerDevPixel),
605
0
      LayoutDeviceSize::FromAppUnits(
606
0
        nsSize(radii[eCornerBottomRightX], radii[eCornerBottomRightY]),
607
0
        aAppUnitsPerDevPixel));
608
0
    region->mode = wr::ClipMode::Clip;
609
0
  }
610
0
}
611
612
} // namespace mozilla