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