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/. */
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
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
25 using namespace mozilla::gfx
;
30 void ReadbackProcessor::BuildUpdates(ContainerLayer
* aContainer
) {
31 NS_ASSERTION(mAllUpdates
.IsEmpty(), "Some updates not processed?");
33 if (!aContainer
->mMayHaveReadbackChild
) return;
35 aContainer
->mMayHaveReadbackChild
= false;
36 // go backwards so the updates read from earlier layers are later in the
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
));
46 static Layer
* FindBackgroundLayer(ReadbackLayer
* aLayer
, nsIntPoint
* aOffset
) {
47 gfx::Matrix transform
;
48 if (!aLayer
->GetTransform().Is2D(&transform
) ||
49 transform
.HasNonIntegerTranslation())
51 nsIntPoint
transformOffset(int32_t(transform
._31
), int32_t(transform
._32
));
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())
59 nsIntPoint
backgroundOffset(int32_t(backgroundTransform
._31
),
60 int32_t(backgroundTransform
._32
));
61 IntRect
rectInBackground(transformOffset
- backgroundOffset
,
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
68 if (!visibleRegion
.Contains(rectInBackground
)) return nullptr;
70 if (l
->GetEffectiveOpacity() != 1.0 || l
->HasMaskLayers() ||
71 !(l
->GetContentFlags() & Layer::CONTENT_OPAQUE
)) {
75 // cliprects are post-transform
76 const Maybe
<ParentLayerIntRect
>& clipRect
= l
->GetLocalClipRect();
77 if (clipRect
&& !clipRect
->Contains(ViewAs
<ParentLayerPixel
>(
78 IntRect(transformOffset
, aLayer
->GetSize()))))
81 Layer::LayerType type
= l
->GetType();
82 if (type
!= Layer::TYPE_COLOR
&& type
!= Layer::TYPE_PAINTED
)
85 *aOffset
= backgroundOffset
- transformOffset
;
92 void ReadbackProcessor::BuildUpdatesForLayer(ReadbackLayer
* aLayer
) {
93 if (!aLayer
->mSink
) return;
96 Layer
* newBackground
= FindBackgroundLayer(aLayer
, &offset
);
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());
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());
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);
131 invalid
.Sub(updateRect
, paintedLayer
->GetValidRegion());
132 updateRect
= invalid
.GetBounds();
135 Update update
= {aLayer
, updateRect
, aLayer
->AllocateSequenceNumber()};
136 mAllUpdates
.AppendElement(update
);
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);
147 aUpdateRegion
->SetEmpty();
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
);
157 aUpdateRegion
->Or(*aUpdateRegion
, update
.mUpdateRect
);
160 mAllUpdates
.RemoveElementAt(i
- 1);
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
170 update
.mLayer
->SetUnknown();
174 } // namespace layers
175 } // namespace mozilla