Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/Compositor.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 "mozilla/layers/Compositor.h"
8
#include "base/message_loop.h"          // for MessageLoop
9
#include "mozilla/layers/CompositorBridgeParent.h"  // for CompositorBridgeParent
10
#include "mozilla/layers/Diagnostics.h"
11
#include "mozilla/layers/Effects.h"     // for Effect, EffectChain, etc
12
#include "mozilla/layers/TextureClient.h"
13
#include "mozilla/layers/TextureHost.h"
14
#include "mozilla/layers/CompositorThread.h"
15
#include "mozilla/mozalloc.h"           // for operator delete, etc
16
#include "gfx2DGlue.h"
17
#include "nsAppRunner.h"
18
#include "LayersHelpers.h"
19
20
namespace mozilla {
21
22
namespace layers {
23
24
Compositor::Compositor(widget::CompositorWidget* aWidget,
25
                      CompositorBridgeParent* aParent)
26
  : mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC)
27
  , mParent(aParent)
28
  , mPixelsPerFrame(0)
29
  , mPixelsFilled(0)
30
  , mScreenRotation(ROTATION_0)
31
  , mWidget(aWidget)
32
  , mIsDestroyed(false)
33
#if defined(MOZ_WIDGET_ANDROID)
34
  // If the default color isn't white for Fennec, there is a black
35
  // flash before the first page of a tab is loaded.
36
  , mClearColor(1.0, 1.0, 1.0, 1.0)
37
  , mDefaultClearColor(1.0, 1.0, 1.0, 1.0)
38
#else
39
  , mClearColor(0.0, 0.0, 0.0, 0.0)
40
  , mDefaultClearColor(0.0, 0.0, 0.0, 0.0)
41
#endif
42
0
{
43
0
}
44
45
Compositor::~Compositor()
46
0
{
47
0
  ReadUnlockTextures();
48
0
}
49
50
void
51
Compositor::Destroy()
52
0
{
53
0
  TextureSourceProvider::Destroy();
54
0
  mIsDestroyed = true;
55
0
}
56
57
void
58
Compositor::EndFrame()
59
0
{
60
0
  ReadUnlockTextures();
61
0
  mLastCompositionEndTime = TimeStamp::Now();
62
0
}
63
64
bool
65
Compositor::ShouldDrawDiagnostics(DiagnosticFlags aFlags)
66
0
{
67
0
  if ((aFlags & DiagnosticFlags::TILE) && !(mDiagnosticTypes & DiagnosticTypes::TILE_BORDERS)) {
68
0
    return false;
69
0
  }
70
0
  if ((aFlags & DiagnosticFlags::BIGIMAGE) &&
71
0
      !(mDiagnosticTypes & DiagnosticTypes::BIGIMAGE_BORDERS)) {
72
0
    return false;
73
0
  }
74
0
  if (mDiagnosticTypes == DiagnosticTypes::NO_DIAGNOSTIC) {
75
0
    return false;
76
0
  }
77
0
  return true;
78
0
}
79
80
void
81
Compositor::DrawDiagnostics(DiagnosticFlags aFlags,
82
                            const nsIntRegion& aVisibleRegion,
83
                            const gfx::IntRect& aClipRect,
84
                            const gfx::Matrix4x4& aTransform,
85
                            uint32_t aFlashCounter)
86
0
{
87
0
  if (!ShouldDrawDiagnostics(aFlags)) {
88
0
    return;
89
0
  }
90
0
91
0
  if (aVisibleRegion.GetNumRects() > 1) {
92
0
    for (auto iter = aVisibleRegion.RectIter(); !iter.Done(); iter.Next()) {
93
0
      DrawDiagnostics(aFlags | DiagnosticFlags::REGION_RECT,
94
0
                      IntRectToRect(iter.Get()), aClipRect, aTransform,
95
0
                      aFlashCounter);
96
0
    }
97
0
  }
98
0
99
0
  DrawDiagnostics(aFlags, IntRectToRect(aVisibleRegion.GetBounds()),
100
0
                  aClipRect, aTransform, aFlashCounter);
101
0
}
102
103
void
104
Compositor::DrawDiagnostics(DiagnosticFlags aFlags,
105
                            const gfx::Rect& aVisibleRect,
106
                            const gfx::IntRect& aClipRect,
107
                            const gfx::Matrix4x4& aTransform,
108
                            uint32_t aFlashCounter)
109
0
{
110
0
  if (!ShouldDrawDiagnostics(aFlags)) {
111
0
    return;
112
0
  }
113
0
114
0
  DrawDiagnosticsInternal(aFlags, aVisibleRect, aClipRect, aTransform,
115
0
                          aFlashCounter);
116
0
}
117
118
void
119
Compositor::DrawDiagnosticsInternal(DiagnosticFlags aFlags,
120
                                    const gfx::Rect& aVisibleRect,
121
                                    const gfx::IntRect& aClipRect,
122
                                    const gfx::Matrix4x4& aTransform,
123
                                    uint32_t aFlashCounter)
124
0
{
125
#ifdef ANDROID
126
  int lWidth = 10;
127
#else
128
  int lWidth = 2;
129
0
#endif
130
0
131
0
  gfx::Color color;
132
0
  if (aFlags & DiagnosticFlags::CONTENT) {
133
0
    color = gfx::Color(0.0f, 1.0f, 0.0f, 1.0f); // green
134
0
    if (aFlags & DiagnosticFlags::COMPONENT_ALPHA) {
135
0
      color = gfx::Color(0.0f, 1.0f, 1.0f, 1.0f); // greenish blue
136
0
    }
137
0
  } else if (aFlags & DiagnosticFlags::IMAGE) {
138
0
    if (aFlags & DiagnosticFlags::NV12) {
139
0
      color = gfx::Color(1.0f, 1.0f, 0.0f, 1.0f); // yellow
140
0
    } else if (aFlags & DiagnosticFlags::YCBCR) {
141
0
      color = gfx::Color(1.0f, 0.55f, 0.0f, 1.0f); // orange
142
0
    } else {
143
0
      color = gfx::Color(1.0f, 0.0f, 0.0f, 1.0f); // red
144
0
    }
145
0
  } else if (aFlags & DiagnosticFlags::COLOR) {
146
0
    color = gfx::Color(0.0f, 0.0f, 1.0f, 1.0f); // blue
147
0
  } else if (aFlags & DiagnosticFlags::CONTAINER) {
148
0
    color = gfx::Color(0.8f, 0.0f, 0.8f, 1.0f); // purple
149
0
  }
150
0
151
0
  // make tile borders a bit more transparent to keep layer borders readable.
152
0
  if (aFlags & DiagnosticFlags::TILE ||
153
0
      aFlags & DiagnosticFlags::BIGIMAGE ||
154
0
      aFlags & DiagnosticFlags::REGION_RECT) {
155
0
    lWidth = 1;
156
0
    color.r *= 0.7f;
157
0
    color.g *= 0.7f;
158
0
    color.b *= 0.7f;
159
0
    color.a = color.a * 0.5f;
160
0
  } else {
161
0
    color.a = color.a * 0.7f;
162
0
  }
163
0
164
0
165
0
  if (mDiagnosticTypes & DiagnosticTypes::FLASH_BORDERS) {
166
0
    float flash = (float)aFlashCounter / (float)DIAGNOSTIC_FLASH_COUNTER_MAX;
167
0
    color.r *= flash;
168
0
    color.g *= flash;
169
0
    color.b *= flash;
170
0
  }
171
0
172
0
  SlowDrawRect(aVisibleRect, color, aClipRect, aTransform, lWidth);
173
0
}
174
175
static void
176
UpdateTextureCoordinates(gfx::TexturedTriangle& aTriangle,
177
                         const gfx::Rect& aRect,
178
                         const gfx::Rect& aIntersection,
179
                         const gfx::Rect& aTextureCoords)
180
0
{
181
0
  // Calculate the relative offset of the intersection within the layer.
182
0
  float dx = (aIntersection.X() - aRect.X()) / aRect.Width();
183
0
  float dy = (aIntersection.Y() - aRect.Y()) / aRect.Height();
184
0
185
0
  // Update the texture offset.
186
0
  float x = aTextureCoords.X() + dx * aTextureCoords.Width();
187
0
  float y = aTextureCoords.Y() + dy * aTextureCoords.Height();
188
0
189
0
  // Scale the texture width and height.
190
0
  float w = aTextureCoords.Width() * aIntersection.Width() / aRect.Width();
191
0
  float h = aTextureCoords.Height() * aIntersection.Height() / aRect.Height();
192
0
193
0
  static const auto Clamp = [](float& f)
194
0
  {
195
0
    if (f >= 1.0f) f = 1.0f;
196
0
    if (f <= 0.0f) f = 0.0f;
197
0
  };
198
0
199
0
  auto UpdatePoint = [&](const gfx::Point& p, gfx::Point& t)
200
0
  {
201
0
    t.x = x + (p.x - aIntersection.X()) / aIntersection.Width() * w;
202
0
    t.y = y + (p.y - aIntersection.Y()) / aIntersection.Height() * h;
203
0
204
0
    Clamp(t.x);
205
0
    Clamp(t.y);
206
0
  };
207
0
208
0
  UpdatePoint(aTriangle.p1, aTriangle.textureCoords.p1);
209
0
  UpdatePoint(aTriangle.p2, aTriangle.textureCoords.p2);
210
0
  UpdatePoint(aTriangle.p3, aTriangle.textureCoords.p3);
211
0
}
212
213
void
214
Compositor::DrawGeometry(const gfx::Rect& aRect,
215
                         const gfx::IntRect& aClipRect,
216
                         const EffectChain& aEffectChain,
217
                         gfx::Float aOpacity,
218
                         const gfx::Matrix4x4& aTransform,
219
                         const gfx::Rect& aVisibleRect,
220
                         const Maybe<gfx::Polygon>& aGeometry)
221
0
{
222
0
  if (aRect.IsEmpty()) {
223
0
    return;
224
0
  }
225
0
226
0
  if (!aGeometry || !SupportsLayerGeometry()) {
227
0
    DrawQuad(aRect, aClipRect, aEffectChain,
228
0
             aOpacity, aTransform, aVisibleRect);
229
0
    return;
230
0
  }
231
0
232
0
  // Cull completely invisible polygons.
233
0
  if (aRect.Intersect(aGeometry->BoundingBox()).IsEmpty()) {
234
0
    return;
235
0
  }
236
0
237
0
  const gfx::Polygon clipped = aGeometry->ClipPolygon(aRect);
238
0
239
0
  // Cull polygons with no area.
240
0
  if (clipped.IsEmpty()) {
241
0
    return;
242
0
  }
243
0
244
0
  DrawPolygon(clipped, aRect, aClipRect, aEffectChain,
245
0
              aOpacity, aTransform, aVisibleRect);
246
0
}
247
248
void
249
Compositor::DrawTriangles(const nsTArray<gfx::TexturedTriangle>& aTriangles,
250
                          const gfx::Rect& aRect,
251
                          const gfx::IntRect& aClipRect,
252
                          const EffectChain& aEffectChain,
253
                          gfx::Float aOpacity,
254
                          const gfx::Matrix4x4& aTransform,
255
                          const gfx::Rect& aVisibleRect)
256
0
{
257
0
  for (const gfx::TexturedTriangle& triangle : aTriangles) {
258
0
    DrawTriangle(triangle, aClipRect, aEffectChain,
259
0
                 aOpacity, aTransform, aVisibleRect);
260
0
  }
261
0
}
262
263
nsTArray<gfx::TexturedTriangle>
264
GenerateTexturedTriangles(const gfx::Polygon& aPolygon,
265
                          const gfx::Rect& aRect,
266
                          const gfx::Rect& aTexRect)
267
0
{
268
0
  nsTArray<gfx::TexturedTriangle> texturedTriangles;
269
0
270
0
  gfx::Rect layerRects[4];
271
0
  gfx::Rect textureRects[4];
272
0
  size_t rects = DecomposeIntoNoRepeatRects(aRect, aTexRect,
273
0
                                            &layerRects, &textureRects);
274
0
  for (size_t i = 0; i < rects; ++i) {
275
0
    const gfx::Rect& rect = layerRects[i];
276
0
    const gfx::Rect& texRect = textureRects[i];
277
0
    const gfx::Polygon clipped = aPolygon.ClipPolygon(rect);
278
0
279
0
    if (clipped.IsEmpty()) {
280
0
      continue;
281
0
    }
282
0
283
0
    for (const gfx::Triangle& triangle : clipped.ToTriangles()) {
284
0
      const gfx::Rect intersection = rect.Intersect(triangle.BoundingBox());
285
0
286
0
      // Cull completely invisible triangles.
287
0
      if (intersection.IsEmpty()) {
288
0
        continue;
289
0
      }
290
0
291
0
      MOZ_ASSERT(rect.Width() > 0.0f && rect.Height() > 0.0f);
292
0
      MOZ_ASSERT(intersection.Width() > 0.0f && intersection.Height() > 0.0f);
293
0
294
0
      // Since the texture was created for non-split geometry, we need to
295
0
      // update the texture coordinates to account for the split.
296
0
      gfx::TexturedTriangle t(triangle);
297
0
      UpdateTextureCoordinates(t, rect, intersection, texRect);
298
0
      texturedTriangles.AppendElement(std::move(t));
299
0
    }
300
0
  }
301
0
302
0
  return texturedTriangles;
303
0
}
304
305
nsTArray<TexturedVertex>
306
TexturedTrianglesToVertexArray(const nsTArray<gfx::TexturedTriangle>& aTriangles)
307
0
{
308
0
  const auto VertexFromPoints = [](const gfx::Point& p, const gfx::Point& t) {
309
0
    return TexturedVertex { { p.x, p.y }, { t.x, t.y } };
310
0
  };
311
0
312
0
  nsTArray<TexturedVertex> vertices;
313
0
314
0
  for (const gfx::TexturedTriangle& t : aTriangles) {
315
0
    vertices.AppendElement(VertexFromPoints(t.p1, t.textureCoords.p1));
316
0
    vertices.AppendElement(VertexFromPoints(t.p2, t.textureCoords.p2));
317
0
    vertices.AppendElement(VertexFromPoints(t.p3, t.textureCoords.p3));
318
0
  }
319
0
320
0
  return vertices;
321
0
}
322
323
void
324
Compositor::DrawPolygon(const gfx::Polygon& aPolygon,
325
                        const gfx::Rect& aRect,
326
                        const gfx::IntRect& aClipRect,
327
                        const EffectChain& aEffectChain,
328
                        gfx::Float aOpacity,
329
                        const gfx::Matrix4x4& aTransform,
330
                        const gfx::Rect& aVisibleRect)
331
0
{
332
0
  nsTArray<gfx::TexturedTriangle> texturedTriangles;
333
0
334
0
  TexturedEffect* texturedEffect =
335
0
    aEffectChain.mPrimaryEffect->AsTexturedEffect();
336
0
337
0
  if (texturedEffect) {
338
0
    texturedTriangles =
339
0
      GenerateTexturedTriangles(aPolygon, aRect, texturedEffect->mTextureCoords);
340
0
  } else {
341
0
    for (const gfx::Triangle& triangle : aPolygon.ToTriangles()) {
342
0
      texturedTriangles.AppendElement(gfx::TexturedTriangle(triangle));
343
0
    }
344
0
  }
345
0
346
0
  if (texturedTriangles.IsEmpty()) {
347
0
    // Nothing to render.
348
0
    return;
349
0
  }
350
0
351
0
  DrawTriangles(texturedTriangles, aRect, aClipRect, aEffectChain,
352
0
                aOpacity, aTransform, aVisibleRect);
353
0
}
354
355
void
356
Compositor::SlowDrawRect(const gfx::Rect& aRect, const gfx::Color& aColor,
357
                     const gfx::IntRect& aClipRect,
358
                     const gfx::Matrix4x4& aTransform, int aStrokeWidth)
359
0
{
360
0
  // TODO This should draw a rect using a single draw call but since
361
0
  // this is only used for debugging overlays it's not worth optimizing ATM.
362
0
  float opacity = 1.0f;
363
0
  EffectChain effects;
364
0
365
0
  effects.mPrimaryEffect = new EffectSolidColor(aColor);
366
0
  // left
367
0
  this->DrawQuad(gfx::Rect(aRect.X(), aRect.Y(),
368
0
                           aStrokeWidth, aRect.Height()),
369
0
                 aClipRect, effects, opacity,
370
0
                 aTransform);
371
0
  // top
372
0
  this->DrawQuad(gfx::Rect(aRect.X() + aStrokeWidth, aRect.Y(),
373
0
                           aRect.Width() - 2 * aStrokeWidth, aStrokeWidth),
374
0
                 aClipRect, effects, opacity,
375
0
                 aTransform);
376
0
  // right
377
0
  this->DrawQuad(gfx::Rect(aRect.XMost() - aStrokeWidth, aRect.Y(),
378
0
                           aStrokeWidth, aRect.Height()),
379
0
                 aClipRect, effects, opacity,
380
0
                 aTransform);
381
0
  // bottom
382
0
  this->DrawQuad(gfx::Rect(aRect.X() + aStrokeWidth, aRect.YMost() - aStrokeWidth,
383
0
                           aRect.Width() - 2 * aStrokeWidth, aStrokeWidth),
384
0
                 aClipRect, effects, opacity,
385
0
                 aTransform);
386
0
}
387
388
void
389
Compositor::FillRect(const gfx::Rect& aRect, const gfx::Color& aColor,
390
                     const gfx::IntRect& aClipRect,
391
                     const gfx::Matrix4x4& aTransform)
392
0
{
393
0
  float opacity = 1.0f;
394
0
  EffectChain effects;
395
0
396
0
  effects.mPrimaryEffect = new EffectSolidColor(aColor);
397
0
  this->DrawQuad(aRect,
398
0
                 aClipRect, effects, opacity,
399
0
                 aTransform);
400
0
}
401
402
403
static float
404
WrapTexCoord(float v)
405
0
{
406
0
    // This should return values in range [0, 1.0)
407
0
    return v - floorf(v);
408
0
}
409
410
static void
411
SetRects(size_t n,
412
         decomposedRectArrayT* aLayerRects,
413
         decomposedRectArrayT* aTextureRects,
414
         float x0, float y0, float x1, float y1,
415
         float tx0, float ty0, float tx1, float ty1,
416
         bool flip_y)
417
0
{
418
0
  if (flip_y) {
419
0
    std::swap(ty0, ty1);
420
0
  }
421
0
  (*aLayerRects)[n] = gfx::Rect(x0, y0, x1 - x0, y1 - y0);
422
0
  (*aTextureRects)[n] = gfx::Rect(tx0, ty0, tx1 - tx0, ty1 - ty0);
423
0
}
424
425
#ifdef DEBUG
426
static inline bool
427
FuzzyEqual(float a, float b)
428
{
429
  return fabs(a - b) < 0.0001f;
430
}
431
static inline bool
432
FuzzyLTE(float a, float b)
433
{
434
  return a <= b + 0.0001f;
435
}
436
#endif
437
438
size_t
439
DecomposeIntoNoRepeatRects(const gfx::Rect& aRect,
440
                           const gfx::Rect& aTexCoordRect,
441
                           decomposedRectArrayT* aLayerRects,
442
                           decomposedRectArrayT* aTextureRects)
443
0
{
444
0
  gfx::Rect texCoordRect = aTexCoordRect;
445
0
446
0
  // If the texture should be flipped, it will have negative height. Detect that
447
0
  // here and compensate for it. We will flip each rect as we emit it.
448
0
  bool flipped = false;
449
0
  if (texCoordRect.Height() < 0) {
450
0
    flipped = true;
451
0
    texCoordRect.MoveByY(texCoordRect.Height());
452
0
    texCoordRect.SetHeight(-texCoordRect.Height());
453
0
  }
454
0
455
0
  // Wrap the texture coordinates so they are within [0,1] and cap width/height
456
0
  // at 1. We rely on this below.
457
0
  texCoordRect = gfx::Rect(gfx::Point(WrapTexCoord(texCoordRect.X()),
458
0
                                      WrapTexCoord(texCoordRect.Y())),
459
0
                           gfx::Size(std::min(texCoordRect.Width(), 1.0f),
460
0
                                     std::min(texCoordRect.Height(), 1.0f)));
461
0
462
0
  NS_ASSERTION(texCoordRect.X() >= 0.0f && texCoordRect.X() <= 1.0f &&
463
0
               texCoordRect.Y() >= 0.0f && texCoordRect.Y() <= 1.0f &&
464
0
               texCoordRect.Width() >= 0.0f && texCoordRect.Width() <= 1.0f &&
465
0
               texCoordRect.Height() >= 0.0f && texCoordRect.Height() <= 1.0f &&
466
0
               texCoordRect.XMost() >= 0.0f && texCoordRect.XMost() <= 2.0f &&
467
0
               texCoordRect.YMost() >= 0.0f && texCoordRect.YMost() <= 2.0f,
468
0
               "We just wrapped the texture coordinates, didn't we?");
469
0
470
0
  // Get the top left and bottom right points of the rectangle. Note that
471
0
  // tl.x/tl.y are within [0,1] but br.x/br.y are within [0,2].
472
0
  gfx::Point tl = texCoordRect.TopLeft();
473
0
  gfx::Point br = texCoordRect.BottomRight();
474
0
475
0
  NS_ASSERTION(tl.x >= 0.0f && tl.x <= 1.0f &&
476
0
               tl.y >= 0.0f && tl.y <= 1.0f &&
477
0
               br.x >= tl.x && br.x <= 2.0f &&
478
0
               br.y >= tl.y && br.y <= 2.0f &&
479
0
               FuzzyLTE(br.x - tl.x, 1.0f) &&
480
0
               FuzzyLTE(br.y - tl.y, 1.0f),
481
0
               "Somehow generated invalid texture coordinates");
482
0
483
0
  // Then check if we wrap in either the x or y axis.
484
0
  bool xwrap = br.x > 1.0f;
485
0
  bool ywrap = br.y > 1.0f;
486
0
487
0
  // If xwrap is false, the texture will be sampled from tl.x .. br.x.
488
0
  // If xwrap is true, then it will be split into tl.x .. 1.0, and
489
0
  // 0.0 .. WrapTexCoord(br.x). Same for the Y axis. The destination
490
0
  // rectangle is also split appropriately, according to the calculated
491
0
  // xmid/ymid values.
492
0
  if (!xwrap && !ywrap) {
493
0
    SetRects(0, aLayerRects, aTextureRects,
494
0
             aRect.X(), aRect.Y(), aRect.XMost(), aRect.YMost(),
495
0
             tl.x, tl.y, br.x, br.y,
496
0
             flipped);
497
0
    return 1;
498
0
  }
499
0
500
0
  // If we are dealing with wrapping br.x and br.y are greater than 1.0 so
501
0
  // wrap them here as well.
502
0
  br = gfx::Point(xwrap ? WrapTexCoord(br.x) : br.x,
503
0
                  ywrap ? WrapTexCoord(br.y) : br.y);
504
0
505
0
  // If we wrap around along the x axis, we will draw first from
506
0
  // tl.x .. 1.0 and then from 0.0 .. br.x (which we just wrapped above).
507
0
  // The same applies for the Y axis. The midpoints we calculate here are
508
0
  // only valid if we actually wrap around.
509
0
  GLfloat xmid = aRect.X() + (1.0f - tl.x) / texCoordRect.Width() * aRect.Width();
510
0
  GLfloat ymid = aRect.Y() + (1.0f - tl.y) / texCoordRect.Height() * aRect.Height();
511
0
512
0
  // Due to floating-point inaccuracy, we have to use XMost()-x and YMost()-y
513
0
  // to calculate width and height, respectively, to ensure that size will
514
0
  // remain consistent going from absolute to relative and back again.
515
0
  NS_ASSERTION(!xwrap ||
516
0
               (xmid >= aRect.X() &&
517
0
                xmid <= aRect.XMost() &&
518
0
                FuzzyEqual((xmid - aRect.X()) + (aRect.XMost() - xmid), aRect.XMost() - aRect.X())),
519
0
               "xmid should be within [x,XMost()] and the wrapped rect should have the same width");
520
0
  NS_ASSERTION(!ywrap ||
521
0
               (ymid >= aRect.Y() &&
522
0
                ymid <= aRect.YMost() &&
523
0
                FuzzyEqual((ymid - aRect.Y()) + (aRect.YMost() - ymid), aRect.YMost() - aRect.Y())),
524
0
               "ymid should be within [y,YMost()] and the wrapped rect should have the same height");
525
0
526
0
  if (!xwrap && ywrap) {
527
0
    SetRects(0, aLayerRects, aTextureRects,
528
0
             aRect.X(), aRect.Y(), aRect.XMost(), ymid,
529
0
             tl.x, tl.y, br.x, 1.0f,
530
0
             flipped);
531
0
    SetRects(1, aLayerRects, aTextureRects,
532
0
             aRect.X(), ymid, aRect.XMost(), aRect.YMost(),
533
0
             tl.x, 0.0f, br.x, br.y,
534
0
             flipped);
535
0
    return 2;
536
0
  }
537
0
538
0
  if (xwrap && !ywrap) {
539
0
    SetRects(0, aLayerRects, aTextureRects,
540
0
             aRect.X(), aRect.Y(), xmid, aRect.YMost(),
541
0
             tl.x, tl.y, 1.0f, br.y,
542
0
             flipped);
543
0
    SetRects(1, aLayerRects, aTextureRects,
544
0
             xmid, aRect.Y(), aRect.XMost(), aRect.YMost(),
545
0
             0.0f, tl.y, br.x, br.y,
546
0
             flipped);
547
0
    return 2;
548
0
  }
549
0
550
0
  SetRects(0, aLayerRects, aTextureRects,
551
0
           aRect.X(), aRect.Y(), xmid, ymid,
552
0
           tl.x, tl.y, 1.0f, 1.0f,
553
0
           flipped);
554
0
  SetRects(1, aLayerRects, aTextureRects,
555
0
           xmid, aRect.Y(), aRect.XMost(), ymid,
556
0
           0.0f, tl.y, br.x, 1.0f,
557
0
           flipped);
558
0
  SetRects(2, aLayerRects, aTextureRects,
559
0
           aRect.X(), ymid, xmid, aRect.YMost(),
560
0
           tl.x, 0.0f, 1.0f, br.y,
561
0
           flipped);
562
0
  SetRects(3, aLayerRects, aTextureRects,
563
0
           xmid, ymid, aRect.XMost(), aRect.YMost(),
564
0
           0.0f, 0.0f, br.x, br.y,
565
0
           flipped);
566
0
  return 4;
567
0
}
568
569
gfx::IntRect
570
Compositor::ComputeBackdropCopyRect(const gfx::Rect& aRect,
571
                                    const gfx::IntRect& aClipRect,
572
                                    const gfx::Matrix4x4& aTransform,
573
                                    gfx::Matrix4x4* aOutTransform,
574
                                    gfx::Rect* aOutLayerQuad)
575
0
{
576
0
  // Compute the clip.
577
0
  gfx::IntPoint rtOffset = GetCurrentRenderTarget()->GetOrigin();
578
0
  gfx::IntSize rtSize = GetCurrentRenderTarget()->GetSize();
579
0
580
0
  return layers::ComputeBackdropCopyRect(
581
0
    aRect,
582
0
    aClipRect,
583
0
    aTransform,
584
0
    gfx::IntRect(rtOffset, rtSize),
585
0
    aOutTransform,
586
0
    aOutLayerQuad);
587
0
}
588
589
gfx::IntRect
590
Compositor::ComputeBackdropCopyRect(const gfx::Triangle& aTriangle,
591
                                    const gfx::IntRect& aClipRect,
592
                                    const gfx::Matrix4x4& aTransform,
593
                                    gfx::Matrix4x4* aOutTransform,
594
                                    gfx::Rect* aOutLayerQuad)
595
0
{
596
0
  gfx::Rect boundingBox = aTriangle.BoundingBox();
597
0
  return ComputeBackdropCopyRect(boundingBox, aClipRect, aTransform,
598
0
                                 aOutTransform, aOutLayerQuad);
599
0
}
600
601
void
602
Compositor::SetInvalid()
603
0
{
604
0
  mParent = nullptr;
605
0
}
606
607
bool
608
Compositor::IsValid() const
609
0
{
610
0
  return !!mParent;
611
0
}
612
613
void
614
Compositor::UnlockAfterComposition(TextureHost* aTexture)
615
0
{
616
0
  TextureSourceProvider::UnlockAfterComposition(aTexture);
617
0
618
0
  // If this is being called after we shutdown the compositor, we must finish
619
0
  // read unlocking now to prevent a cycle.
620
0
  if (IsDestroyed()) {
621
0
    ReadUnlockTextures();
622
0
  }
623
0
}
624
625
bool
626
Compositor::NotifyNotUsedAfterComposition(TextureHost* aTextureHost)
627
0
{
628
0
  if (IsDestroyed() || AsBasicCompositor()) {
629
0
    return false;
630
0
  }
631
0
  return TextureSourceProvider::NotifyNotUsedAfterComposition(aTextureHost);
632
0
}
633
634
void
635
Compositor::GetFrameStats(GPUStats* aStats)
636
0
{
637
0
  aStats->mInvalidPixels = mPixelsPerFrame;
638
0
  aStats->mPixelsFilled = mPixelsFilled;
639
0
}
640
641
} // namespace layers
642
} // namespace mozilla