Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/ReadbackProcessor.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 "ReadbackProcessor.h"
8
#include <sys/types.h>                  // for int32_t
9
#include "Layers.h"                     // for Layer, PaintedLayer, etc
10
#include "ReadbackLayer.h"              // for ReadbackLayer, ReadbackSink
11
#include "UnitTransforms.h"             // for ViewAs
12
#include "Units.h"                      // for ParentLayerIntRect
13
#include "gfxContext.h"                 // for gfxContext
14
#include "gfxUtils.h"
15
#include "gfxRect.h"                    // for gfxRect
16
#include "mozilla/gfx/2D.h"
17
#include "mozilla/gfx/BasePoint.h"      // for BasePoint
18
#include "mozilla/gfx/BaseRect.h"       // for BaseRect
19
#include "mozilla/gfx/Point.h"          // for Intsize
20
#include "nsDebug.h"                    // for NS_ASSERTION
21
#include "nsISupportsImpl.h"            // for gfxContext::Release, etc
22
#include "nsPoint.h"                    // for nsIntPoint
23
#include "nsRegion.h"                   // for nsIntRegion
24
25
using namespace mozilla::gfx;
26
27
namespace mozilla {
28
namespace layers {
29
30
void
31
ReadbackProcessor::BuildUpdates(ContainerLayer* aContainer)
32
0
{
33
0
  NS_ASSERTION(mAllUpdates.IsEmpty(), "Some updates not processed?");
34
0
35
0
  if (!aContainer->mMayHaveReadbackChild)
36
0
    return;
37
0
38
0
  aContainer->mMayHaveReadbackChild = false;
39
0
  // go backwards so the updates read from earlier layers are later in the
40
0
  // array.
41
0
  for (Layer* l = aContainer->GetLastChild(); l; l = l->GetPrevSibling()) {
42
0
    if (l->GetType() == Layer::TYPE_READBACK) {
43
0
      aContainer->mMayHaveReadbackChild = true;
44
0
      BuildUpdatesForLayer(static_cast<ReadbackLayer*>(l));
45
0
    }
46
0
  }
47
0
}
48
49
static Layer*
50
FindBackgroundLayer(ReadbackLayer* aLayer, nsIntPoint* aOffset)
51
0
{
52
0
  gfx::Matrix transform;
53
0
  if (!aLayer->GetTransform().Is2D(&transform) ||
54
0
      transform.HasNonIntegerTranslation())
55
0
    return nullptr;
56
0
  nsIntPoint transformOffset(int32_t(transform._31), int32_t(transform._32));
57
0
58
0
  for (Layer* l = aLayer->GetPrevSibling(); l; l = l->GetPrevSibling()) {
59
0
    gfx::Matrix backgroundTransform;
60
0
    if (!l->GetTransform().Is2D(&backgroundTransform) ||
61
0
        gfx::ThebesMatrix(backgroundTransform).HasNonIntegerTranslation())
62
0
      return nullptr;
63
0
64
0
    nsIntPoint backgroundOffset(int32_t(backgroundTransform._31), int32_t(backgroundTransform._32));
65
0
    IntRect rectInBackground(transformOffset - backgroundOffset, aLayer->GetSize());
66
0
    const nsIntRegion visibleRegion = l->GetLocalVisibleRegion().ToUnknownRegion();
67
0
    if (!visibleRegion.Intersects(rectInBackground))
68
0
      continue;
69
0
    // Since l is present in the background, from here on we either choose l
70
0
    // or nothing.
71
0
    if (!visibleRegion.Contains(rectInBackground))
72
0
      return nullptr;
73
0
74
0
    if (l->GetEffectiveOpacity() != 1.0 ||
75
0
        l->HasMaskLayers() ||
76
0
        !(l->GetContentFlags() & Layer::CONTENT_OPAQUE))
77
0
    {
78
0
      return nullptr;
79
0
    }
80
0
81
0
    // cliprects are post-transform
82
0
    const Maybe<ParentLayerIntRect>& clipRect = l->GetLocalClipRect();
83
0
    if (clipRect && !clipRect->Contains(ViewAs<ParentLayerPixel>(IntRect(transformOffset, aLayer->GetSize()))))
84
0
      return nullptr;
85
0
86
0
    Layer::LayerType type = l->GetType();
87
0
    if (type != Layer::TYPE_COLOR && type != Layer::TYPE_PAINTED)
88
0
      return nullptr;
89
0
90
0
    *aOffset = backgroundOffset - transformOffset;
91
0
    return l;
92
0
  }
93
0
94
0
  return nullptr;
95
0
}
96
97
void
98
ReadbackProcessor::BuildUpdatesForLayer(ReadbackLayer* aLayer)
99
0
{
100
0
  if (!aLayer->mSink)
101
0
    return;
102
0
103
0
  nsIntPoint offset;
104
0
  Layer* newBackground = FindBackgroundLayer(aLayer, &offset);
105
0
  if (!newBackground) {
106
0
    aLayer->SetUnknown();
107
0
    return;
108
0
  }
109
0
110
0
  if (newBackground->GetType() == Layer::TYPE_COLOR) {
111
0
    ColorLayer* colorLayer = static_cast<ColorLayer*>(newBackground);
112
0
    if (aLayer->mBackgroundColor != colorLayer->GetColor()) {
113
0
      aLayer->mBackgroundLayer = nullptr;
114
0
      aLayer->mBackgroundColor = colorLayer->GetColor();
115
0
      NS_ASSERTION(aLayer->mBackgroundColor.a == 1.f,
116
0
                   "Color layer said it was opaque!");
117
0
      RefPtr<DrawTarget> dt =
118
0
          aLayer->mSink->BeginUpdate(aLayer->GetRect(),
119
0
                                     aLayer->AllocateSequenceNumber());
120
0
      if (dt) {
121
0
        ColorPattern color(ToDeviceColor(aLayer->mBackgroundColor));
122
0
        IntSize size = aLayer->GetSize();
123
0
        dt->FillRect(Rect(0, 0, size.width, size.height), color);
124
0
        aLayer->mSink->EndUpdate(aLayer->GetRect());
125
0
      }
126
0
    }
127
0
  } else {
128
0
    NS_ASSERTION(newBackground->AsPaintedLayer(), "Must be PaintedLayer");
129
0
    PaintedLayer* paintedLayer = static_cast<PaintedLayer*>(newBackground);
130
0
    // updateRect is relative to the PaintedLayer
131
0
    IntRect updateRect = aLayer->GetRect() - offset;
132
0
    if (paintedLayer != aLayer->mBackgroundLayer ||
133
0
        offset != aLayer->mBackgroundLayerOffset) {
134
0
      aLayer->mBackgroundLayer = paintedLayer;
135
0
      aLayer->mBackgroundLayerOffset = offset;
136
0
      aLayer->mBackgroundColor = Color();
137
0
      paintedLayer->SetUsedForReadback(true);
138
0
    } else {
139
0
      nsIntRegion invalid;
140
0
      invalid.Sub(updateRect, paintedLayer->GetValidRegion());
141
0
      updateRect = invalid.GetBounds();
142
0
    }
143
0
144
0
    Update update = { aLayer, updateRect, aLayer->AllocateSequenceNumber() };
145
0
    mAllUpdates.AppendElement(update);
146
0
  }
147
0
}
148
149
void
150
ReadbackProcessor::GetPaintedLayerUpdates(PaintedLayer* aLayer,
151
                                         nsTArray<Update>* aUpdates,
152
                                         nsIntRegion* aUpdateRegion)
153
0
{
154
0
  // All PaintedLayers used for readback are in mAllUpdates (some possibly
155
0
  // with an empty update rect).
156
0
  aLayer->SetUsedForReadback(false);
157
0
  if (aUpdateRegion) {
158
0
    aUpdateRegion->SetEmpty();
159
0
  }
160
0
  for (uint32_t i = mAllUpdates.Length(); i > 0; --i) {
161
0
    const Update& update = mAllUpdates[i - 1];
162
0
    if (update.mLayer->mBackgroundLayer == aLayer) {
163
0
      aLayer->SetUsedForReadback(true);
164
0
      // Don't bother asking for updates if we have an empty update rect.
165
0
      if (!update.mUpdateRect.IsEmpty()) {
166
0
        aUpdates->AppendElement(update);
167
0
        if (aUpdateRegion) {
168
0
          aUpdateRegion->Or(*aUpdateRegion, update.mUpdateRect);
169
0
        }
170
0
      }
171
0
      mAllUpdates.RemoveElementAt(i - 1);
172
0
    }
173
0
  }
174
0
}
175
176
ReadbackProcessor::~ReadbackProcessor()
177
0
{
178
0
  for (uint32_t i = mAllUpdates.Length(); i > 0; --i) {
179
0
    const Update& update = mAllUpdates[i - 1];
180
0
    // Unprocessed update. Notify the readback sink that this content is
181
0
    // unknown.
182
0
    update.mLayer->SetUnknown();
183
0
  }
184
0
}
185
186
} // namespace layers
187
} // namespace mozilla