RenderTheme does not need to be per-page
[WebKit-https.git] / Source / WebCore / css / CSSDefaultStyleSheets.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5  * Copyright (C) 2005-2017 Apple Inc. All rights reserved.
6  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7  * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9  * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
11  * Copyright (C) 2012 Google Inc. All rights reserved.
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Library General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Library General Public License for more details.
22  *
23  * You should have received a copy of the GNU Library General Public License
24  * along with this library; see the file COPYING.LIB.  If not, write to
25  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26  * Boston, MA 02110-1301, USA.
27  */
28
29 #include "config.h"
30 #include "CSSDefaultStyleSheets.h"
31
32 #include "Chrome.h"
33 #include "ChromeClient.h"
34 #include "HTMLAnchorElement.h"
35 #include "HTMLAudioElement.h"
36 #include "HTMLBRElement.h"
37 #include "HTMLBodyElement.h"
38 #include "HTMLDivElement.h"
39 #include "HTMLEmbedElement.h"
40 #include "HTMLHeadElement.h"
41 #include "HTMLHtmlElement.h"
42 #include "HTMLObjectElement.h"
43 #include "HTMLSpanElement.h"
44 #include "MathMLElement.h"
45 #include "MediaQueryEvaluator.h"
46 #include "Page.h"
47 #include "RenderTheme.h"
48 #include "RuleSet.h"
49 #include "RuntimeEnabledFeatures.h"
50 #include "SVGElement.h"
51 #include "StyleSheetContents.h"
52 #include "UserAgentStyleSheets.h"
53 #include <wtf/NeverDestroyed.h>
54
55 namespace WebCore {
56
57 using namespace HTMLNames;
58
59 RuleSet* CSSDefaultStyleSheets::defaultStyle;
60 RuleSet* CSSDefaultStyleSheets::defaultQuirksStyle;
61 RuleSet* CSSDefaultStyleSheets::defaultPrintStyle;
62 unsigned CSSDefaultStyleSheets::defaultStyleVersion;
63
64 StyleSheetContents* CSSDefaultStyleSheets::simpleDefaultStyleSheet;
65 StyleSheetContents* CSSDefaultStyleSheets::defaultStyleSheet;
66 StyleSheetContents* CSSDefaultStyleSheets::quirksStyleSheet;
67 StyleSheetContents* CSSDefaultStyleSheets::svgStyleSheet;
68 StyleSheetContents* CSSDefaultStyleSheets::mathMLStyleSheet;
69 StyleSheetContents* CSSDefaultStyleSheets::mediaControlsStyleSheet;
70 StyleSheetContents* CSSDefaultStyleSheets::fullscreenStyleSheet;
71 StyleSheetContents* CSSDefaultStyleSheets::plugInsStyleSheet;
72 StyleSheetContents* CSSDefaultStyleSheets::imageControlsStyleSheet;
73
74 // FIXME: It would be nice to use some mechanism that guarantees this is in sync with the real UA stylesheet.
75 static const char* simpleUserAgentStyleSheet = "html,body,div{display:block}head{display:none}body{margin:8px}div:focus,span:focus,a:focus{outline:auto 5px -webkit-focus-ring-color}a:any-link{color:-webkit-link;text-decoration:underline}a:any-link:active{color:-webkit-activelink}";
76
77 static inline bool elementCanUseSimpleDefaultStyle(const Element& element)
78 {
79     return is<HTMLHtmlElement>(element) || is<HTMLHeadElement>(element)
80         || is<HTMLBodyElement>(element) || is<HTMLDivElement>(element)
81         || is<HTMLSpanElement>(element) || is<HTMLBRElement>(element)
82         || is<HTMLAnchorElement>(element);
83 }
84
85 static const MediaQueryEvaluator& screenEval()
86 {
87     static NeverDestroyed<const MediaQueryEvaluator> staticScreenEval(String(MAKE_STATIC_STRING_IMPL("screen")));
88     return staticScreenEval;
89 }
90
91 static const MediaQueryEvaluator& printEval()
92 {
93     static NeverDestroyed<const MediaQueryEvaluator> staticPrintEval(String(MAKE_STATIC_STRING_IMPL("print")));
94     return staticPrintEval;
95 }
96
97 static StyleSheetContents* parseUASheet(const String& str)
98 {
99     StyleSheetContents& sheet = StyleSheetContents::create(CSSParserContext(UASheetMode)).leakRef(); // leak the sheet on purpose
100     sheet.parseString(str);
101     return &sheet;
102 }
103
104 static StyleSheetContents* parseUASheet(const char* characters, unsigned size)
105 {
106     return parseUASheet(String(characters, size));
107 }
108
109 void CSSDefaultStyleSheets::initDefaultStyle(const Element* root)
110 {
111     if (!defaultStyle) {
112         if (!root || elementCanUseSimpleDefaultStyle(*root))
113             loadSimpleDefaultStyle();
114         else
115             loadFullDefaultStyle();
116     }
117 }
118
119 void CSSDefaultStyleSheets::loadFullDefaultStyle()
120 {
121     if (simpleDefaultStyleSheet) {
122         ASSERT(defaultStyle);
123         ASSERT(defaultPrintStyle == defaultStyle);
124         delete defaultStyle;
125         simpleDefaultStyleSheet->deref();
126         defaultStyle = std::make_unique<RuleSet>().release();
127         defaultPrintStyle = std::make_unique<RuleSet>().release();
128         simpleDefaultStyleSheet = 0;
129     } else {
130         ASSERT(!defaultStyle);
131         defaultStyle = std::make_unique<RuleSet>().release();
132         defaultPrintStyle = std::make_unique<RuleSet>().release();
133         defaultQuirksStyle = std::make_unique<RuleSet>().release();
134     }
135
136     // Strict-mode rules.
137     String defaultRules = String(htmlUserAgentStyleSheet, sizeof(htmlUserAgentStyleSheet)) + RenderTheme::singleton().extraDefaultStyleSheet();
138     defaultStyleSheet = parseUASheet(defaultRules);
139     defaultStyle->addRulesFromSheet(*defaultStyleSheet, screenEval());
140     defaultPrintStyle->addRulesFromSheet(*defaultStyleSheet, printEval());
141
142     // Quirks-mode rules.
143     String quirksRules = String(quirksUserAgentStyleSheet, sizeof(quirksUserAgentStyleSheet)) + RenderTheme::singleton().extraQuirksStyleSheet();
144     quirksStyleSheet = parseUASheet(quirksRules);
145     defaultQuirksStyle->addRulesFromSheet(*quirksStyleSheet, screenEval());
146 }
147
148 void CSSDefaultStyleSheets::loadSimpleDefaultStyle()
149 {
150     ASSERT(!defaultStyle);
151     ASSERT(!simpleDefaultStyleSheet);
152
153     defaultStyle = std::make_unique<RuleSet>().release();
154     // There are no media-specific rules in the simple default style.
155     defaultPrintStyle = defaultStyle;
156     defaultQuirksStyle = std::make_unique<RuleSet>().release();
157
158     simpleDefaultStyleSheet = parseUASheet(simpleUserAgentStyleSheet, strlen(simpleUserAgentStyleSheet));
159     defaultStyle->addRulesFromSheet(*simpleDefaultStyleSheet, screenEval());
160     ++defaultStyleVersion;
161     // No need to initialize quirks sheet yet as there are no quirk rules for elements allowed in simple default style.
162 }
163
164 void CSSDefaultStyleSheets::ensureDefaultStyleSheetsForElement(const Element& element)
165 {
166     if (simpleDefaultStyleSheet && !elementCanUseSimpleDefaultStyle(element)) {
167         loadFullDefaultStyle();
168         ++defaultStyleVersion;
169     }
170
171     if (is<HTMLElement>(element)) {
172         if (is<HTMLObjectElement>(element) || is<HTMLEmbedElement>(element)) {
173             if (!plugInsStyleSheet && element.document().page()) {
174                 String plugInsRules = RenderTheme::singleton().extraPlugInsStyleSheet() + element.document().page()->chrome().client().plugInExtraStyleSheet();
175                 if (plugInsRules.isEmpty())
176                     plugInsRules = String(plugInsUserAgentStyleSheet, sizeof(plugInsUserAgentStyleSheet));
177                 plugInsStyleSheet = parseUASheet(plugInsRules);
178                 defaultStyle->addRulesFromSheet(*plugInsStyleSheet, screenEval());
179                 ++defaultStyleVersion;
180             }
181         }
182 #if ENABLE(VIDEO)
183         else if (is<HTMLMediaElement>(element)) {
184             if (!mediaControlsStyleSheet) {
185                 String mediaRules = RenderTheme::singleton().mediaControlsStyleSheet();
186                 if (mediaRules.isEmpty())
187                     mediaRules = String(mediaControlsUserAgentStyleSheet, sizeof(mediaControlsUserAgentStyleSheet)) + RenderTheme::singleton().extraMediaControlsStyleSheet();
188                 mediaControlsStyleSheet = parseUASheet(mediaRules);
189                 defaultStyle->addRulesFromSheet(*mediaControlsStyleSheet, screenEval());
190                 defaultPrintStyle->addRulesFromSheet(*mediaControlsStyleSheet, printEval());
191                 ++defaultStyleVersion;
192             }
193         }
194 #endif // ENABLE(VIDEO)
195 #if ENABLE(SERVICE_CONTROLS)
196         else if (is<HTMLDivElement>(element) && element.isImageControlsRootElement()) {
197             if (!imageControlsStyleSheet) {
198                 String imageControlsRules = RenderTheme::singleton().imageControlsStyleSheet();
199                 imageControlsStyleSheet = parseUASheet(imageControlsRules);
200                 defaultStyle->addRulesFromSheet(*imageControlsStyleSheet, screenEval());
201                 defaultPrintStyle->addRulesFromSheet(*imageControlsStyleSheet, printEval());
202                 ++defaultStyleVersion;
203             }
204         }
205 #endif // ENABLE(SERVICE_CONTROLS)
206     } else if (is<SVGElement>(element)) {
207         if (!svgStyleSheet) {
208             // SVG rules.
209             svgStyleSheet = parseUASheet(svgUserAgentStyleSheet, sizeof(svgUserAgentStyleSheet));
210             defaultStyle->addRulesFromSheet(*svgStyleSheet, screenEval());
211             defaultPrintStyle->addRulesFromSheet(*svgStyleSheet, printEval());
212             ++defaultStyleVersion;
213         }
214     }
215 #if ENABLE(MATHML)
216     else if (is<MathMLElement>(element)) {
217         if (!mathMLStyleSheet) {
218             // MathML rules.
219             mathMLStyleSheet = parseUASheet(mathmlUserAgentStyleSheet, sizeof(mathmlUserAgentStyleSheet));
220             defaultStyle->addRulesFromSheet(*mathMLStyleSheet, screenEval());
221             defaultPrintStyle->addRulesFromSheet(*mathMLStyleSheet, printEval());
222             ++defaultStyleVersion;
223         }
224     }
225 #endif // ENABLE(MATHML)
226
227 #if ENABLE(FULLSCREEN_API)
228     if (!fullscreenStyleSheet && element.document().webkitIsFullScreen()) {
229         String fullscreenRules = String(fullscreenUserAgentStyleSheet, sizeof(fullscreenUserAgentStyleSheet)) + RenderTheme::singleton().extraFullScreenStyleSheet();
230         fullscreenStyleSheet = parseUASheet(fullscreenRules);
231         defaultStyle->addRulesFromSheet(*fullscreenStyleSheet, screenEval());
232         defaultQuirksStyle->addRulesFromSheet(*fullscreenStyleSheet, screenEval());
233         ++defaultStyleVersion;
234     }
235 #endif // ENABLE(FULLSCREEN_API)
236
237     ASSERT(defaultStyle->features().idsInRules.isEmpty());
238     ASSERT(mathMLStyleSheet || defaultStyle->features().siblingRules.isEmpty());
239 }
240
241 } // namespace WebCore