blob: 47ee7c070c18656894b44e8c716102df16dc49a0 [file] [log] [blame]
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
* Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All
* rights reserved.
* Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
* Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
* (http://www.torchmobile.com/)
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (C) Research In Motion Limited 2011. All rights reserved.
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "third_party/blink/renderer/core/css/css_default_style_sheets.h"
#include "third_party/blink/public/resources/grit/blink_resources.h"
#include "third_party/blink/renderer/core/css/media_query_evaluator.h"
#include "third_party/blink/renderer/core/css/rule_set.h"
#include "third_party/blink/renderer/core/css/style_sheet_contents.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/html_anchor_element.h"
#include "third_party/blink/renderer/core/html/html_html_element.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/renderer/core/mathml_names.h"
#include "third_party/blink/renderer/platform/data_resource_helper.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/leak_annotations.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
CSSDefaultStyleSheets& CSSDefaultStyleSheets::Instance() {
DEFINE_STATIC_LOCAL(Persistent<CSSDefaultStyleSheets>,
css_default_style_sheets,
(MakeGarbageCollected<CSSDefaultStyleSheets>()));
return *css_default_style_sheets;
}
static const MediaQueryEvaluator& ScreenEval() {
DEFINE_STATIC_LOCAL(const Persistent<MediaQueryEvaluator>, static_screen_eval,
(MakeGarbageCollected<MediaQueryEvaluator>("screen")));
return *static_screen_eval;
}
static const MediaQueryEvaluator& PrintEval() {
DEFINE_STATIC_LOCAL(const Persistent<MediaQueryEvaluator>, static_print_eval,
(MakeGarbageCollected<MediaQueryEvaluator>("print")));
return *static_print_eval;
}
static const MediaQueryEvaluator& ForcedColorsEval() {
// We use "ua-forced-colors" here instead of "forced-colors" to indicate that
// this is a UA hack for the "forced-colors" media query.
DEFINE_STATIC_LOCAL(
Persistent<MediaQueryEvaluator>, forced_colors_eval,
(MakeGarbageCollected<MediaQueryEvaluator>("ua-forced-colors")));
return *forced_colors_eval;
}
static StyleSheetContents* ParseUASheet(const String& str) {
// UA stylesheets always parse in the insecure context mode.
auto* sheet = MakeGarbageCollected<StyleSheetContents>(
MakeGarbageCollected<CSSParserContext>(
kUASheetMode, SecureContextMode::kInsecureContext));
sheet->ParseString(str);
// User Agent stylesheets are parsed once for the lifetime of the renderer
// process and are intentionally leaked.
LEAK_SANITIZER_IGNORE_OBJECT(sheet);
return sheet;
}
CSSDefaultStyleSheets::CSSDefaultStyleSheets()
: media_controls_style_sheet_loader_(nullptr) {
// Predefined @counter-style rules
String predefined_counter_styles_sheet =
RuntimeEnabledFeatures::CSSAtRuleCounterStyleEnabled()
? UncompressResourceAsASCIIString(
IDR_UASTYLE_PREDEFINED_COUNTER_STYLES_CSS)
: String();
// Strict-mode rules.
String default_rules = UncompressResourceAsASCIIString(IDR_UASTYLE_HTML_CSS) +
LayoutTheme::GetTheme().ExtraDefaultStyleSheet() +
predefined_counter_styles_sheet;
default_style_sheet_ = ParseUASheet(default_rules);
// Quirks-mode rules.
String quirks_rules =
UncompressResourceAsASCIIString(IDR_UASTYLE_QUIRKS_CSS) +
LayoutTheme::GetTheme().ExtraQuirksStyleSheet();
quirks_style_sheet_ = ParseUASheet(quirks_rules);
InitializeDefaultStyles();
#if DCHECK_IS_ON()
default_style_->CompactRulesIfNeeded();
default_mathml_style_->CompactRulesIfNeeded();
default_svg_style_->CompactRulesIfNeeded();
default_quirks_style_->CompactRulesIfNeeded();
default_print_style_->CompactRulesIfNeeded();
DCHECK(default_style_->UniversalRules()->IsEmpty());
DCHECK(default_mathml_style_->UniversalRules()->IsEmpty());
DCHECK(default_svg_style_->UniversalRules()->IsEmpty());
DCHECK(default_quirks_style_->UniversalRules()->IsEmpty());
DCHECK(default_print_style_->UniversalRules()->IsEmpty());
#endif
}
void CSSDefaultStyleSheets::PrepareForLeakDetection() {
// Clear the optional style sheets.
mobile_viewport_style_sheet_.Clear();
television_viewport_style_sheet_.Clear();
xhtml_mobile_profile_style_sheet_.Clear();
svg_style_sheet_.Clear();
mathml_style_sheet_.Clear();
media_controls_style_sheet_.Clear();
text_track_style_sheet_.Clear();
forced_colors_style_sheet_.Clear();
fullscreen_style_sheet_.Clear();
webxr_overlay_style_sheet_.Clear();
marker_style_sheet_.Clear();
// Recreate the default style sheet to clean up possible SVG resources.
String default_rules = UncompressResourceAsASCIIString(IDR_UASTYLE_HTML_CSS) +
LayoutTheme::GetTheme().ExtraDefaultStyleSheet();
default_style_sheet_ = ParseUASheet(default_rules);
// Initialize the styles that have the lazily loaded style sheets.
InitializeDefaultStyles();
default_view_source_style_.Clear();
}
void CSSDefaultStyleSheets::InitializeDefaultStyles() {
// This must be called only from constructor / PrepareForLeakDetection.
default_style_ = MakeGarbageCollected<RuleSet>();
default_mathml_style_ = MakeGarbageCollected<RuleSet>();
default_svg_style_ = MakeGarbageCollected<RuleSet>();
default_quirks_style_ = MakeGarbageCollected<RuleSet>();
default_print_style_ = MakeGarbageCollected<RuleSet>();
default_media_controls_style_ = MakeGarbageCollected<RuleSet>();
default_forced_color_style_.Clear();
default_pseudo_element_style_.Clear();
default_style_->AddRulesFromSheet(DefaultStyleSheet(), ScreenEval());
default_quirks_style_->AddRulesFromSheet(QuirksStyleSheet(), ScreenEval());
default_print_style_->AddRulesFromSheet(DefaultStyleSheet(), PrintEval());
}
RuleSet* CSSDefaultStyleSheets::DefaultViewSourceStyle() {
if (!default_view_source_style_) {
default_view_source_style_ = MakeGarbageCollected<RuleSet>();
// Loaded stylesheet is leaked on purpose.
StyleSheetContents* stylesheet = ParseUASheet(
UncompressResourceAsASCIIString(IDR_UASTYLE_VIEW_SOURCE_CSS));
default_view_source_style_->AddRulesFromSheet(stylesheet, ScreenEval());
}
return default_view_source_style_;
}
StyleSheetContents*
CSSDefaultStyleSheets::EnsureXHTMLMobileProfileStyleSheet() {
if (!xhtml_mobile_profile_style_sheet_) {
xhtml_mobile_profile_style_sheet_ =
ParseUASheet(UncompressResourceAsASCIIString(IDR_UASTYLE_XHTMLMP_CSS));
}
return xhtml_mobile_profile_style_sheet_;
}
StyleSheetContents* CSSDefaultStyleSheets::EnsureMobileViewportStyleSheet() {
if (!mobile_viewport_style_sheet_) {
mobile_viewport_style_sheet_ = ParseUASheet(
UncompressResourceAsASCIIString(IDR_UASTYLE_VIEWPORT_ANDROID_CSS));
}
return mobile_viewport_style_sheet_;
}
StyleSheetContents*
CSSDefaultStyleSheets::EnsureTelevisionViewportStyleSheet() {
if (!television_viewport_style_sheet_) {
television_viewport_style_sheet_ = ParseUASheet(
UncompressResourceAsASCIIString(IDR_UASTYLE_VIEWPORT_TELEVISION_CSS));
}
return television_viewport_style_sheet_;
}
static void AddTextTrackCSSProperties(StringBuilder* builder,
CSSPropertyID propertyId,
String value) {
builder->Append(CSSProperty::Get(propertyId).GetPropertyNameString());
builder->Append(": ");
builder->Append(value);
builder->Append("; ");
}
bool CSSDefaultStyleSheets::EnsureDefaultStyleSheetsForElement(
const Element& element) {
bool changed_default_style = false;
// FIXME: We should assert that the sheet only styles SVG elements.
if (element.IsSVGElement() && !svg_style_sheet_) {
svg_style_sheet_ =
ParseUASheet(UncompressResourceAsASCIIString(IDR_UASTYLE_SVG_CSS));
default_svg_style_->AddRulesFromSheet(SvgStyleSheet(), ScreenEval());
default_print_style_->AddRulesFromSheet(SvgStyleSheet(), PrintEval());
if (default_forced_color_style_) {
default_forced_color_style_->AddRulesFromSheet(SvgStyleSheet(),
ForcedColorsEval());
}
changed_default_style = true;
}
// FIXME: We should assert that the sheet only styles MathML elements.
if (element.namespaceURI() == mathml_names::kNamespaceURI &&
!mathml_style_sheet_) {
mathml_style_sheet_ = ParseUASheet(
RuntimeEnabledFeatures::MathMLCoreEnabled()
? UncompressResourceAsASCIIString(IDR_UASTYLE_MATHML_CSS)
: UncompressResourceAsASCIIString(IDR_UASTYLE_MATHML_FALLBACK_CSS));
default_mathml_style_->AddRulesFromSheet(MathmlStyleSheet(), ScreenEval());
default_print_style_->AddRulesFromSheet(MathmlStyleSheet(), PrintEval());
changed_default_style = true;
}
if (!media_controls_style_sheet_ && HasMediaControlsStyleSheetLoader() &&
(IsA<HTMLVideoElement>(element) || IsA<HTMLAudioElement>(element))) {
// FIXME: We should assert that this sheet only contains rules for <video>
// and <audio>.
media_controls_style_sheet_ =
ParseUASheet(media_controls_style_sheet_loader_->GetUAStyleSheet());
default_media_controls_style_->AddRulesFromSheet(MediaControlsStyleSheet(),
ScreenEval());
default_print_style_->AddRulesFromSheet(MediaControlsStyleSheet(),
PrintEval());
if (default_forced_color_style_) {
default_forced_color_style_->AddRulesFromSheet(MediaControlsStyleSheet(),
ForcedColorsEval());
}
changed_default_style = true;
}
if (!text_track_style_sheet_ && IsA<HTMLVideoElement>(element)) {
Settings* settings = element.GetDocument().GetSettings();
if (settings) {
StringBuilder builder;
builder.Append("video::-webkit-media-text-track-display { ");
AddTextTrackCSSProperties(&builder, CSSPropertyID::kBackgroundColor,
settings->GetTextTrackWindowColor());
AddTextTrackCSSProperties(&builder, CSSPropertyID::kPadding,
settings->GetTextTrackWindowPadding());
AddTextTrackCSSProperties(&builder, CSSPropertyID::kBorderRadius,
settings->GetTextTrackWindowRadius());
builder.Append(" } video::cue { ");
AddTextTrackCSSProperties(&builder, CSSPropertyID::kBackgroundColor,
settings->GetTextTrackBackgroundColor());
AddTextTrackCSSProperties(&builder, CSSPropertyID::kFontFamily,
settings->GetTextTrackFontFamily());
AddTextTrackCSSProperties(&builder, CSSPropertyID::kFontStyle,
settings->GetTextTrackFontStyle());
AddTextTrackCSSProperties(&builder, CSSPropertyID::kFontVariant,
settings->GetTextTrackFontVariant());
AddTextTrackCSSProperties(&builder, CSSPropertyID::kColor,
settings->GetTextTrackTextColor());
AddTextTrackCSSProperties(&builder, CSSPropertyID::kTextShadow,
settings->GetTextTrackTextShadow());
AddTextTrackCSSProperties(&builder, CSSPropertyID::kFontSize,
settings->GetTextTrackTextSize());
builder.Append(" } ");
text_track_style_sheet_ = ParseUASheet(builder.ToString());
default_media_controls_style_->AddRulesFromSheet(text_track_style_sheet_,
ScreenEval());
default_print_style_->AddRulesFromSheet(text_track_style_sheet_,
PrintEval());
changed_default_style = true;
}
}
DCHECK(!default_style_->Features().HasIdsInSelectors());
return changed_default_style;
}
bool CSSDefaultStyleSheets::EnsureDefaultStyleSheetsForPseudoElement(
PseudoId pseudo_id) {
switch (pseudo_id) {
case kPseudoIdMarker: {
if (marker_style_sheet_)
return false;
marker_style_sheet_ =
ParseUASheet(UncompressResourceAsASCIIString(IDR_UASTYLE_MARKER_CSS));
if (!default_pseudo_element_style_)
default_pseudo_element_style_ = MakeGarbageCollected<RuleSet>();
default_pseudo_element_style_->AddRulesFromSheet(MarkerStyleSheet(),
ScreenEval());
return true;
}
default:
return false;
}
}
void CSSDefaultStyleSheets::SetMediaControlsStyleSheetLoader(
std::unique_ptr<UAStyleSheetLoader> loader) {
media_controls_style_sheet_loader_.swap(loader);
}
bool CSSDefaultStyleSheets::EnsureDefaultStyleSheetForXrOverlay() {
if (webxr_overlay_style_sheet_)
return false;
webxr_overlay_style_sheet_ = ParseUASheet(
UncompressResourceAsASCIIString(IDR_UASTYLE_WEBXR_OVERLAY_CSS));
default_style_->AddRulesFromSheet(webxr_overlay_style_sheet_, ScreenEval());
default_print_style_->AddRulesFromSheet(webxr_overlay_style_sheet_,
PrintEval());
if (default_forced_color_style_) {
default_forced_color_style_->AddRulesFromSheet(webxr_overlay_style_sheet_,
ForcedColorsEval());
}
return true;
}
void CSSDefaultStyleSheets::EnsureDefaultStyleSheetForFullscreen() {
if (fullscreen_style_sheet_)
return;
String fullscreen_rules =
UncompressResourceAsASCIIString(IDR_UASTYLE_FULLSCREEN_CSS) +
LayoutTheme::GetTheme().ExtraFullscreenStyleSheet();
fullscreen_style_sheet_ = ParseUASheet(fullscreen_rules);
default_style_->AddRulesFromSheet(FullscreenStyleSheet(), ScreenEval());
default_quirks_style_->AddRulesFromSheet(FullscreenStyleSheet(),
ScreenEval());
}
bool CSSDefaultStyleSheets::EnsureDefaultStyleSheetForForcedColors() {
if (forced_colors_style_sheet_)
return false;
String forced_colors_rules =
RuntimeEnabledFeatures::ForcedColorsEnabled()
? UncompressResourceAsASCIIString(IDR_UASTYLE_THEME_FORCED_COLORS_CSS)
: String();
forced_colors_style_sheet_ = ParseUASheet(forced_colors_rules);
if (!default_forced_color_style_)
default_forced_color_style_ = MakeGarbageCollected<RuleSet>();
default_forced_color_style_->AddRulesFromSheet(DefaultStyleSheet(),
ForcedColorsEval());
default_forced_color_style_->AddRulesFromSheet(ForcedColorsStyleSheet(),
ForcedColorsEval());
if (svg_style_sheet_) {
default_forced_color_style_->AddRulesFromSheet(SvgStyleSheet(),
ForcedColorsEval());
}
if (media_controls_style_sheet_) {
default_forced_color_style_->AddRulesFromSheet(MediaControlsStyleSheet(),
ForcedColorsEval());
}
if (webxr_overlay_style_sheet_) {
default_forced_color_style_->AddRulesFromSheet(webxr_overlay_style_sheet_,
ForcedColorsEval());
}
return true;
}
void CSSDefaultStyleSheets::CollectFeaturesTo(const Document& document,
RuleFeatureSet& features) {
if (DefaultStyle())
features.Add(DefaultStyle()->Features());
if (DefaultMediaControlsStyle())
features.Add(DefaultMediaControlsStyle()->Features());
if (DefaultMathMLStyle())
features.Add(DefaultMathMLStyle()->Features());
if (document.IsViewSource() && DefaultViewSourceStyle())
features.Add(DefaultViewSourceStyle()->Features());
}
void CSSDefaultStyleSheets::Trace(Visitor* visitor) const {
visitor->Trace(default_style_);
visitor->Trace(default_mathml_style_);
visitor->Trace(default_svg_style_);
visitor->Trace(default_quirks_style_);
visitor->Trace(default_print_style_);
visitor->Trace(default_view_source_style_);
visitor->Trace(default_forced_color_style_);
visitor->Trace(default_media_controls_style_);
visitor->Trace(default_style_sheet_);
visitor->Trace(default_pseudo_element_style_);
visitor->Trace(mobile_viewport_style_sheet_);
visitor->Trace(television_viewport_style_sheet_);
visitor->Trace(xhtml_mobile_profile_style_sheet_);
visitor->Trace(quirks_style_sheet_);
visitor->Trace(svg_style_sheet_);
visitor->Trace(mathml_style_sheet_);
visitor->Trace(media_controls_style_sheet_);
visitor->Trace(text_track_style_sheet_);
visitor->Trace(forced_colors_style_sheet_);
visitor->Trace(fullscreen_style_sheet_);
visitor->Trace(webxr_overlay_style_sheet_);
visitor->Trace(marker_style_sheet_);
}
} // namespace blink