b8069d6607836e3f37e7ecfe60da9d0c8639da21
[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 "FullscreenManager.h"
35 #include "HTMLAnchorElement.h"
36 #include "HTMLBRElement.h"
37 #include "HTMLBodyElement.h"
38 #include "HTMLDataListElement.h"
39 #include "HTMLDivElement.h"
40 #include "HTMLEmbedElement.h"
41 #include "HTMLHeadElement.h"
42 #include "HTMLHtmlElement.h"
43 #include "HTMLInputElement.h"
44 #include "HTMLMediaElement.h"
45 #include "HTMLObjectElement.h"
46 #include "HTMLSpanElement.h"
47 #include "MathMLElement.h"
48 #include "MediaQueryEvaluator.h"
49 #include "Page.h"
50 #include "RenderTheme.h"
51 #include "RuleSet.h"
52 #include "SVGElement.h"
53 #include "StyleSheetContents.h"
54 #include "UserAgentStyleSheets.h"
55 #include <wtf/NeverDestroyed.h>
56
57 namespace WebCore {
58
59 using namespace HTMLNames;
60
61 RuleSet* CSSDefaultStyleSheets::defaultStyle;
62 RuleSet* CSSDefaultStyleSheets::defaultQuirksStyle;
63 RuleSet* CSSDefaultStyleSheets::defaultPrintStyle;
64 unsigned CSSDefaultStyleSheets::defaultStyleVersion;
65
66 StyleSheetContents* CSSDefaultStyleSheets::simpleDefaultStyleSheet;
67 StyleSheetContents* CSSDefaultStyleSheets::defaultStyleSheet;
68 StyleSheetContents* CSSDefaultStyleSheets::quirksStyleSheet;
69 StyleSheetContents* CSSDefaultStyleSheets::svgStyleSheet;
70 StyleSheetContents* CSSDefaultStyleSheets::mathMLStyleSheet;
71 StyleSheetContents* CSSDefaultStyleSheets::mediaControlsStyleSheet;
72 StyleSheetContents* CSSDefaultStyleSheets::fullscreenStyleSheet;
73 StyleSheetContents* CSSDefaultStyleSheets::plugInsStyleSheet;
74 StyleSheetContents* CSSDefaultStyleSheets::imageControlsStyleSheet;
75 StyleSheetContents* CSSDefaultStyleSheets::mediaQueryStyleSheet;
76 #if ENABLE(DATALIST_ELEMENT)
77 StyleSheetContents* CSSDefaultStyleSheets::dataListStyleSheet;
78 #endif
79 #if ENABLE(INPUT_TYPE_COLOR)
80 StyleSheetContents* CSSDefaultStyleSheets::colorInputStyleSheet;
81 #endif
82
83 // FIXME: It would be nice to use some mechanism that guarantees this is in sync with the real UA stylesheet.
84 #if PLATFORM(MAC)
85 // The only difference in the simple style sheet for macOS is the addition of html{color:text}.
86 static const char* simpleUserAgentStyleSheet = "html,body,div{display:block}html{color:text}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}";
87 #else
88 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}";
89 #endif
90
91 static inline bool elementCanUseSimpleDefaultStyle(const Element& element)
92 {
93     return is<HTMLHtmlElement>(element) || is<HTMLHeadElement>(element)
94         || is<HTMLBodyElement>(element) || is<HTMLDivElement>(element)
95         || is<HTMLSpanElement>(element) || is<HTMLBRElement>(element)
96         || is<HTMLAnchorElement>(element);
97 }
98
99 static const MediaQueryEvaluator& screenEval()
100 {
101     static NeverDestroyed<const MediaQueryEvaluator> staticScreenEval(String(MAKE_STATIC_STRING_IMPL("screen")));
102     return staticScreenEval;
103 }
104
105 static const MediaQueryEvaluator& printEval()
106 {
107     static NeverDestroyed<const MediaQueryEvaluator> staticPrintEval(String(MAKE_STATIC_STRING_IMPL("print")));
108     return staticPrintEval;
109 }
110
111 static StyleSheetContents* parseUASheet(const String& str)
112 {
113     StyleSheetContents& sheet = StyleSheetContents::create(CSSParserContext(UASheetMode)).leakRef(); // leak the sheet on purpose
114     sheet.parseString(str);
115     return &sheet;
116 }
117
118 static StyleSheetContents* parseUASheet(const char* characters, unsigned size)
119 {
120     return parseUASheet(String(characters, size));
121 }
122
123 void CSSDefaultStyleSheets::initDefaultStyle(const Element* root)
124 {
125     if (!defaultStyle) {
126         if (!root || elementCanUseSimpleDefaultStyle(*root))
127             loadSimpleDefaultStyle();
128         else
129             loadFullDefaultStyle();
130     }
131 }
132
133 void CSSDefaultStyleSheets::addToDefaultStyle(StyleSheetContents& sheet)
134 {
135     defaultStyle->addRulesFromSheet(sheet, screenEval());
136     defaultPrintStyle->addRulesFromSheet(sheet, printEval());
137
138     // Build a stylesheet consisting of non-trivial media queries seen in default style.
139     // Rulesets for these can't be global and need to be built in document context.
140     for (auto& rule : sheet.childRules()) {
141         if (!is<StyleRuleMedia>(*rule))
142             continue;
143         auto& mediaRule = downcast<StyleRuleMedia>(*rule);
144         auto* mediaQuery = mediaRule.mediaQueries();
145         if (!mediaQuery)
146             continue;
147         if (screenEval().evaluate(*mediaQuery, nullptr))
148             continue;
149         if (printEval().evaluate(*mediaQuery, nullptr))
150             continue;
151         mediaQueryStyleSheet->parserAppendRule(mediaRule.copy());
152     }
153
154     ++defaultStyleVersion;
155 }
156
157 void CSSDefaultStyleSheets::loadFullDefaultStyle()
158 {
159     if (defaultStyle && !simpleDefaultStyleSheet)
160         return;
161     
162     if (simpleDefaultStyleSheet) {
163         ASSERT(defaultStyle);
164         ASSERT(defaultPrintStyle == defaultStyle);
165         delete defaultStyle;
166         simpleDefaultStyleSheet->deref();
167         simpleDefaultStyleSheet = nullptr;
168     } else {
169         ASSERT(!defaultStyle);
170         defaultQuirksStyle = std::make_unique<RuleSet>().release();
171     }
172
173     defaultStyle = std::make_unique<RuleSet>().release();
174     defaultPrintStyle = std::make_unique<RuleSet>().release();
175     mediaQueryStyleSheet = &StyleSheetContents::create(CSSParserContext(UASheetMode)).leakRef();
176
177     // Strict-mode rules.
178     String defaultRules = String(htmlUserAgentStyleSheet, sizeof(htmlUserAgentStyleSheet)) + RenderTheme::singleton().extraDefaultStyleSheet();
179     defaultStyleSheet = parseUASheet(defaultRules);
180     addToDefaultStyle(*defaultStyleSheet);
181
182     // Quirks-mode rules.
183     String quirksRules = String(quirksUserAgentStyleSheet, sizeof(quirksUserAgentStyleSheet)) + RenderTheme::singleton().extraQuirksStyleSheet();
184     quirksStyleSheet = parseUASheet(quirksRules);
185     defaultQuirksStyle->addRulesFromSheet(*quirksStyleSheet, screenEval());
186 }
187
188 void CSSDefaultStyleSheets::loadSimpleDefaultStyle()
189 {
190     ASSERT(!defaultStyle);
191     ASSERT(!simpleDefaultStyleSheet);
192
193     defaultStyle = std::make_unique<RuleSet>().release();
194     // There are no media-specific rules in the simple default style.
195     defaultPrintStyle = defaultStyle;
196     defaultQuirksStyle = std::make_unique<RuleSet>().release();
197
198     simpleDefaultStyleSheet = parseUASheet(simpleUserAgentStyleSheet, strlen(simpleUserAgentStyleSheet));
199     defaultStyle->addRulesFromSheet(*simpleDefaultStyleSheet, screenEval());
200     ++defaultStyleVersion;
201     // No need to initialize quirks sheet yet as there are no quirk rules for elements allowed in simple default style.
202 }
203
204 void CSSDefaultStyleSheets::ensureDefaultStyleSheetsForElement(const Element& element)
205 {
206     if (simpleDefaultStyleSheet && !elementCanUseSimpleDefaultStyle(element)) {
207         loadFullDefaultStyle();
208         ++defaultStyleVersion;
209     }
210
211     if (is<HTMLElement>(element)) {
212         if (is<HTMLObjectElement>(element) || is<HTMLEmbedElement>(element)) {
213             if (!plugInsStyleSheet && element.document().page()) {
214                 String plugInsRules = RenderTheme::singleton().extraPlugInsStyleSheet() + element.document().page()->chrome().client().plugInExtraStyleSheet();
215                 if (plugInsRules.isEmpty())
216                     plugInsRules = String(plugInsUserAgentStyleSheet, sizeof(plugInsUserAgentStyleSheet));
217                 plugInsStyleSheet = parseUASheet(plugInsRules);
218                 addToDefaultStyle(*plugInsStyleSheet);
219             }
220         }
221 #if ENABLE(VIDEO)
222         else if (is<HTMLMediaElement>(element)) {
223             if (!mediaControlsStyleSheet) {
224                 String mediaRules = RenderTheme::singleton().mediaControlsStyleSheet();
225                 if (mediaRules.isEmpty())
226                     mediaRules = String(mediaControlsUserAgentStyleSheet, sizeof(mediaControlsUserAgentStyleSheet)) + RenderTheme::singleton().extraMediaControlsStyleSheet();
227                 mediaControlsStyleSheet = parseUASheet(mediaRules);
228                 addToDefaultStyle(*mediaControlsStyleSheet);
229
230             }
231         }
232 #endif // ENABLE(VIDEO)
233 #if ENABLE(SERVICE_CONTROLS)
234         else if (is<HTMLDivElement>(element) && element.isImageControlsRootElement()) {
235             if (!imageControlsStyleSheet) {
236                 String imageControlsRules = RenderTheme::singleton().imageControlsStyleSheet();
237                 imageControlsStyleSheet = parseUASheet(imageControlsRules);
238                 addToDefaultStyle(*imageControlsStyleSheet);
239             }
240         }
241 #endif // ENABLE(SERVICE_CONTROLS)
242 #if ENABLE(DATALIST_ELEMENT)
243         else if (!dataListStyleSheet && is<HTMLDataListElement>(element)) {
244             dataListStyleSheet = parseUASheet(RenderTheme::singleton().dataListStyleSheet());
245             addToDefaultStyle(*dataListStyleSheet);
246         }
247 #endif // ENABLE(DATALIST_ELEMENT)
248 #if ENABLE(INPUT_TYPE_COLOR)
249         else if (!colorInputStyleSheet && is<HTMLInputElement>(element) && downcast<HTMLInputElement>(element).isColorControl()) {
250             colorInputStyleSheet = parseUASheet(RenderTheme::singleton().colorInputStyleSheet());
251             addToDefaultStyle(*colorInputStyleSheet);
252         }
253 #endif // ENABLE(INPUT_TYPE_COLOR)
254     } else if (is<SVGElement>(element)) {
255         if (!svgStyleSheet) {
256             // SVG rules.
257             svgStyleSheet = parseUASheet(svgUserAgentStyleSheet, sizeof(svgUserAgentStyleSheet));
258             addToDefaultStyle(*svgStyleSheet);
259         }
260     }
261 #if ENABLE(MATHML)
262     else if (is<MathMLElement>(element)) {
263         if (!mathMLStyleSheet) {
264             // MathML rules.
265             mathMLStyleSheet = parseUASheet(mathmlUserAgentStyleSheet, sizeof(mathmlUserAgentStyleSheet));
266             addToDefaultStyle(*mathMLStyleSheet);
267         }
268     }
269 #endif // ENABLE(MATHML)
270
271 #if ENABLE(FULLSCREEN_API)
272     if (!fullscreenStyleSheet && element.document().fullscreenManager().isFullscreen()) {
273         String fullscreenRules = String(fullscreenUserAgentStyleSheet, sizeof(fullscreenUserAgentStyleSheet)) + RenderTheme::singleton().extraFullScreenStyleSheet();
274         fullscreenStyleSheet = parseUASheet(fullscreenRules);
275         addToDefaultStyle(*fullscreenStyleSheet);
276     }
277 #endif // ENABLE(FULLSCREEN_API)
278
279     ASSERT(defaultStyle->features().idsInRules.isEmpty());
280     ASSERT(mathMLStyleSheet || defaultStyle->features().siblingRules.isEmpty());
281 }
282
283 } // namespace WebCore