| /* |
| * Copyright (C) 2019 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "LayerAncestorClippingStack.h" |
| |
| #include "GraphicsLayer.h" |
| #include "ScrollingConstraints.h" |
| #include "ScrollingCoordinator.h" |
| #include <wtf/text/TextStream.h> |
| |
| namespace WebCore { |
| |
| LayerAncestorClippingStack::LayerAncestorClippingStack(Vector<CompositedClipData>&& clipDataStack) |
| : m_stack(WTF::map(WTFMove(clipDataStack), [](auto&& clipDataEntry) { return ClippingStackEntry { WTFMove(clipDataEntry), 0, nullptr }; })) |
| { |
| } |
| |
| bool LayerAncestorClippingStack::equalToClipData(const Vector<CompositedClipData>& clipDataStack) const |
| { |
| if (m_stack.size() != clipDataStack.size()) |
| return false; |
| |
| for (unsigned i = 0; i < m_stack.size(); ++i) { |
| if (m_stack[i].clipData != clipDataStack[i]) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool LayerAncestorClippingStack::hasAnyScrollingLayers() const |
| { |
| for (const auto& entry : m_stack) { |
| if (entry.clipData.isOverflowScroll) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| void LayerAncestorClippingStack::clear(ScrollingCoordinator* scrollingCoordinator) |
| { |
| for (auto& entry : m_stack) { |
| if (entry.overflowScrollProxyNodeID) { |
| ASSERT(scrollingCoordinator); |
| scrollingCoordinator->unparentChildrenAndDestroyNode(entry.overflowScrollProxyNodeID); |
| entry.overflowScrollProxyNodeID = 0; |
| } |
| |
| GraphicsLayer::unparentAndClear(entry.clippingLayer); |
| } |
| } |
| |
| void LayerAncestorClippingStack::detachFromScrollingCoordinator(ScrollingCoordinator& scrollingCoordinator) |
| { |
| for (auto& entry : m_stack) { |
| if (entry.overflowScrollProxyNodeID) { |
| scrollingCoordinator.unparentChildrenAndDestroyNode(entry.overflowScrollProxyNodeID); |
| entry.overflowScrollProxyNodeID = 0; |
| } |
| } |
| } |
| |
| GraphicsLayer* LayerAncestorClippingStack::firstClippingLayer() const |
| { |
| return m_stack.first().clippingLayer.get(); |
| } |
| |
| GraphicsLayer* LayerAncestorClippingStack::lastClippingLayer() const |
| { |
| return m_stack.last().clippingLayer.get(); |
| } |
| |
| ScrollingNodeID LayerAncestorClippingStack::lastOverflowScrollProxyNodeID() const |
| { |
| for (auto& entry : makeReversedRange(m_stack)) { |
| if (entry.overflowScrollProxyNodeID) |
| return entry.overflowScrollProxyNodeID; |
| } |
| |
| return 0; |
| } |
| |
| void LayerAncestorClippingStack::updateScrollingNodeLayers(ScrollingCoordinator& scrollingCoordinator) |
| { |
| for (const auto& entry : m_stack) { |
| if (!entry.clipData.isOverflowScroll) |
| continue; |
| |
| scrollingCoordinator.setNodeLayers(entry.overflowScrollProxyNodeID, { entry.clippingLayer.get() }); |
| } |
| } |
| |
| bool LayerAncestorClippingStack::updateWithClipData(ScrollingCoordinator* scrollingCoordinator, Vector<CompositedClipData>&& clipDataStack) |
| { |
| bool stackChanged = false; |
| |
| int clipEntryCount = clipDataStack.size(); |
| int stackEntryCount = m_stack.size(); |
| for (int i = 0; i < clipEntryCount; ++i) { |
| auto& clipDataEntry = clipDataStack[i]; |
| |
| if (i >= stackEntryCount) { |
| m_stack.append({ WTFMove(clipDataEntry), 0, nullptr }); |
| stackChanged = true; |
| continue; |
| } |
| |
| auto& existingEntry = m_stack[i]; |
| |
| if (existingEntry.clipData != clipDataEntry) |
| stackChanged = true; |
| |
| if (existingEntry.clipData.isOverflowScroll && !clipDataEntry.isOverflowScroll) { |
| ASSERT(scrollingCoordinator); |
| scrollingCoordinator->unparentChildrenAndDestroyNode(existingEntry.overflowScrollProxyNodeID); |
| existingEntry.overflowScrollProxyNodeID = 0; |
| } |
| |
| existingEntry.clipData = WTFMove(clipDataEntry); |
| } |
| |
| if (stackEntryCount > clipEntryCount) { |
| for (int i = clipEntryCount; i < stackEntryCount; ++i) { |
| auto& entry = m_stack[i]; |
| if (entry.overflowScrollProxyNodeID) { |
| ASSERT(scrollingCoordinator); |
| scrollingCoordinator->unparentChildrenAndDestroyNode(entry.overflowScrollProxyNodeID); |
| } |
| GraphicsLayer::unparentAndClear(entry.clippingLayer); |
| } |
| |
| m_stack.shrink(clipEntryCount); |
| stackChanged = true; |
| } else |
| m_stack.shrinkToFit(); |
| |
| return stackChanged; |
| } |
| |
| Vector<CompositedClipData> LayerAncestorClippingStack::compositedClipData() const |
| { |
| return m_stack.map([](auto& entry) { |
| return entry.clipData; |
| }); |
| } |
| |
| static TextStream& operator<<(TextStream& ts, const LayerAncestorClippingStack::ClippingStackEntry& entry) |
| { |
| ts.dumpProperty("layer", entry.clipData.clippingLayer.get()); |
| ts.dumpProperty("clip", entry.clipData.clipRect); |
| ts.dumpProperty("isOverflowScroll", entry.clipData.isOverflowScroll); |
| if (entry.overflowScrollProxyNodeID) |
| ts.dumpProperty("overflowScrollProxyNodeID", entry.overflowScrollProxyNodeID); |
| if (entry.clippingLayer) |
| ts.dumpProperty("clippingLayer", entry.clippingLayer->primaryLayerID()); |
| return ts; |
| } |
| |
| TextStream& operator<<(TextStream& ts, const LayerAncestorClippingStack& clipStack) |
| { |
| TextStream multilineStream; |
| multilineStream.setIndent(ts.indent() + 2); |
| |
| { |
| TextStream::GroupScope scope(ts); |
| multilineStream << "LayerAncestorClippingStack"; |
| |
| for (unsigned i = 0; i < clipStack.stack().size(); ++i) { |
| auto& entry = clipStack.stack()[i]; |
| TextStream::GroupScope entryScope(multilineStream); |
| multilineStream << "entry " << i; |
| multilineStream << entry; |
| } |
| |
| ts << multilineStream.release(); |
| } |
| return ts; |
| } |
| |
| } // namespace WebCore |
| |