1/*
2 * Copyright (C) 2019 Apple 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''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "LayerOverlapMap.h"
28#include <wtf/text/TextStream.h>
29
30namespace WebCore {
31
32struct RectList {
33 Vector<LayoutRect> rects;
34 LayoutRect boundingRect;
35
36 void append(const LayoutRect& rect)
37 {
38 rects.append(rect);
39 boundingRect.unite(rect);
40 }
41
42 void append(const RectList& rectList)
43 {
44 rects.appendVector(rectList.rects);
45 boundingRect.unite(rectList.boundingRect);
46 }
47
48 bool intersects(const LayoutRect& rect) const
49 {
50 if (!rects.size() || !rect.intersects(boundingRect))
51 return false;
52
53 for (const auto& currentRect : rects) {
54 if (currentRect.intersects(rect))
55 return true;
56 }
57 return false;
58 }
59};
60
61class OverlapMapContainer {
62public:
63 void add(const LayoutRect& bounds)
64 {
65 m_rectList.append(bounds);
66 }
67
68 bool overlapsLayers(const LayoutRect& bounds) const
69 {
70 return m_rectList.intersects(bounds);
71 }
72
73 void unite(const OverlapMapContainer& otherContainer)
74 {
75 m_rectList.append(otherContainer.m_rectList);
76 }
77
78 const RectList& rectList() const { return m_rectList; }
79
80private:
81 RectList m_rectList;
82};
83
84LayerOverlapMap::LayerOverlapMap()
85 : m_geometryMap(UseTransforms)
86{
87 // Begin assuming the root layer will be composited so that there is
88 // something on the stack. The root layer should also never get an
89 // popCompositingContainer call.
90 pushCompositingContainer();
91}
92
93LayerOverlapMap::~LayerOverlapMap() = default;
94
95void LayerOverlapMap::add(const LayoutRect& bounds)
96{
97 // Layers do not contribute to overlap immediately--instead, they will
98 // contribute to overlap as soon as their composited ancestor has been
99 // recursively processed and popped off the stack.
100 ASSERT(m_overlapStack.size() >= 2);
101 m_overlapStack[m_overlapStack.size() - 2]->add(bounds);
102 m_isEmpty = false;
103}
104
105bool LayerOverlapMap::overlapsLayers(const LayoutRect& bounds) const
106{
107 return m_overlapStack.last()->overlapsLayers(bounds);
108}
109
110void LayerOverlapMap::pushCompositingContainer()
111{
112 m_overlapStack.append(std::make_unique<OverlapMapContainer>());
113}
114
115void LayerOverlapMap::popCompositingContainer()
116{
117 m_overlapStack[m_overlapStack.size() - 2]->unite(*m_overlapStack.last());
118 m_overlapStack.removeLast();
119}
120
121static TextStream& operator<<(TextStream& ts, const RectList& rectList)
122{
123 ts << "bounds " << rectList.boundingRect << " (" << rectList.rects << " rects)";
124 return ts;
125}
126
127static TextStream& operator<<(TextStream& ts, const OverlapMapContainer& container)
128{
129 ts << container.rectList();
130 return ts;
131}
132
133TextStream& operator<<(TextStream& ts, const LayerOverlapMap& overlapMap)
134{
135 TextStream multilineStream;
136
137 TextStream::GroupScope scope(ts);
138 multilineStream << indent << "LayerOverlapMap\n";
139
140 for (auto& container : overlapMap.overlapStack())
141 multilineStream << " " << *container << "\n";
142
143 ts << multilineStream.release();
144 return ts;
145}
146
147} // namespace WebCore
148