Bug 1632310 [wpt PR 23186] - Add test for computed versus resolved style., a=testonly
[gecko.git] / gfx / layers / ReadbackProcessor.cpp
blob1e5e21c086a16b12ae554831f5047cdff31f2881
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
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
25 using namespace mozilla::gfx;
27 namespace mozilla {
28 namespace layers {
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
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));
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));
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;
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;
70 if (l->GetEffectiveOpacity() != 1.0 || l->HasMaskLayers() ||
71 !(l->GetContentFlags() & Layer::CONTENT_OPAQUE)) {
72 return nullptr;
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;
81 Layer::LayerType type = l->GetType();
82 if (type != Layer::TYPE_COLOR && type != Layer::TYPE_PAINTED)
83 return nullptr;
85 *aOffset = backgroundOffset - transformOffset;
86 return l;
89 return nullptr;
92 void ReadbackProcessor::BuildUpdatesForLayer(ReadbackLayer* aLayer) {
93 if (!aLayer->mSink) return;
95 nsIntPoint offset;
96 Layer* newBackground = FindBackgroundLayer(aLayer, &offset);
97 if (!newBackground) {
98 aLayer->SetUnknown();
99 return;
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());
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();
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);
146 if (aUpdateRegion) {
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);
156 if (aUpdateRegion) {
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
169 // unknown.
170 update.mLayer->SetUnknown();
174 } // namespace layers
175 } // namespace mozilla