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