[LFC] Add Display::Box::nonCollapsedMarginBox for verification purposes.
[WebKit-https.git] / Source / WebCore / layout / Verification.cpp
1 /*
2  * Copyright (C) 2018 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 "LayoutContext.h"
28
29 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
30
31 #include "DisplayBox.h"
32 #include "LayoutBox.h"
33 #include "LayoutContainer.h"
34 #include "LayoutTreeBuilder.h"
35 #include "RenderBox.h"
36 #include "RenderView.h"
37 #include <wtf/text/TextStream.h>
38
39 namespace WebCore {
40 namespace Layout {
41
42 static bool outputMismatchingBoxInformationIfNeeded(TextStream& stream, const LayoutContext& context, const RenderBox& renderer, const Box& layoutBox)
43 {
44     bool firstMismatchingRect = true;
45     auto outputRect = [&] (const String& prefix, const LayoutRect& rendererRect, const LayoutRect& layoutRect) {
46         if (firstMismatchingRect) {
47             stream << (renderer.element() ? renderer.element()->nodeName().utf8().data() : "") << " " << renderer.renderName() << "(" << &renderer << ") layoutBox(" << &layoutBox << ")";
48             stream.nextLine();
49             firstMismatchingRect = false;
50         }
51
52         stream  << prefix.utf8().data() << "\trenderer->(" << rendererRect.x() << "," << rendererRect.y() << ") (" << rendererRect.width() << "x" << rendererRect.height() << ")"
53             << "\tlayout->(" << layoutRect.x() << "," << layoutRect.y() << ") (" << layoutRect.width() << "x" << layoutRect.height() << ")"; 
54         stream.nextLine();
55     };
56
57     auto* displayBox = context.displayBoxForLayoutBox(layoutBox);
58     ASSERT(displayBox);
59
60     auto frameRect = renderer.frameRect();
61     // rendering does not offset for relative positioned boxes.
62     if (renderer.isInFlowPositioned())
63         frameRect.move(renderer.offsetForInFlowPosition());
64
65     if (frameRect != displayBox->rect()) {
66         outputRect("frameBox", renderer.frameRect(), displayBox->rect());
67         return true;
68     }
69
70 #ifndef NDEBUG
71     if (renderer.marginBoxRect() != displayBox->nonCollapsedMarginBox()) {
72         outputRect("marginBox", renderer.marginBoxRect(), displayBox->nonCollapsedMarginBox());
73         return true;
74     }
75 #else
76     // For now in non-debug builds, verify the horizontal margin only
77     if (renderer.marginBoxRect().left() != displayBox->marginBox().left()
78         || renderer.marginBoxRect().right() != displayBox->marginBox().right() ) {
79         outputRect("marginBox", renderer.marginBoxRect(), displayBox->marginBox());
80         return true;
81     }
82 #endif
83
84     if (renderer.borderBoxRect() != displayBox->borderBox()) {
85         outputRect("borderBox", renderer.borderBoxRect(), displayBox->borderBox());
86         return true;
87     }
88
89     if (renderer.paddingBoxRect() != displayBox->paddingBox()) {
90         outputRect("paddingBox", renderer.paddingBoxRect(), displayBox->paddingBox());
91         return true;
92     }
93
94     if (renderer.contentBoxRect() != displayBox->contentBox()) {
95         outputRect("contentBox", renderer.contentBoxRect(), displayBox->contentBox());
96         return true;
97     }
98
99     return false;
100 }
101
102 static bool verifyAndOutputSubtree(TextStream& stream, const LayoutContext& context, const RenderBox& renderer, const Box& layoutBox)
103 {
104     auto mismtachingGeometry = outputMismatchingBoxInformationIfNeeded(stream, context, renderer, layoutBox);
105
106     if (!is<Container>(layoutBox))
107         return mismtachingGeometry;
108
109     auto& container = downcast<Container>(layoutBox);
110     auto* childBox = container.firstChild();
111     auto* childRenderer = renderer.firstChild();
112
113     while (childRenderer) {
114         if (!is<RenderBox>(*childRenderer)) {
115             childRenderer = childRenderer->nextSibling();
116             continue;
117         }
118
119         auto mismatchingSubtreeGeometry = verifyAndOutputSubtree(stream, context, downcast<RenderBox>(*childRenderer), *childBox);
120         mismtachingGeometry |= mismatchingSubtreeGeometry;
121
122         childBox = childBox->nextSibling();
123         childRenderer = childRenderer->nextSibling();
124     }
125     return mismtachingGeometry;
126 }
127
128 void LayoutContext::verifyAndOutputMismatchingLayoutTree(const RenderView& renderView) const
129 {
130     TextStream stream;
131     auto mismatchingGeometry = verifyAndOutputSubtree(stream, *this, renderView, *m_root.get());
132 #if ENABLE(TREE_DEBUGGING)
133     if (mismatchingGeometry) {
134         showRenderTree(&renderView);
135         TreeBuilder::showLayoutTree(*this, *m_root.get());
136     }
137 #endif
138     WTFLogAlways("%s", stream.release().utf8().data());
139 }
140
141 }
142 }
143
144 #endif