Release-assert NoEventDispatchAssertion in canExecute, updateLayout, and updateStyle
[WebKit-https.git] / Source / WebCore / dom / NoEventDispatchAssertion.h
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004-2016 Apple Inc. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #pragma once
25
26 #include "ContainerNode.h"
27 #include <wtf/MainThread.h>
28
29 namespace WebCore {
30
31 class NoEventDispatchAssertion {
32 public:
33     // This variant is expensive. Use NoEventDispatchAssertion::InMainThread whenever possible.
34     NoEventDispatchAssertion()
35     {
36         if (!isMainThread())
37             return;
38         ++s_count;
39     }
40
41     NoEventDispatchAssertion(const NoEventDispatchAssertion&)
42         : NoEventDispatchAssertion()
43     {
44     }
45
46     ~NoEventDispatchAssertion()
47     {
48         if (!isMainThread())
49             return;
50         ASSERT(s_count);
51         s_count--;
52     }
53
54     static bool isEventAllowedInMainThread()
55     {
56         return !isMainThread() || !s_count;
57     }
58
59     class InMainThread {
60     public:
61         InMainThread()
62         {
63             ASSERT(isMainThread());
64             ++s_count;
65         }
66
67         ~InMainThread()
68         {
69             ASSERT(isMainThread());
70             ASSERT(s_count);
71             --s_count;
72         }
73
74         // Don't enable this assertion in release since it's O(n).
75         // Release asserts in canExecuteScript should be sufficient for security defense purposes.
76         static bool isEventDispatchAllowedInSubtree(Node& node)
77         {
78 #if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS)
79             return isEventAllowed() || EventAllowedScope::isAllowedNode(node);
80 #else
81             UNUSED_PARAM(node);
82             return true;
83 #endif
84         }
85
86         static bool isEventAllowed()
87         {
88             ASSERT(isMainThread());
89             return !s_count;
90         }
91     };
92     
93 #if !ASSERT_DISABLED
94     class EventAllowedScope {
95     public:
96         explicit EventAllowedScope(ContainerNode& userAgentContentRoot)
97             : m_eventAllowedTreeRoot(userAgentContentRoot)
98             , m_previousScope(s_currentScope)
99         {
100             s_currentScope = this;
101         }
102
103         ~EventAllowedScope()
104         {
105             s_currentScope = m_previousScope;
106         }
107
108         static bool isAllowedNode(Node& node)
109         {
110             return s_currentScope && s_currentScope->isAllowedNodeInternal(node);
111         }
112
113     private:
114         bool isAllowedNodeInternal(Node& node)
115         {
116             return m_eventAllowedTreeRoot->contains(&node) || (m_previousScope && m_previousScope->isAllowedNodeInternal(node));
117         }
118
119         Ref<ContainerNode> m_eventAllowedTreeRoot;
120
121         EventAllowedScope* m_previousScope;
122         static EventAllowedScope* s_currentScope;
123     };
124 #else
125     class EventAllowedScope {
126     public:
127         explicit EventAllowedScope(ContainerNode&) { }
128         static bool isAllowedNode(Node&) { return true; }
129     };
130 #endif
131
132     // FIXME: Remove this class once the sync layout inside SVGImage::draw is removed.
133     class DisableAssertionsInScope {
134     public:
135         DisableAssertionsInScope()
136         {
137             ASSERT(isMainThread());
138             std::swap(s_count, m_originalCount);
139         }
140
141         ~DisableAssertionsInScope()
142         {
143             s_count = m_originalCount;
144         }
145     private:
146         unsigned m_originalCount { 0 };
147     };
148
149 private:
150     WEBCORE_EXPORT static unsigned s_count;
151 };
152
153 } // namespace WebCore