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, 2006, 2007, 2008, 2009, 2010, 2011, 2012 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 "MediaQueryEvaluator.h"
37#include "Page.h"
38#include "RenderTheme.h"
39#include "RuleSet.h"
40#include "StyleSheetContents.h"
41#include "UserAgentStyleSheets.h"
42#include <wtf/NeverDestroyed.h>
43
44namespace WebCore {
45
46using namespace HTMLNames;
47
48RuleSet* CSSDefaultStyleSheets::defaultStyle;
49RuleSet* CSSDefaultStyleSheets::defaultQuirksStyle;
50RuleSet* CSSDefaultStyleSheets::defaultPrintStyle;
51
52StyleSheetContents* CSSDefaultStyleSheets::simpleDefaultStyleSheet;
53StyleSheetContents* CSSDefaultStyleSheets::defaultStyleSheet;
54StyleSheetContents* CSSDefaultStyleSheets::quirksStyleSheet;
55StyleSheetContents* CSSDefaultStyleSheets::svgStyleSheet;
56StyleSheetContents* CSSDefaultStyleSheets::mathMLStyleSheet;
57StyleSheetContents* CSSDefaultStyleSheets::mediaControlsStyleSheet;
58StyleSheetContents* CSSDefaultStyleSheets::fullscreenStyleSheet;
59StyleSheetContents* CSSDefaultStyleSheets::plugInsStyleSheet;
60StyleSheetContents* CSSDefaultStyleSheets::imageControlsStyleSheet;
61
62// FIXME: It would be nice to use some mechanism that guarantees this is in sync with the real UA stylesheet.
63static 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:-webkit-any-link{color:-webkit-link;text-decoration:underline}a:-webkit-any-link:active{color:-webkit-activelink}";
64
65static inline bool elementCanUseSimpleDefaultStyle(Element* e)
66{
67    return e->hasTagName(htmlTag) || e->hasTagName(headTag) || e->hasTagName(bodyTag) || e->hasTagName(divTag) || e->hasTagName(spanTag) || e->hasTagName(brTag) || isHTMLAnchorElement(e);
68}
69
70static const MediaQueryEvaluator& screenEval()
71{
72    static NeverDestroyed<const MediaQueryEvaluator> staticScreenEval("screen");
73    return staticScreenEval;
74}
75
76static const MediaQueryEvaluator& printEval()
77{
78    static NeverDestroyed<const MediaQueryEvaluator> staticPrintEval("print");
79    return staticPrintEval;
80}
81
82static StyleSheetContents* parseUASheet(const String& str)
83{
84    StyleSheetContents& sheet = StyleSheetContents::create().leakRef(); // leak the sheet on purpose
85    sheet.parseString(str);
86    return &sheet;
87}
88
89static StyleSheetContents* parseUASheet(const char* characters, unsigned size)
90{
91    return parseUASheet(String(characters, size));
92}
93
94void CSSDefaultStyleSheets::initDefaultStyle(Element* root)
95{
96    if (!defaultStyle) {
97        if (!root || elementCanUseSimpleDefaultStyle(root))
98            loadSimpleDefaultStyle();
99        else
100            loadFullDefaultStyle();
101    }
102}
103
104void CSSDefaultStyleSheets::loadFullDefaultStyle()
105{
106    if (simpleDefaultStyleSheet) {
107        ASSERT(defaultStyle);
108        ASSERT(defaultPrintStyle == defaultStyle);
109        delete defaultStyle;
110        simpleDefaultStyleSheet->deref();
111        defaultStyle = std::make_unique<RuleSet>().release();
112        defaultPrintStyle = std::make_unique<RuleSet>().release();
113        simpleDefaultStyleSheet = 0;
114    } else {
115        ASSERT(!defaultStyle);
116        defaultStyle = std::make_unique<RuleSet>().release();
117        defaultPrintStyle = std::make_unique<RuleSet>().release();
118        defaultQuirksStyle = std::make_unique<RuleSet>().release();
119    }
120
121    // Strict-mode rules.
122    String defaultRules = String(htmlUserAgentStyleSheet, sizeof(htmlUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraDefaultStyleSheet();
123    defaultStyleSheet = parseUASheet(defaultRules);
124    defaultStyle->addRulesFromSheet(defaultStyleSheet, screenEval());
125    defaultPrintStyle->addRulesFromSheet(defaultStyleSheet, printEval());
126
127    // Quirks-mode rules.
128    String quirksRules = String(quirksUserAgentStyleSheet, sizeof(quirksUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraQuirksStyleSheet();
129    quirksStyleSheet = parseUASheet(quirksRules);
130    defaultQuirksStyle->addRulesFromSheet(quirksStyleSheet, screenEval());
131}
132
133void CSSDefaultStyleSheets::loadSimpleDefaultStyle()
134{
135    ASSERT(!defaultStyle);
136    ASSERT(!simpleDefaultStyleSheet);
137
138    defaultStyle = std::make_unique<RuleSet>().release();
139    // There are no media-specific rules in the simple default style.
140    defaultPrintStyle = defaultStyle;
141    defaultQuirksStyle = std::make_unique<RuleSet>().release();
142
143    simpleDefaultStyleSheet = parseUASheet(simpleUserAgentStyleSheet, strlen(simpleUserAgentStyleSheet));
144    defaultStyle->addRulesFromSheet(simpleDefaultStyleSheet, screenEval());
145
146    // No need to initialize quirks sheet yet as there are no quirk rules for elements allowed in simple default style.
147}
148
149void CSSDefaultStyleSheets::ensureDefaultStyleSheetsForElement(Element* element, bool& changedDefaultStyle)
150{
151    if (simpleDefaultStyleSheet && !elementCanUseSimpleDefaultStyle(element)) {
152        loadFullDefaultStyle();
153        changedDefaultStyle = true;
154    }
155
156    if (element->isSVGElement() && !svgStyleSheet) {
157        // SVG rules.
158        svgStyleSheet = parseUASheet(svgUserAgentStyleSheet, sizeof(svgUserAgentStyleSheet));
159        defaultStyle->addRulesFromSheet(svgStyleSheet, screenEval());
160        defaultPrintStyle->addRulesFromSheet(svgStyleSheet, printEval());
161        changedDefaultStyle = true;
162    }
163
164#if ENABLE(MATHML)
165    if (element->isMathMLElement() && !mathMLStyleSheet) {
166        // MathML rules.
167        mathMLStyleSheet = parseUASheet(mathmlUserAgentStyleSheet, sizeof(mathmlUserAgentStyleSheet));
168        defaultStyle->addRulesFromSheet(mathMLStyleSheet, screenEval());
169        defaultPrintStyle->addRulesFromSheet(mathMLStyleSheet, printEval());
170        changedDefaultStyle = true;
171    }
172#endif
173
174#if ENABLE(VIDEO)
175    if (!mediaControlsStyleSheet && (element->hasTagName(videoTag) || isHTMLAudioElement(element))) {
176        String mediaRules = RenderTheme::themeForPage(element->document().page())->mediaControlsStyleSheet();
177        if (mediaRules.isEmpty())
178            mediaRules = String(mediaControlsUserAgentStyleSheet, sizeof(mediaControlsUserAgentStyleSheet)) + RenderTheme::themeForPage(element->document().page())->extraMediaControlsStyleSheet();
179        mediaControlsStyleSheet = parseUASheet(mediaRules);
180        defaultStyle->addRulesFromSheet(mediaControlsStyleSheet, screenEval());
181        defaultPrintStyle->addRulesFromSheet(mediaControlsStyleSheet, printEval());
182        changedDefaultStyle = true;
183    }
184#endif
185
186#if ENABLE(FULLSCREEN_API)
187    if (!fullscreenStyleSheet && element->document().webkitIsFullScreen()) {
188        String fullscreenRules = String(fullscreenUserAgentStyleSheet, sizeof(fullscreenUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraFullScreenStyleSheet();
189        fullscreenStyleSheet = parseUASheet(fullscreenRules);
190        defaultStyle->addRulesFromSheet(fullscreenStyleSheet, screenEval());
191        defaultQuirksStyle->addRulesFromSheet(fullscreenStyleSheet, screenEval());
192        changedDefaultStyle = true;
193    }
194#endif
195
196#if ENABLE(SERVICE_CONTROLS)
197    if (!imageControlsStyleSheet && element->isImageControlsRootElement()) {
198        String imageControlsRules = RenderTheme::themeForPage(element->document().page())->imageControlsStyleSheet();
199        imageControlsStyleSheet = parseUASheet(imageControlsRules);
200        defaultStyle->addRulesFromSheet(imageControlsStyleSheet, screenEval());
201        defaultPrintStyle->addRulesFromSheet(imageControlsStyleSheet, printEval());
202        changedDefaultStyle = true;
203    }
204#endif
205
206    if (!plugInsStyleSheet && (element->hasTagName(objectTag) || element->hasTagName(embedTag))) {
207        String plugInsRules = RenderTheme::themeForPage(element->document().page())->extraPlugInsStyleSheet() + element->document().page()->chrome().client().plugInExtraStyleSheet();
208        if (plugInsRules.isEmpty())
209            plugInsRules = String(plugInsUserAgentStyleSheet, sizeof(plugInsUserAgentStyleSheet));
210        plugInsStyleSheet = parseUASheet(plugInsRules);
211        defaultStyle->addRulesFromSheet(plugInsStyleSheet, screenEval());
212        changedDefaultStyle = true;
213    }
214
215    ASSERT(defaultStyle->features().idsInRules.isEmpty());
216    ASSERT(mathMLStyleSheet || defaultStyle->features().siblingRules.isEmpty());
217}
218
219} // namespace WebCore
220