Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/composite/ContentHost.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/ContentHost.h"
8
#include "LayersLogging.h"              // for AppendToString
9
#include "gfx2DGlue.h"                  // for ContentForFormat
10
#include "mozilla/gfx/Point.h"          // for IntSize
11
#include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
12
#include "mozilla/gfx/BaseRect.h"       // for BaseRect
13
#include "mozilla/layers/Compositor.h"  // for Compositor
14
#include "mozilla/layers/Effects.h"     // for TexturedEffect, Effect, etc
15
#include "mozilla/layers/LayersMessages.h"  // for ThebesBufferData
16
#include "nsAString.h"
17
#include "nsPrintfCString.h"            // for nsPrintfCString
18
#include "nsString.h"                   // for nsAutoCString
19
#include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
20
21
namespace mozilla {
22
using namespace gfx;
23
24
namespace layers {
25
26
ContentHostBase::ContentHostBase(const TextureInfo& aTextureInfo)
27
  : ContentHost(aTextureInfo)
28
  , mInitialised(false)
29
0
{}
30
31
ContentHostBase::~ContentHostBase()
32
0
{
33
0
}
34
35
void
36
ContentHostTexture::Composite(Compositor* aCompositor,
37
                              LayerComposite* aLayer,
38
                              EffectChain& aEffectChain,
39
                              float aOpacity,
40
                              const gfx::Matrix4x4& aTransform,
41
                              const SamplingFilter aSamplingFilter,
42
                              const IntRect& aClipRect,
43
                              const nsIntRegion* aVisibleRegion,
44
                              const Maybe<gfx::Polygon>& aGeometry)
45
0
{
46
0
  NS_ASSERTION(aVisibleRegion, "Requires a visible region");
47
0
48
0
  AutoLockCompositableHost lock(this);
49
0
  if (lock.Failed()) {
50
0
    return;
51
0
  }
52
0
53
0
  if (!mTextureHost->BindTextureSource(mTextureSource)) {
54
0
    return;
55
0
  }
56
0
  MOZ_ASSERT(mTextureSource.get());
57
0
58
0
  if (!mTextureHostOnWhite) {
59
0
    mTextureSourceOnWhite = nullptr;
60
0
  }
61
0
  if (mTextureHostOnWhite && !mTextureHostOnWhite->BindTextureSource(mTextureSourceOnWhite)) {
62
0
    return;
63
0
  }
64
0
65
0
  RefPtr<TexturedEffect> effect = CreateTexturedEffect(mTextureSource.get(),
66
0
                                                       mTextureSourceOnWhite.get(),
67
0
                                                       aSamplingFilter, true);
68
0
  if (!effect) {
69
0
    return;
70
0
  }
71
0
72
0
  aEffectChain.mPrimaryEffect = effect;
73
0
74
0
  nsIntRegion tmpRegion;
75
0
  const nsIntRegion* renderRegion;
76
0
#ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
77
0
  if (PaintWillResample()) {
78
0
    // If we're resampling, then the texture image will contain exactly the
79
0
    // entire visible region's bounds, and we should draw it all in one quad
80
0
    // to avoid unexpected aliasing.
81
0
    tmpRegion = aVisibleRegion->GetBounds();
82
0
    renderRegion = &tmpRegion;
83
0
  } else {
84
0
    renderRegion = aVisibleRegion;
85
0
  }
86
#else
87
  renderRegion = aVisibleRegion;
88
#endif
89
90
0
  nsIntRegion region(*renderRegion);
91
0
  nsIntPoint origin = GetOriginOffset();
92
0
  // translate into TexImage space, buffer origin might not be at texture (0,0)
93
0
  region.MoveBy(-origin);
94
0
95
0
  // Figure out the intersecting draw region
96
0
  gfx::IntSize texSize = mTextureSource->GetSize();
97
0
  IntRect textureRect = IntRect(0, 0, texSize.width, texSize.height);
98
0
  textureRect.MoveBy(region.GetBounds().TopLeft());
99
0
  nsIntRegion subregion;
100
0
  subregion.And(region, textureRect);
101
0
  if (subregion.IsEmpty()) {
102
0
    // Region is empty, nothing to draw
103
0
    return;
104
0
  }
105
0
106
0
  nsIntRegion screenRects;
107
0
  nsIntRegion regionRects;
108
0
109
0
  // Collect texture/screen coordinates for drawing
110
0
  for (auto iter = subregion.RectIter(); !iter.Done(); iter.Next()) {
111
0
    IntRect regionRect = iter.Get();
112
0
    IntRect screenRect = iter.Get();
113
0
    screenRect.MoveBy(origin);
114
0
115
0
    screenRects.Or(screenRects, screenRect);
116
0
    regionRects.Or(regionRects, regionRect);
117
0
  }
118
0
119
0
  BigImageIterator* bigImgIter = mTextureSource->AsBigImageIterator();
120
0
  BigImageIterator* iterOnWhite = nullptr;
121
0
  if (bigImgIter) {
122
0
    bigImgIter->BeginBigImageIteration();
123
0
  }
124
0
125
0
  if (mTextureSourceOnWhite) {
126
0
    iterOnWhite = mTextureSourceOnWhite->AsBigImageIterator();
127
0
    MOZ_ASSERT(!bigImgIter || bigImgIter->GetTileCount() == iterOnWhite->GetTileCount(),
128
0
               "Tile count mismatch on component alpha texture");
129
0
    if (iterOnWhite) {
130
0
      iterOnWhite->BeginBigImageIteration();
131
0
    }
132
0
  }
133
0
134
0
  bool usingTiles = (bigImgIter && bigImgIter->GetTileCount() > 1);
135
0
  do {
136
0
    if (iterOnWhite && bigImgIter) {
137
0
      MOZ_ASSERT(iterOnWhite->GetTileRect() == bigImgIter->GetTileRect(),
138
0
                 "component alpha textures should be the same size.");
139
0
    }
140
0
141
0
    IntRect texRect = bigImgIter ? bigImgIter->GetTileRect()
142
0
                                 : IntRect(0, 0,
143
0
                                             texSize.width,
144
0
                                             texSize.height);
145
0
146
0
    // Draw texture. If we're using tiles, we do repeating manually, as texture
147
0
    // repeat would cause each individual tile to repeat instead of the
148
0
    // compound texture as a whole. This involves drawing at most 4 sections,
149
0
    // 2 for each axis that has texture repeat.
150
0
    for (int y = 0; y < (usingTiles ? 2 : 1); y++) {
151
0
      for (int x = 0; x < (usingTiles ? 2 : 1); x++) {
152
0
        IntRect currentTileRect(texRect);
153
0
        currentTileRect.MoveBy(x * texSize.width, y * texSize.height);
154
0
155
0
        for (auto screenIter = screenRects.RectIter(),
156
0
                  regionIter = regionRects.RectIter();
157
0
             !screenIter.Done() && !regionIter.Done();
158
0
             screenIter.Next(), regionIter.Next()) {
159
0
          const IntRect& screenRect = screenIter.Get();
160
0
          const IntRect& regionRect = regionIter.Get();
161
0
          IntRect tileScreenRect(screenRect);
162
0
          IntRect tileRegionRect(regionRect);
163
0
164
0
          // When we're using tiles, find the intersection between the tile
165
0
          // rect and this region rect. Tiling is then handled by the
166
0
          // outer for-loops and modifying the tile rect.
167
0
          if (usingTiles) {
168
0
            tileScreenRect.MoveBy(-origin);
169
0
            tileScreenRect = tileScreenRect.Intersect(currentTileRect);
170
0
            tileScreenRect.MoveBy(origin);
171
0
172
0
            if (tileScreenRect.IsEmpty())
173
0
              continue;
174
0
175
0
            tileRegionRect = regionRect.Intersect(currentTileRect);
176
0
            tileRegionRect.MoveBy(-currentTileRect.TopLeft());
177
0
          }
178
0
          gfx::Rect rect(tileScreenRect.X(), tileScreenRect.Y(),
179
0
                         tileScreenRect.Width(), tileScreenRect.Height());
180
0
181
0
          effect->mTextureCoords = Rect(Float(tileRegionRect.X()) / texRect.Width(),
182
0
                                        Float(tileRegionRect.Y()) / texRect.Height(),
183
0
                                        Float(tileRegionRect.Width()) / texRect.Width(),
184
0
                                        Float(tileRegionRect.Height()) / texRect.Height());
185
0
186
0
          aCompositor->DrawGeometry(rect, aClipRect, aEffectChain,
187
0
                                    aOpacity, aTransform, aGeometry);
188
0
189
0
          if (usingTiles) {
190
0
            DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT | DiagnosticFlags::BIGIMAGE;
191
0
            if (iterOnWhite) {
192
0
              diagnostics |= DiagnosticFlags::COMPONENT_ALPHA;
193
0
            }
194
0
            aCompositor->DrawDiagnostics(diagnostics, rect, aClipRect,
195
0
                                         aTransform, mFlashCounter);
196
0
          }
197
0
        }
198
0
      }
199
0
    }
200
0
201
0
    if (iterOnWhite) {
202
0
      iterOnWhite->NextTile();
203
0
    }
204
0
  } while (usingTiles && bigImgIter->NextTile());
205
0
206
0
  if (bigImgIter) {
207
0
    bigImgIter->EndBigImageIteration();
208
0
  }
209
0
  if (iterOnWhite) {
210
0
    iterOnWhite->EndBigImageIteration();
211
0
  }
212
0
213
0
  DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT;
214
0
  if (iterOnWhite) {
215
0
    diagnostics |= DiagnosticFlags::COMPONENT_ALPHA;
216
0
  }
217
0
  aCompositor->DrawDiagnostics(diagnostics, nsIntRegion(mBufferRect), aClipRect,
218
0
                               aTransform, mFlashCounter);
219
0
}
220
221
RefPtr<TextureSource>
222
ContentHostTexture::AcquireTextureSource()
223
0
{
224
0
  if (!mTextureHost || !mTextureHost->AcquireTextureSource(mTextureSource)) {
225
0
    return nullptr;
226
0
  }
227
0
  return mTextureSource.get();
228
0
}
229
230
RefPtr<TextureSource>
231
ContentHostTexture::AcquireTextureSourceOnWhite()
232
0
{
233
0
  if (!mTextureHostOnWhite ||
234
0
      !mTextureHostOnWhite->AcquireTextureSource(mTextureSourceOnWhite))
235
0
  {
236
0
    return nullptr;
237
0
  }
238
0
  return mTextureSourceOnWhite.get();
239
0
}
240
241
void
242
ContentHostTexture::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
243
0
{
244
0
  ContentHostBase::UseTextureHost(aTextures);
245
0
  MOZ_ASSERT(aTextures.Length() == 1);
246
0
  const TimedTexture& t = aTextures[0];
247
0
  MOZ_ASSERT(t.mPictureRect.IsEqualInterior(
248
0
      nsIntRect(nsIntPoint(0, 0), nsIntSize(t.mTexture->GetSize()))),
249
0
      "Only default picture rect supported");
250
0
251
0
  if (t.mTexture != mTextureHost) {
252
0
    mReceivedNewHost = true;
253
0
  }
254
0
255
0
  mTextureHost = t.mTexture;
256
0
  mTextureHostOnWhite = nullptr;
257
0
  mTextureSourceOnWhite = nullptr;
258
0
  if (mTextureHost) {
259
0
    mTextureHost->PrepareTextureSource(mTextureSource);
260
0
  }
261
0
}
262
263
void
264
ContentHostTexture::UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
265
                                              TextureHost* aTextureOnWhite)
266
0
{
267
0
  ContentHostBase::UseComponentAlphaTextures(aTextureOnBlack, aTextureOnWhite);
268
0
  mTextureHost = aTextureOnBlack;
269
0
  mTextureHostOnWhite = aTextureOnWhite;
270
0
  if (mTextureHost) {
271
0
    mTextureHost->PrepareTextureSource(mTextureSource);
272
0
  }
273
0
  if (mTextureHostOnWhite) {
274
0
    mTextureHostOnWhite->PrepareTextureSource(mTextureSourceOnWhite);
275
0
  }
276
0
}
277
278
void
279
ContentHostTexture::SetTextureSourceProvider(TextureSourceProvider* aProvider)
280
0
{
281
0
  ContentHostBase::SetTextureSourceProvider(aProvider);
282
0
  if (mTextureHost) {
283
0
    mTextureHost->SetTextureSourceProvider(aProvider);
284
0
  }
285
0
  if (mTextureHostOnWhite) {
286
0
    mTextureHostOnWhite->SetTextureSourceProvider(aProvider);
287
0
  }
288
0
}
289
290
void
291
ContentHostTexture::Dump(std::stringstream& aStream,
292
                         const char* aPrefix,
293
                         bool aDumpHtml)
294
0
{
295
#ifdef MOZ_DUMP_PAINTING
296
  if (aDumpHtml) {
297
    aStream << "<ul>";
298
  }
299
  if (mTextureHost) {
300
    aStream << aPrefix;
301
    if (aDumpHtml) {
302
      aStream << "<li> <a href=";
303
    } else {
304
      aStream << "Front buffer: ";
305
    }
306
    DumpTextureHost(aStream, mTextureHost);
307
    if (aDumpHtml) {
308
      aStream << "> Front buffer </a></li> ";
309
    } else {
310
      aStream << "\n";
311
    }
312
  }
313
  if (mTextureHostOnWhite) {
314
    aStream << aPrefix;
315
    if (aDumpHtml) {
316
      aStream << "<li> <a href=";
317
    } else {
318
      aStream << "Front buffer on white: ";
319
    }
320
    DumpTextureHost(aStream, mTextureHostOnWhite);
321
    if (aDumpHtml) {
322
      aStream << "> Front buffer on white </a> </li> ";
323
    } else {
324
      aStream << "\n";
325
    }
326
  }
327
  if (aDumpHtml) {
328
    aStream << "</ul>";
329
  }
330
#endif
331
}
332
333
static inline void
334
AddWrappedRegion(const nsIntRegion& aInput, nsIntRegion& aOutput,
335
                 const IntSize& aSize, const nsIntPoint& aShift)
336
0
{
337
0
  nsIntRegion tempRegion;
338
0
  tempRegion.And(IntRect(aShift, aSize), aInput);
339
0
  tempRegion.MoveBy(-aShift);
340
0
  aOutput.Or(aOutput, tempRegion);
341
0
}
342
343
bool
344
ContentHostSingleBuffered::UpdateThebes(const ThebesBufferData& aData,
345
                                        const nsIntRegion& aUpdated,
346
                                        const nsIntRegion& aOldValidRegionBack)
347
0
{
348
0
  if (!mTextureHost) {
349
0
    mInitialised = false;
350
0
    return true; // FIXME should we return false? Returning true for now
351
0
  }              // to preserve existing behavior of NOT causing IPC errors.
352
0
353
0
  // updated is in screen coordinates. Convert it to buffer coordinates.
354
0
  nsIntRegion destRegion(aUpdated);
355
0
356
0
  if (mReceivedNewHost) {
357
0
    destRegion.Or(destRegion, aOldValidRegionBack);
358
0
    mReceivedNewHost = false;
359
0
  }
360
0
  destRegion.MoveBy(-aData.rect().TopLeft());
361
0
362
0
  if (!aData.rect().Contains(aUpdated.GetBounds()) ||
363
0
      aData.rotation().x > aData.rect().Width() ||
364
0
      aData.rotation().y > aData.rect().Height()) {
365
0
    NS_ERROR("Invalid update data");
366
0
    return false;
367
0
  }
368
0
369
0
  // destRegion is now in logical coordinates relative to the buffer, but we
370
0
  // need to account for rotation. We do that by moving the region to the
371
0
  // rotation offset and then wrapping any pixels that extend off the
372
0
  // bottom/right edges.
373
0
374
0
  // Shift to the rotation point
375
0
  destRegion.MoveBy(aData.rotation());
376
0
377
0
  IntSize bufferSize = aData.rect().Size();
378
0
379
0
  // Select only the pixels that are still within the buffer.
380
0
  nsIntRegion finalRegion;
381
0
  finalRegion.And(IntRect(IntPoint(), bufferSize), destRegion);
382
0
383
0
  // For each of the overlap areas (right, bottom-right, bottom), select those
384
0
  // pixels and wrap them around to the opposite edge of the buffer rect.
385
0
  AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().Width(), 0));
386
0
  AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(aData.rect().Width(), aData.rect().Height()));
387
0
  AddWrappedRegion(destRegion, finalRegion, bufferSize, nsIntPoint(0, aData.rect().Height()));
388
0
389
0
  MOZ_ASSERT(IntRect(0, 0, aData.rect().Width(), aData.rect().Height()).Contains(finalRegion.GetBounds()));
390
0
391
0
  mTextureHost->Updated(&finalRegion);
392
0
  if (mTextureHostOnWhite) {
393
0
    mTextureHostOnWhite->Updated(&finalRegion);
394
0
  }
395
0
  mInitialised = true;
396
0
397
0
  mBufferRect = aData.rect();
398
0
  mBufferRotation = aData.rotation();
399
0
400
0
  return true;
401
0
}
402
403
bool
404
ContentHostDoubleBuffered::UpdateThebes(const ThebesBufferData& aData,
405
                                        const nsIntRegion& aUpdated,
406
                                        const nsIntRegion& aOldValidRegionBack)
407
0
{
408
0
  if (!mTextureHost) {
409
0
    mInitialised = false;
410
0
    return true;
411
0
  }
412
0
413
0
  // We don't need to calculate an update region because we assume that if we
414
0
  // are using double buffering then we have render-to-texture and thus no
415
0
  // upload to do.
416
0
  mTextureHost->Updated();
417
0
  if (mTextureHostOnWhite) {
418
0
    mTextureHostOnWhite->Updated();
419
0
  }
420
0
  mInitialised = true;
421
0
422
0
  mBufferRect = aData.rect();
423
0
  mBufferRotation = aData.rotation();
424
0
425
0
  // Save the current valid region of our front buffer, because if
426
0
  // we're double buffering, it's going to be the valid region for the
427
0
  // next back buffer sent back to the renderer.
428
0
  //
429
0
  // NB: we rely here on the fact that mValidRegion is initialized to
430
0
  // empty, and that the first time Swap() is called we don't have a
431
0
  // valid front buffer that we're going to return to content.
432
0
  mValidRegionForNextBackBuffer = aOldValidRegionBack;
433
0
434
0
  return true;
435
0
}
436
437
void
438
ContentHostTexture::PrintInfo(std::stringstream& aStream, const char* aPrefix)
439
0
{
440
0
  aStream << aPrefix;
441
0
  aStream << nsPrintfCString("ContentHost (0x%p)", this).get();
442
0
443
0
  AppendToString(aStream, mBufferRect, " [buffer-rect=", "]");
444
0
  AppendToString(aStream, mBufferRotation, " [buffer-rotation=", "]");
445
0
  if (PaintWillResample()) {
446
0
    aStream << " [paint-will-resample]";
447
0
  }
448
0
449
0
  if (mTextureHost) {
450
0
    nsAutoCString pfx(aPrefix);
451
0
    pfx += "  ";
452
0
453
0
    aStream << "\n";
454
0
    mTextureHost->PrintInfo(aStream, pfx.get());
455
0
  }
456
0
}
457
458
459
already_AddRefed<TexturedEffect>
460
ContentHostTexture::GenEffect(const gfx::SamplingFilter aSamplingFilter)
461
0
{
462
0
  if (!mTextureHost) {
463
0
    return nullptr;
464
0
  }
465
0
  if (!mTextureHost->BindTextureSource(mTextureSource)) {
466
0
    return nullptr;
467
0
  }
468
0
  if (!mTextureHostOnWhite) {
469
0
    mTextureSourceOnWhite = nullptr;
470
0
  }
471
0
  if (mTextureHostOnWhite && !mTextureHostOnWhite->BindTextureSource(mTextureSourceOnWhite)) {
472
0
    return nullptr;
473
0
  }
474
0
  return CreateTexturedEffect(mTextureSource.get(),
475
0
                              mTextureSourceOnWhite.get(),
476
0
                              aSamplingFilter, true);
477
0
}
478
479
already_AddRefed<gfx::DataSourceSurface>
480
ContentHostTexture::GetAsSurface()
481
0
{
482
0
  if (!mTextureHost) {
483
0
    return nullptr;
484
0
  }
485
0
486
0
  return mTextureHost->GetAsSurface();
487
0
}
488
489
490
} // namespace layers
491
} // namespace mozilla