c7fd79079cbae4275d3488d635ce4170fc552de3
[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     if (renderer.marginBoxRect() != displayBox->marginBox()) {
71         outputRect("marginBox", renderer.marginBoxRect(), displayBox->marginBox());
72         return true;
73     }
74
75     if (renderer.borderBoxRect() != displayBox->borderBox()) {
76         outputRect("borderBox", renderer.borderBoxRect(), displayBox->borderBox());
77         return true;
78     }
79
80     if (renderer.paddingBoxRect() != displayBox->paddingBox()) {
81         outputRect("paddingBox", renderer.paddingBoxRect(), displayBox->paddingBox());
82         return true;
83     }
84
85     if (renderer.contentBoxRect() != displayBox->contentBox()) {
86         outputRect("contentBox", renderer.contentBoxRect(), displayBox->contentBox());
87         return true;
88     }
89
90     return false;
91 }
92
93 static bool verifyAndOutputSubtree(TextStream& stream, const LayoutContext& context, const RenderBox& renderer, const Box& layoutBox)
94 {
95     auto mismtachingGeometry = outputMismatchingBoxInformationIfNeeded(stream, context, renderer, layoutBox);
96
97     if (!is<Container>(layoutBox))
98         return mismtachingGeometry;
99
100     auto& container = downcast<Container>(layoutBox);
101     auto* childBox = container.firstChild();
102     auto* childRenderer = renderer.firstChild();
103
104     while (childRenderer) {
105         if (!is<RenderBox>(*childRenderer)) {
106             childRenderer = childRenderer->nextSibling();
107             continue;
108         }
109
110         auto mismatchingSubtreeGeometry = verifyAndOutputSubtree(stream, context, downcast<RenderBox>(*childRenderer), *childBox);
111         mismtachingGeometry |= mismatchingSubtreeGeometry;
112
113         childBox = childBox->nextSibling();
114         childRenderer = childRenderer->nextSibling();
115     }
116     return mismtachingGeometry;
117 }
118
119 void LayoutContext::verifyAndOutputMismatchingLayoutTree(const RenderView& renderView) const
120 {
121     TextStream stream;
122     auto mismatchingGeometry = verifyAndOutputSubtree(stream, *this, renderView, *m_root.get());
123 #if ENABLE(TREE_DEBUGGING)
124     if (mismatchingGeometry) {
125         showRenderTree(&renderView);
126         TreeBuilder::showLayoutTree(*this, *m_root.get());
127     }
128 #endif
129     WTFLogAlways("%s", stream.release().utf8().data());
130 }
131
132 }
133 }
134
135 #endif