Source code

Revision control

Other Tools

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