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 "core/css/CSSDefaultStyleSheets.h"
31
32#include "core/MathMLNames.h"
33#include "core/UserAgentStyleSheets.h"
34#include "core/css/MediaQueryEvaluator.h"
35#include "core/css/RuleSet.h"
36#include "core/css/StyleSheetContents.h"
37#include "core/dom/Fullscreen.h"
38#include "core/html/HTMLAnchorElement.h"
39#include "core/html/HTMLHtmlElement.h"
40#include "core/rendering/RenderTheme.h"
41#include "wtf/LeakAnnotations.h"
42
43namespace blink {
44
45using namespace HTMLNames;
46
47CSSDefaultStyleSheets& CSSDefaultStyleSheets::instance()
48{
49    DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<CSSDefaultStyleSheets>, cssDefaultStyleSheets, (adoptPtrWillBeNoop(new CSSDefaultStyleSheets())));
50    return *cssDefaultStyleSheets;
51}
52
53static const MediaQueryEvaluator& screenEval()
54{
55    DEFINE_STATIC_LOCAL(const MediaQueryEvaluator, staticScreenEval, ("screen"));
56    return staticScreenEval;
57}
58
59static const MediaQueryEvaluator& printEval()
60{
61    DEFINE_STATIC_LOCAL(const MediaQueryEvaluator, staticPrintEval, ("print"));
62    return staticPrintEval;
63}
64
65static PassRefPtrWillBeRawPtr<StyleSheetContents> parseUASheet(const String& str)
66{
67    RefPtrWillBeRawPtr<StyleSheetContents> sheet = StyleSheetContents::create(CSSParserContext(UASheetMode, 0));
68    sheet->parseString(str);
69    // User Agent stylesheets are parsed once for the lifetime of the renderer
70    // and are intentionally leaked.
71    WTF_ANNOTATE_LEAKING_OBJECT_PTR(sheet.get());
72    return sheet.release();
73}
74
75static PassRefPtrWillBeRawPtr<StyleSheetContents> parseUASheet(const char* characters, unsigned size)
76{
77    return parseUASheet(String(characters, size));
78}
79
80CSSDefaultStyleSheets::CSSDefaultStyleSheets()
81    : m_defaultStyle(nullptr)
82    , m_defaultViewportStyle(nullptr)
83    , m_defaultQuirksStyle(nullptr)
84    , m_defaultPrintStyle(nullptr)
85    , m_defaultViewSourceStyle(nullptr)
86    , m_defaultXHTMLMobileProfileStyle(nullptr)
87    , m_defaultTransitionStyle(nullptr)
88    , m_defaultStyleSheet(nullptr)
89    , m_viewportStyleSheet(nullptr)
90    , m_quirksStyleSheet(nullptr)
91    , m_svgStyleSheet(nullptr)
92    , m_mathmlStyleSheet(nullptr)
93    , m_mediaControlsStyleSheet(nullptr)
94    , m_fullscreenStyleSheet(nullptr)
95{
96    m_defaultStyle = RuleSet::create();
97    m_defaultViewportStyle = RuleSet::create();
98    m_defaultPrintStyle = RuleSet::create();
99    m_defaultQuirksStyle = RuleSet::create();
100
101    // Strict-mode rules.
102    String defaultRules = String(htmlCss, sizeof(htmlCss)) + RenderTheme::theme().extraDefaultStyleSheet();
103    m_defaultStyleSheet = parseUASheet(defaultRules);
104    m_defaultStyle->addRulesFromSheet(defaultStyleSheet(), screenEval());
105#if OS(ANDROID)
106    String viewportRules(viewportAndroidCss, sizeof(viewportAndroidCss));
107#else
108    String viewportRules;
109#endif
110    m_viewportStyleSheet = parseUASheet(viewportRules);
111    m_defaultViewportStyle->addRulesFromSheet(viewportStyleSheet(), screenEval());
112    m_defaultPrintStyle->addRulesFromSheet(defaultStyleSheet(), printEval());
113
114    // Quirks-mode rules.
115    String quirksRules = String(quirksCss, sizeof(quirksCss)) + RenderTheme::theme().extraQuirksStyleSheet();
116    m_quirksStyleSheet = parseUASheet(quirksRules);
117    m_defaultQuirksStyle->addRulesFromSheet(quirksStyleSheet(), screenEval());
118}
119
120RuleSet* CSSDefaultStyleSheets::defaultViewSourceStyle()
121{
122    if (!m_defaultViewSourceStyle) {
123        m_defaultViewSourceStyle = RuleSet::create();
124        // Loaded stylesheet is leaked on purpose.
125        RefPtrWillBeRawPtr<StyleSheetContents> stylesheet = parseUASheet(viewSourceCss, sizeof(viewSourceCss));
126        m_defaultViewSourceStyle->addRulesFromSheet(stylesheet.release().leakRef(), screenEval());
127    }
128    return m_defaultViewSourceStyle.get();
129}
130
131RuleSet* CSSDefaultStyleSheets::defaultTransitionStyle()
132{
133    if (!m_defaultTransitionStyle) {
134        m_defaultTransitionStyle = RuleSet::create();
135        // Loaded stylesheet is leaked on purpose.
136        RefPtrWillBeRawPtr<StyleSheetContents> stylesheet = parseUASheet(navigationTransitionsCss, sizeof(navigationTransitionsCss));
137        m_defaultTransitionStyle->addRulesFromSheet(stylesheet.release().leakRef(), screenEval());
138    }
139    return m_defaultTransitionStyle.get();
140}
141
142RuleSet* CSSDefaultStyleSheets::defaultXHTMLMobileProfileStyle()
143{
144    if (!m_defaultXHTMLMobileProfileStyle) {
145        m_defaultXHTMLMobileProfileStyle = RuleSet::create();
146        // Loaded stylesheet is leaked on purpose.
147        RefPtrWillBeRawPtr<StyleSheetContents> stylesheet = parseUASheet(xhtmlmpCss, sizeof(xhtmlmpCss));
148        m_defaultXHTMLMobileProfileStyle->addRulesFromSheet(stylesheet.release().leakRef(), screenEval());
149    }
150    return m_defaultXHTMLMobileProfileStyle.get();
151}
152
153void CSSDefaultStyleSheets::ensureDefaultStyleSheetsForElement(Element* element, bool& changedDefaultStyle)
154{
155    // FIXME: We should assert that the sheet only styles SVG elements.
156    if (element->isSVGElement() && !m_svgStyleSheet) {
157        m_svgStyleSheet = parseUASheet(svgCss, sizeof(svgCss));
158        m_defaultStyle->addRulesFromSheet(svgStyleSheet(), screenEval());
159        m_defaultPrintStyle->addRulesFromSheet(svgStyleSheet(), printEval());
160        changedDefaultStyle = true;
161    }
162
163    // FIXME: We should assert that the sheet only styles MathML elements.
164    if (element->namespaceURI() == MathMLNames::mathmlNamespaceURI
165        && !m_mathmlStyleSheet) {
166        m_mathmlStyleSheet = parseUASheet(mathmlCss, sizeof(mathmlCss));
167        m_defaultStyle->addRulesFromSheet(mathmlStyleSheet(), screenEval());
168        m_defaultPrintStyle->addRulesFromSheet(mathmlStyleSheet(), printEval());
169        changedDefaultStyle = true;
170    }
171
172    // FIXME: We should assert that this sheet only contains rules for <video> and <audio>.
173    if (!m_mediaControlsStyleSheet && (isHTMLVideoElement(*element) || isHTMLAudioElement(*element))) {
174        String mediaRules = String(mediaControlsCss, sizeof(mediaControlsCss)) + RenderTheme::theme().extraMediaControlsStyleSheet();
175        m_mediaControlsStyleSheet = parseUASheet(mediaRules);
176        m_defaultStyle->addRulesFromSheet(mediaControlsStyleSheet(), screenEval());
177        m_defaultPrintStyle->addRulesFromSheet(mediaControlsStyleSheet(), printEval());
178        changedDefaultStyle = true;
179    }
180
181    // FIXME: This only works because we Force recalc the entire document so the new sheet
182    // is loaded for <html> and the correct styles apply to everyone.
183    if (!m_fullscreenStyleSheet && Fullscreen::isFullScreen(element->document())) {
184        String fullscreenRules = String(fullscreenCss, sizeof(fullscreenCss)) + RenderTheme::theme().extraFullScreenStyleSheet();
185        m_fullscreenStyleSheet = parseUASheet(fullscreenRules);
186        m_defaultStyle->addRulesFromSheet(fullscreenStyleSheet(), screenEval());
187        m_defaultQuirksStyle->addRulesFromSheet(fullscreenStyleSheet(), screenEval());
188        changedDefaultStyle = true;
189    }
190
191    ASSERT(!m_defaultStyle->features().hasIdsInSelectors());
192    ASSERT(m_defaultStyle->features().siblingRules.isEmpty());
193}
194
195void CSSDefaultStyleSheets::trace(Visitor* visitor)
196{
197    visitor->trace(m_defaultStyle);
198    visitor->trace(m_defaultViewportStyle);
199    visitor->trace(m_defaultQuirksStyle);
200    visitor->trace(m_defaultPrintStyle);
201    visitor->trace(m_defaultViewSourceStyle);
202    visitor->trace(m_defaultXHTMLMobileProfileStyle);
203    visitor->trace(m_defaultTransitionStyle);
204    visitor->trace(m_defaultStyleSheet);
205    visitor->trace(m_viewportStyleSheet);
206    visitor->trace(m_quirksStyleSheet);
207    visitor->trace(m_svgStyleSheet);
208    visitor->trace(m_mathmlStyleSheet);
209    visitor->trace(m_mediaControlsStyleSheet);
210    visitor->trace(m_fullscreenStyleSheet);
211}
212
213} // namespace blink
214