[chromium] Compute occlusion during paint loop
[WebKit-https.git] / Source / WebKit / chromium / tests / TiledLayerChromiumTest.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26
27 #include "TiledLayerChromium.h"
28
29 #include "CCLayerTreeTestCommon.h"
30 #include "FakeCCLayerTreeHostClient.h"
31 #include "LayerTextureUpdater.h"
32 #include "Region.h"
33 #include "TextureManager.h"
34 #include "WebCompositor.h"
35 #include "cc/CCSingleThreadProxy.h" // For DebugScopedSetImplThread
36 #include "cc/CCTextureUpdater.h"
37 #include "cc/CCTiledLayerImpl.h"
38 #include <gtest/gtest.h>
39
40 using namespace WebCore;
41 using namespace WTF;
42
43 #define EXPECT_EQ_RECT(a, b) \
44     EXPECT_EQ(a.x(), b.x()); \
45     EXPECT_EQ(a.y(), b.y()); \
46     EXPECT_EQ(a.width(), b.width()); \
47     EXPECT_EQ(a.height(), b.height());
48
49 namespace {
50
51 class FakeTextureAllocator : public TextureAllocator {
52 public:
53     virtual unsigned createTexture(const IntSize&, GC3Denum) { return 0; }
54     virtual void deleteTexture(unsigned, const IntSize&, GC3Denum) { }
55 };
56
57 class FakeTiledLayerChromium;
58
59 class FakeLayerTextureUpdater : public LayerTextureUpdater {
60 public:
61     class Texture : public LayerTextureUpdater::Texture {
62     public:
63         Texture(PassOwnPtr<ManagedTexture> texture) : LayerTextureUpdater::Texture(texture) { }
64         virtual ~Texture() { }
65
66         virtual void updateRect(GraphicsContext3D*, TextureAllocator*, const IntRect&, const IntRect&) { }
67     };
68
69     FakeLayerTextureUpdater() : m_prepareCount(0) { }
70     virtual ~FakeLayerTextureUpdater() { }
71
72     // Sets the rect to invalidate during the next call to prepareToUpdate(). After the next
73     // call to prepareToUpdate() the rect is reset.
74     void setRectToInvalidate(const IntRect&, FakeTiledLayerChromium*);
75
76     // Number of times prepareToUpdate has been invoked.
77     int prepareCount() const { return m_prepareCount; }
78     void clearPrepareCount() { m_prepareCount = 0; }
79
80     void setOpaquePaintRect(const IntRect& opaquePaintRect) { m_opaquePaintRect = opaquePaintRect; }
81
82     // Last rect passed to prepareToUpdate().
83     const IntRect& lastUpdateRect()  const { return m_lastUpdateRect; }
84
85     virtual PassOwnPtr<LayerTextureUpdater::Texture> createTexture(TextureManager* manager) { return adoptPtr(new Texture(ManagedTexture::create(manager))); }
86     virtual SampledTexelFormat sampledTexelFormat(GC3Denum) { return SampledTexelFormatRGBA; }
87     virtual void prepareToUpdate(const IntRect& contentRect, const IntSize&, int, float, IntRect* resultingOpaqueRect);
88
89 private:
90     int m_prepareCount;
91     IntRect m_rectToInvalidate;
92     IntRect m_lastUpdateRect;
93     IntRect m_opaquePaintRect;
94     RefPtr<FakeTiledLayerChromium> m_layer;
95 };
96
97 class FakeCCTiledLayerImpl : public CCTiledLayerImpl {
98 public:
99     explicit FakeCCTiledLayerImpl(int id)
100         : CCTiledLayerImpl(id) { }
101     virtual ~FakeCCTiledLayerImpl() { }
102
103     bool hasTileAt(int i, int j)
104     {
105         return CCTiledLayerImpl::hasTileAt(i, j);
106     }
107 };
108
109 class FakeTiledLayerChromium : public TiledLayerChromium {
110 public:
111     explicit FakeTiledLayerChromium(TextureManager* textureManager)
112         : TiledLayerChromium()
113         , m_fakeTextureUpdater(adoptRef(new FakeLayerTextureUpdater))
114         , m_textureManager(textureManager)
115     {
116         setTileSize(IntSize(100, 100));
117         setTextureFormat(GraphicsContext3D::RGBA);
118         setBorderTexelOption(CCLayerTilingData::NoBorderTexels);
119         setIsDrawable(true); // So that we don't get false positives if any of these tests expect to return false from drawsContent() for other reasons.
120     }
121     virtual ~FakeTiledLayerChromium() { }
122
123     void invalidateRect(const IntRect& rect)
124     {
125         TiledLayerChromium::invalidateRect(rect);
126     }
127
128     void prepareToUpdate(const IntRect& rect)
129     {
130         TiledLayerChromium::prepareToUpdate(rect);
131     }
132
133     void prepareToUpdateIdle(const IntRect& rect)
134     {
135         TiledLayerChromium::prepareToUpdateIdle(rect);
136     }
137
138     bool needsIdlePaint(const IntRect& rect)
139     {
140         return TiledLayerChromium::needsIdlePaint(rect);
141     }
142
143     bool skipsDraw() const
144     {
145         return TiledLayerChromium::skipsDraw();
146     }
147
148     FakeLayerTextureUpdater* fakeLayerTextureUpdater() { return m_fakeTextureUpdater.get(); }
149
150     virtual TextureManager* textureManager() const { return m_textureManager; }
151
152     virtual void paintContentsIfDirty(const Region& /* occludedScreenSpace */)
153     {
154         prepareToUpdate(visibleLayerRect());
155     }
156
157 private:
158     virtual void createTextureUpdater(const CCLayerTreeHost*) { }
159
160     virtual LayerTextureUpdater* textureUpdater() const
161     {
162         return m_fakeTextureUpdater.get();
163     }
164
165     RefPtr<FakeLayerTextureUpdater> m_fakeTextureUpdater;
166     TextureManager* m_textureManager;
167 };
168
169 class FakeTiledLayerWithScaledBounds : public FakeTiledLayerChromium {
170 public:
171     explicit FakeTiledLayerWithScaledBounds(TextureManager* textureManager)
172         : FakeTiledLayerChromium(textureManager)
173     {
174     }
175
176     void setContentBounds(const IntSize& contentBounds) { m_forcedContentBounds = contentBounds; }
177     virtual IntSize contentBounds() const { return m_forcedContentBounds; }
178
179     FloatRect updateRect() { return m_updateRect; }
180
181 protected:
182     IntSize m_forcedContentBounds;
183 };
184
185 void FakeLayerTextureUpdater::setRectToInvalidate(const IntRect& rect, FakeTiledLayerChromium* layer)
186 {
187     m_rectToInvalidate = rect;
188     m_layer = layer;
189 }
190
191 void FakeLayerTextureUpdater::prepareToUpdate(const IntRect& contentRect, const IntSize&, int, float, IntRect* resultingOpaqueRect)
192 {
193     m_prepareCount++;
194     m_lastUpdateRect = contentRect;
195     if (!m_rectToInvalidate.isEmpty()) {
196         m_layer->invalidateRect(m_rectToInvalidate);
197         m_rectToInvalidate = IntRect();
198         m_layer = 0;
199     }
200     *resultingOpaqueRect = m_opaquePaintRect;
201 }
202
203 TEST(TiledLayerChromiumTest, pushDirtyTiles)
204 {
205     OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024);
206     RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
207     DebugScopedSetImplThread implThread;
208     RefPtr<FakeCCTiledLayerImpl> layerImpl = adoptRef(new FakeCCTiledLayerImpl(0));
209
210     FakeTextureAllocator textureAllocator;
211     CCTextureUpdater updater(&textureAllocator);
212
213     // The tile size is 100x100, so this invalidates and then paints two tiles.
214     layer->setBounds(IntSize(100, 200));
215     layer->invalidateRect(IntRect(0, 0, 100, 200));
216     layer->prepareToUpdate(IntRect(0, 0, 100, 200));
217     layer->updateCompositorResources(0, updater);
218     layer->pushPropertiesTo(layerImpl.get());
219
220     // We should have both tiles on the impl side.
221     EXPECT_TRUE(layerImpl->hasTileAt(0, 0));
222     EXPECT_TRUE(layerImpl->hasTileAt(0, 1));
223
224     textureManager->unprotectAllTextures();
225
226     // Invalidates both tiles...
227     layer->invalidateRect(IntRect(0, 0, 100, 200));
228     // ....but then only update one of them.
229     layer->prepareToUpdate(IntRect(0, 0, 100, 100));
230     layer->updateCompositorResources(0, updater);
231     layer->pushPropertiesTo(layerImpl.get());
232
233     // We should only have the first tile since the other tile was invalidated but not painted.
234     EXPECT_TRUE(layerImpl->hasTileAt(0, 0));
235     EXPECT_FALSE(layerImpl->hasTileAt(0, 1));
236 }
237
238 TEST(TiledLayerChromiumTest, pushIdlePaintTiles)
239 {
240     OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024);
241     RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
242     DebugScopedSetImplThread implThread;
243     RefPtr<FakeCCTiledLayerImpl> layerImpl = adoptRef(new FakeCCTiledLayerImpl(0));
244
245     FakeTextureAllocator textureAllocator;
246     CCTextureUpdater updater(&textureAllocator);
247
248     // The tile size is 100x100. Setup 5x5 tiles with one visible tile in the center.
249     IntSize contentBounds(500, 500);
250     IntRect contentRect(IntPoint::zero(), contentBounds);
251     IntRect visibleRect(200, 200, 100, 100);
252
253     // This invalidates 25 tiles and then paints one visible tile.
254     layer->setBounds(contentBounds);
255     layer->setVisibleLayerRect(visibleRect);
256     layer->invalidateRect(contentRect);
257     layer->prepareToUpdate(visibleRect);
258
259     // We should need idle-painting for 3x3 tiles in the center.
260     EXPECT_TRUE(layer->needsIdlePaint(visibleRect));
261
262     layer->updateCompositorResources(0, updater);
263     layer->pushPropertiesTo(layerImpl.get());
264
265     // We should have one tile on the impl side.
266     EXPECT_TRUE(layerImpl->hasTileAt(2, 2));
267
268     textureManager->unprotectAllTextures();
269
270     // For the next four updates, we should detect we still need idle painting.
271     for (int i = 0; i < 4; i++) {
272         layer->prepareToUpdate(visibleRect);
273         EXPECT_TRUE(layer->needsIdlePaint(visibleRect));
274         layer->prepareToUpdateIdle(visibleRect);
275         layer->updateCompositorResources(0, updater);
276         layer->pushPropertiesTo(layerImpl.get());
277         textureManager->unprotectAllTextures();
278     }
279
280     // After four passes of idle painting, we should be finished painting
281     EXPECT_FALSE(layer->needsIdlePaint(visibleRect));
282
283     // We should have one tile surrounding the visible tile on all sides, but no other tiles.
284     IntRect idlePaintTiles(1, 1, 3, 3);
285     for (int i = 0; i < 5; i++) {
286         for (int j = 0; j < 5; j++) {
287             if (idlePaintTiles.contains(i, j))
288                 EXPECT_TRUE(layerImpl->hasTileAt(i, j));
289             else
290                 EXPECT_FALSE(layerImpl->hasTileAt(i, j));
291         }
292     }
293 }
294
295
296 TEST(TiledLayerChromiumTest, idlePaintOutOfMemory)
297 {
298     // The tile size is 100x100. Setup 5x5 tiles with one 1x1 visible tile in the center.
299     IntSize contentBounds(300, 300);
300     IntRect contentRect(IntPoint::zero(), contentBounds);
301     IntRect visibleRect(100, 100, 100, 100);
302
303     // We have enough memory for only the visible rect, so we will run out of memory in first idle paint.
304     int memoryLimit = 4 * 100 * 100; // 2 tiles, 4 bytes per pixel.
305
306     OwnPtr<TextureManager> textureManager = TextureManager::create(memoryLimit, memoryLimit / 2, 1024);
307     RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
308     DebugScopedSetImplThread implThread;
309     RefPtr<FakeCCTiledLayerImpl> layerImpl = adoptRef(new FakeCCTiledLayerImpl(0));
310
311     FakeTextureAllocator textureAllocator;
312     CCTextureUpdater updater(&textureAllocator);
313
314     // This invalidates 9 tiles and then paints one visible tile.
315     layer->setBounds(contentBounds);
316     layer->setVisibleLayerRect(visibleRect);
317     layer->invalidateRect(contentRect);
318     layer->prepareToUpdate(visibleRect);
319
320     // We should need idle-painting for 3x3 tiles surounding visible tile.
321     EXPECT_TRUE(layer->needsIdlePaint(visibleRect));
322
323     layer->updateCompositorResources(0, updater);
324     layer->pushPropertiesTo(layerImpl.get());
325
326     // We should have one tile on the impl side.
327     EXPECT_TRUE(layerImpl->hasTileAt(1, 1));
328
329     textureManager->unprotectAllTextures();
330     layer->prepareToUpdate(visibleRect);
331     layer->prepareToUpdateIdle(visibleRect);
332
333     // We shouldn't signal we need another idle paint after we run out of memory.
334     EXPECT_FALSE(layer->needsIdlePaint(visibleRect));
335
336     layer->updateCompositorResources(0, updater);
337     layer->pushPropertiesTo(layerImpl.get());
338 }
339
340 TEST(TiledLayerChromiumTest, invalidateFromPrepare)
341 {
342     OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024);
343     RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
344     DebugScopedSetImplThread implThread;
345     RefPtr<FakeCCTiledLayerImpl> layerImpl = adoptRef(new FakeCCTiledLayerImpl(0));
346
347     FakeTextureAllocator textureAllocator;
348     CCTextureUpdater updater(&textureAllocator);
349
350     // The tile size is 100x100, so this invalidates and then paints two tiles.
351     layer->setBounds(IntSize(100, 200));
352     layer->invalidateRect(IntRect(0, 0, 100, 200));
353     layer->prepareToUpdate(IntRect(0, 0, 100, 200));
354     layer->updateCompositorResources(0, updater);
355     layer->pushPropertiesTo(layerImpl.get());
356
357     // We should have both tiles on the impl side.
358     EXPECT_TRUE(layerImpl->hasTileAt(0, 0));
359     EXPECT_TRUE(layerImpl->hasTileAt(0, 1));
360
361     textureManager->unprotectAllTextures();
362
363     layer->fakeLayerTextureUpdater()->clearPrepareCount();
364     // Invoke prepareToUpdate again. As the layer is valid prepareToUpdate shouldn't be invoked on
365     // the LayerTextureUpdater.
366     layer->prepareToUpdate(IntRect(0, 0, 100, 200));
367     EXPECT_EQ(0, layer->fakeLayerTextureUpdater()->prepareCount());
368
369     layer->invalidateRect(IntRect(0, 0, 50, 50));
370     // setRectToInvalidate triggers invalidateRect() being invoked from prepareToUpdate.
371     layer->fakeLayerTextureUpdater()->setRectToInvalidate(IntRect(25, 25, 50, 50), layer.get());
372     layer->fakeLayerTextureUpdater()->clearPrepareCount();
373     layer->prepareToUpdate(IntRect(0, 0, 100, 200));
374     EXPECT_EQ(1, layer->fakeLayerTextureUpdater()->prepareCount());
375     layer->fakeLayerTextureUpdater()->clearPrepareCount();
376     // The layer should still be invalid as prepareToUpdate invoked invalidate.
377     layer->prepareToUpdate(IntRect(0, 0, 100, 200));
378     EXPECT_EQ(1, layer->fakeLayerTextureUpdater()->prepareCount());
379 }
380
381 TEST(TiledLayerChromiumTest, verifyUpdateRectWhenContentBoundsAreScaled)
382 {
383     // The updateRect (that indicates what was actually painted) should be in
384     // layer space, not the content space.
385
386     OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024);
387     RefPtr<FakeTiledLayerWithScaledBounds> layer = adoptRef(new FakeTiledLayerWithScaledBounds(textureManager.get()));
388
389     FakeTextureAllocator textureAllocator;
390     CCTextureUpdater updater(&textureAllocator);
391
392     IntRect layerBounds(0, 0, 300, 200);
393     IntRect contentBounds(0, 0, 200, 250);
394
395     layer->setBounds(layerBounds.size());
396     layer->setContentBounds(contentBounds.size());
397     layer->setVisibleLayerRect(contentBounds);
398
399     // On first update, the updateRect includes all tiles, even beyond the boundaries of the layer.
400     // However, it should still be in layer space, not content space.
401     layer->invalidateRect(contentBounds);
402     layer->prepareToUpdate(contentBounds);
403     layer->updateCompositorResources(0, updater);
404     EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 300, 300 * 0.8), layer->updateRect());
405
406     // After the tiles are updated once, another invalidate only needs to update the bounds of the layer.
407     layer->invalidateRect(contentBounds);
408     layer->prepareToUpdate(contentBounds);
409     layer->updateCompositorResources(0, updater);
410     EXPECT_FLOAT_RECT_EQ(FloatRect(layerBounds), layer->updateRect());
411
412     // Partial re-paint should also be represented by the updateRect in layer space, not content space.
413     IntRect partialDamage(30, 100, 10, 10);
414     layer->invalidateRect(partialDamage);
415     layer->prepareToUpdate(contentBounds);
416     layer->updateCompositorResources(0, updater);
417     EXPECT_FLOAT_RECT_EQ(FloatRect(45, 80, 15, 8), layer->updateRect());
418 }
419
420 TEST(TiledLayerChromiumTest, skipsDrawGetsReset)
421 {
422     // Initialize without threading support.
423     WebKit::WebCompositor::initialize(0);
424     FakeCCLayerTreeHostClient fakeCCLayerTreeHostClient;
425     RefPtr<CCLayerTreeHost> ccLayerTreeHost = CCLayerTreeHost::create(&fakeCCLayerTreeHostClient, CCSettings());
426
427     // Create two 300 x 300 tiled layers.
428     IntSize contentBounds(300, 300);
429     IntRect contentRect(IntPoint::zero(), contentBounds);
430
431     RefPtr<FakeTiledLayerChromium> rootLayer = adoptRef(new FakeTiledLayerChromium(ccLayerTreeHost->contentsTextureManager()));
432     RefPtr<FakeTiledLayerChromium> childLayer = adoptRef(new FakeTiledLayerChromium(ccLayerTreeHost->contentsTextureManager()));
433     rootLayer->addChild(childLayer);
434
435     rootLayer->setBounds(contentBounds);
436     rootLayer->setPosition(FloatPoint(150, 150));
437     childLayer->setBounds(contentBounds);
438     childLayer->setPosition(FloatPoint(150, 150));
439     rootLayer->invalidateRect(contentRect);
440     childLayer->invalidateRect(contentRect);
441
442     // We have enough memory for only one of the two layers.
443     int memoryLimit = 4 * 300 * 300; // 4 bytes per pixel.
444
445     FakeTextureAllocator textureAllocator;
446     CCTextureUpdater updater(&textureAllocator);
447
448     ccLayerTreeHost->setRootLayer(rootLayer);
449     ccLayerTreeHost->setViewportSize(IntSize(300, 300));
450     ccLayerTreeHost->contentsTextureManager()->setMaxMemoryLimitBytes(memoryLimit);
451     ccLayerTreeHost->updateLayers();
452     ccLayerTreeHost->updateCompositorResources(ccLayerTreeHost->context(), updater);
453
454     // We'll skip the root layer.
455     EXPECT_TRUE(rootLayer->skipsDraw());
456     EXPECT_FALSE(childLayer->skipsDraw());
457
458     ccLayerTreeHost->commitComplete();
459
460     // Remove the child layer.
461     rootLayer->removeAllChildren();
462
463     // Need to set the max limit again as it gets overwritten by updateLayers().
464     ccLayerTreeHost->contentsTextureManager()->setMaxMemoryLimitBytes(memoryLimit);
465     ccLayerTreeHost->updateLayers();
466     EXPECT_FALSE(rootLayer->skipsDraw());
467
468     ccLayerTreeHost->setRootLayer(0);
469     ccLayerTreeHost.clear();
470     WebKit::WebCompositor::shutdown();
471 }
472
473 TEST(TiledLayerChromiumTest, layerAddsSelfToOccludedRegion)
474 {
475     OwnPtr<TextureManager> textureManager = TextureManager::create(4*1024*1024, 2*1024*1024, 1024);
476     RefPtr<FakeTiledLayerChromium> layer = adoptRef(new FakeTiledLayerChromium(textureManager.get()));
477
478     // The tile size is 100x100, so this invalidates and then paints two tiles in various ways.
479
480     Region occluded;
481     IntRect contentBounds = IntRect(0, 0, 100, 200);
482     IntRect visibleBounds = IntRect(0, 0, 100, 150);
483
484     layer->setBounds(contentBounds.size());
485     layer->setVisibleLayerRect(visibleBounds);
486     layer->setDrawOpacity(1);
487
488     // The screenSpaceTransform is verified in CCLayerTreeHostCommonTests
489     TransformationMatrix screenSpaceTransform;
490     layer->setScreenSpaceTransform(screenSpaceTransform);
491
492     // If the layer is opaque then the occluded region should be the whole layer's visible region.
493     layer->setOpaque(true);
494     layer->invalidateRect(contentBounds);
495     layer->prepareToUpdate(contentBounds);
496
497     occluded = Region();
498     layer->addSelfToOccludedScreenSpace(occluded);
499     EXPECT_EQ_RECT(visibleBounds, occluded.bounds());
500     EXPECT_EQ(1u, occluded.rects().size());
501
502     // If the layer is not opaque then the occluded region should be empty.
503     layer->setOpaque(false);
504     layer->invalidateRect(contentBounds);
505     layer->prepareToUpdate(contentBounds);
506
507     occluded = Region();
508     layer->addSelfToOccludedScreenSpace(occluded);
509     EXPECT_EQ_RECT(IntRect(), occluded.bounds());
510     EXPECT_EQ(1u, occluded.rects().size());
511
512     // If the layer paints opaque content, then the occluded region should match the visible opaque content.
513     IntRect opaquePaintRect = IntRect(10, 10, 90, 190);
514     layer->fakeLayerTextureUpdater()->setOpaquePaintRect(opaquePaintRect);
515     layer->invalidateRect(contentBounds);
516     layer->prepareToUpdate(contentBounds);
517
518     occluded = Region();
519     layer->addSelfToOccludedScreenSpace(occluded);
520     EXPECT_EQ_RECT(intersection(opaquePaintRect, visibleBounds), occluded.bounds());
521     EXPECT_EQ(1u, occluded.rects().size());
522
523     // If we paint again without invalidating, the same stuff should be occluded.
524     layer->fakeLayerTextureUpdater()->setOpaquePaintRect(IntRect());
525     layer->prepareToUpdate(contentBounds);
526
527     occluded = Region();
528     layer->addSelfToOccludedScreenSpace(occluded);
529     EXPECT_EQ_RECT(intersection(opaquePaintRect, visibleBounds), occluded.bounds());
530     EXPECT_EQ(1u, occluded.rects().size());
531
532     // If the layer is transformed then the resulting occluded area needs to be transformed to its target space.
533     TransformationMatrix transform;
534     transform.translate(contentBounds.width() / 2.0, contentBounds.height() / 2.0);
535     transform.rotate(90);
536     transform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0);
537     transform.translate(10, 10);
538     screenSpaceTransform.translate(contentBounds.width() / 2.0, contentBounds.height() / 2.0);
539     screenSpaceTransform *= transform;
540     screenSpaceTransform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0);
541     layer->setScreenSpaceTransform(screenSpaceTransform);
542     layer->prepareToUpdate(contentBounds);
543
544     occluded = Region();
545     layer->addSelfToOccludedScreenSpace(occluded);
546     EXPECT_EQ_RECT(screenSpaceTransform.mapRect(intersection(opaquePaintRect, visibleBounds)), occluded.bounds());
547     EXPECT_EQ(1u, occluded.rects().size());
548
549     // But a non-axis-aligned transform does not get considered for occlusion.
550     transform.translate(contentBounds.width() / 2.0, contentBounds.height() / 2.0);
551     transform.rotate(5);
552     transform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0);
553     screenSpaceTransform.translate(contentBounds.width() / 2.0, contentBounds.height() / 2.0);
554     screenSpaceTransform *= transform;
555     screenSpaceTransform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0);
556     layer->setScreenSpaceTransform(screenSpaceTransform);
557     layer->prepareToUpdate(contentBounds);
558
559     occluded = Region();
560     layer->addSelfToOccludedScreenSpace(occluded);
561     // FIXME: If we find an opaque rect contained in the rotated non-axis-aligned rect, then
562     // this won't be an empty result.
563     EXPECT_EQ_RECT(IntRect(), occluded.bounds());
564     EXPECT_EQ(0u, occluded.rects().size());
565 }
566
567 } // namespace