WebKit Inside: CSS 样式表解码字符集
CSS 样式表引入有3种方式: 外部样式表、内部样式表、行内样式,不同的引入方式,解码样式表的字符集原理不一样。
外部样式表
外部样式表由 link 标签引入,当 WebKit 解析到 link 标签时就会构造 CachedCSSStyleSheet 对象。这个对象持有 CachedResourceRequest 对象和 TextResourceDecoder 对象。CachedResourceRequest 对象负责发送请求,TextResourceDecoder 对象负责对下载回来的 CSS 数据进行解码。TextResourceDecoder 对象里面的 m_encoding 属性,就是存储着解码 CSS 数据使用的字符编码信息。相关类图如下所示:

在创建 TextResourceDecoder 对象时,会传入 CachedResourceRequest 使用的字符集信息,代码如下所示:
CachedCSSStyleSheet::CachedCSSStyleSheet(CachedResourceRequest&& request, PAL::SessionID sessionID, const CookieJar* cookieJar)
: CachedResource(WTFMove(request), Type::CSSStyleSheet, sessionID, cookieJar)
// 1. 创建 TextResourceDecoder,传入 CachedResourceRqeuest 字符集
, m_decoder(TextResourceDecoder::create(cssContentTypeAtom(), request.charset()))
{
}
在上面代码注释 1 处,就是 CachedCSSStyleSheet 创建 TextResourceDecoder 对象,并且传入了 CachedResourceReqeust 的字符集用来初始化 TextResourceDecoder 内部的 m_encoding 属性,代码如下:
inline TextResourceDecoder::TextResourceDecoder(const String& mimeType, const PAL::TextEncoding& specifiedDefaultEncoding, bool usesEncodingDetector)
: m_contentType(determineContentType(mimeType))
// 1. specifiedDefaultEncoding 就是传入的 CachedResourceRequest 的字符集
// m_contentType 此时是 CSS
, m_encoding(defaultEncoding(m_contentType, specifiedDefaultEncoding))
, m_usesEncodingDetector(usesEncodingDetector)
{
}
在上面代码注释 1 处初始化 TextResourceDecoder 的 m_encoding 属性,m_contentType 此时的值是 CSS,specifiedDefaultEncoding 就是 CachedResourceRequest 的字符集。但是在初始化 m_encoding 时,并不是直接将 m_encoding 直接赋值为 specifiedDefaultEncoding,而是调用了 TextResourceDecoder::defaultEncoding 函数,相关代码如下:
const PAL::TextEncoding& TextResourceDecoder::defaultEncoding(ContentType contentType, const PAL::TextEncoding& specifiedDefaultEncoding)
{
// Despite 8.5 "Text/xml with Omitted Charset" of RFC 3023, we assume UTF-8 instead of US-ASCII
// for text/xml. This matches Firefox.
// 1. 如果解码的是 XML ,那么无论传入的 specifiedDefaultEncoding 是什么值,都使用 UTF-8 作为默认解码字符集
if (contentType == XML)
return PAL::UTF8Encoding();
// 2. 对于其他资源类型,如果 specifiedDefaultEncoding 使用的字符集名为 null,就默认使用 Latin-1 字符集,
// 也就是 ISO-8859-1
if (!specifiedDefaultEncoding.isValid())
return PAL::Latin1Encoding(); // 3. 将 specifiedDefaultEncoding 作为 TextResourceDecoder 的默认解码字符集
return specifiedDefaultEncoding;
}
上面代码注释 1 处可以看出,TextResourceDecoder 不仅用来解码 CSS,还可以用来解码其他资源类型。如果解码的资源类型是 XML,那么默认的解码字符集就是 UTF-8。
从注释 2 处可以看到,如果不是 XML 资源类型,并且 specifiedDefaultEncoding 不合法,也就是 specifiedDefaultEncoding 内部代码字符集名的 m_name 属性为 null,那么就使用 Latin-1(也就是 ISO-8859-1) 作为 TextResourceDecoder 的默认解码字符集。
从注释 3 可以看到,对于非 XML 资源类型,specifiedDefaultEncoding 就会作为 TextResourceDecoder 的默认解码字符集。也就是会说,解码 CSS 的默认字符集和 CacheResourceRequest 使用同一个字符集。
那么,CacheResourceRequest 的字符集是如何来的呢?相关代码如下:
void HTMLLinkElement::process()
{
...
if (m_disabledState != Disabled && treatAsStyleSheet && document().frame() && m_url.isValid()) {
// 1. 解析 link 标签的 charset 属性值
String charset = attributeWithoutSynchronization(charsetAttr);
if (!PAL::TextEncoding { charset }.isValid())
// 2. 获取文档 Document 使用的字符集
charset = document().charset();
...
// 3. 设置 CachedResourceRequest 的字符集
request.setCharset(WTFMove(charset));
...
return;
}
...
}
上面代码注释 1 处首先解析 link 标签的 charset 属性,如果解析到就使用这个字符集作为 CachedResourceRequest 的字符集,如 注释 3所示。如果解析不到,就使用文档 Document 的字符集作为 CachedResourceReqeust 的字符集,如注释 2 所示。文档 Document 的字符集由 <meta> 标签指定,如果没有 <meta> 标签,那么文档 Document 默认使用 Latin-1 字符集(ISO-8859-1)。
但是,解码 CSS 使用的字符集此时还并没有完全确定,因为 CSS 样式表本身支持 @charset at-rule,它可以指定解码 CSS 样式表需要使用什么字符集。因此,当从网络上下载到 CSS 样式表之后,还需要检测 CSS 样式表里面是否有 @charset at-rule,相关代码如下:
String TextResourceDecoder::decode(const char* data, size_t length)
{
...
if (m_contentType == CSS && !m_checkedForCSSCharset)
// 1. 当下载完 CSS 样式表,这里调用 checkForCSSCharset 函数,检测样式表里是否有 @charset
if (!checkForCSSCharset(data, length, movedDataToBuffer))
return emptyString();
...
}
上面代码注释 1处,当下载完 CSS 样式表使用 TextResourceDecoder 进行解码时,会调用 TextResourceDecoder::checkForCSSCharset 检测 CSS 样式表里面是否有 @charset at-rule。如果有 @charset at-rule,那么就将 TextResourceDecoder 的 m_encoding 属性值设置为 @charset 指定的字符集。
综上所述,对于外部引入的样式表,解码字符集的优先级为:
1 如果样式表有 @charset at-rule,就优先使用 @charset 指定的字符集;
2 否则,就看 link 标签有没有 charset 属性,有的话就优先使用 link 标签 charset 属性指定的字符集;
3 否则,就使用文档 Document 的字符集。
内部样式表与行内样式
由于内部样式表和行内样式本身就在 HTML 文件里面,因此对于它们的解码就使用 HTML 字符集。HTML 解码字符集确认规则如下:
1 如果有 <meta> 标签,就使用 <meta> 标签使用的字符集;
2 否则,就默认使用 Latin-1(ISO-8859-1) 字符集
WebKit Inside: CSS 样式表解码字符集的更多相关文章
- 2016年10月27日--css样式表
CSS样式表 样式表分类 1.内联样式表 和html联合显示,控制精确,但是可重用性差,冗余多. !doctype html> <html> <head> <met ...
- 3月22日 html(三)css样式表
CSS(Cascading Style Sheet,叠层样式表),作用是美化HTML网页. 一.样式表 (一)样式表的分类 1.内联样式表 和HTML联合显示,控制精确,但是可重用性差,冗余较多. 例 ...
- 【3-24】css样式表分类、选择器、样式属性
一.css样式表分类: (一)内联样式表:代码写在标签内的样式表 控制精确 代码重用性差 优先级最高 格式:<p style="样式属性">内容</p> ...
- HTML css 样式表
CSS样式表 2.1.样式表的基本概念 2.1.1.样式表分类 1.内联样式表 和html联合显示,控制精确,但是可重用性差,冗余多. 例:<p style="font-size:14 ...
- WEB入门 四 CSS样式表深入
学习内容 Ø CSS选择器深入学习 Ø CSS继承 Ø CSS文本效果 Ø CSS图片效果 能力目标 Ø 掌握CSS选择器的组合声 ...
- 3.22课·········CSS样式表
CSS(Cascading Style Sheet,叠层样式表),作用是美化HTML网页. /*注释区域*/ 此为注释语法 一.样式表 (一)样式表的分类 1.内联样式表 和HTML联合显示,控 ...
- 2016/2/19 css样式表 Cascading Style Sheet 叠层样式表 美化HTML网页
一.样式表 (一)样式表的分类 1.内联样式表 和HTML联合显示,控制精确,但是可重用性差,冗余较多. 例:<p style="font-size:14px;">内联 ...
- 网站开发综合技术 第二部分 CSS样式表
第2部分 CSS样式表 CSS(Cascading Style Sheets,层叠样式表),作用是美化HTML网页. /*注释*/ 注释语法 2.1.样式表的基本概念 2.1.1.样式表分类 1 ...
- 深度理解CSS样式表,内有彩蛋....
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- CSS样式表
CSS样式及属性 样式标的基本概念 样式表的分类 1.内联样式表 和html联合显示,控制精确,但可重用性差,冗余多. 例:<p style="font-size:14px;" ...
随机推荐
- WPF入门教程系列二十八 ——DataGrid使用示例MVVM模式(5)
WPF入门教程系列目录 WPF入门教程系列二--Application介绍 WPF入门教程系列三--Application介绍(续) WPF入门教程系列四--Dispatcher介绍 WPF入门教程系 ...
- Hive常见时间日期函数的使用与问题整理
这里整理一下Hive常见的时间函数和日期函数和用法,作为平时数据处理过程的一个检索和记录. 平时在数据处理过程中,如果不经常使用时间函数,一时间遇到一些时间上的处理,难免会想不起来. hive本身提供 ...
- Python初学者友好丨详解参数传递类型
摘要: 本文清晰地解释了Python中的不同参数传递类型,并提供了示例代码来说明每种类型的用法.对于初学者或不清楚Python传参的读者们来说是非常有益的,文中提供了足够的信息来理解和使用Python ...
- pcie reset系列之 内核框架
FLR是pci reset的一种. 关于FLR的寄存器操作比较简单, 相关的寄存器有: 配置空间里device cap里的FLR capability bit, 这个表示设备是否支持FLR. 配置空间 ...
- 【Java技术专题】「攻破技术盲区」带你攻破你很可能存在的Java技术盲点之动态性技术原理指南(反射技术专题)
@ 目录 带你攻破你很可能存在的Java技术盲点之动态性技术原理指南 编程语言的类型 静态类型语言 动态类型语言 技术核心方向 反射API 反射案例介绍 反射功能操作 获取构造器 长度可变的参数 - ...
- 2023-07-09:给定N、M两个参数, 一共有N个格子,每个格子可以涂上一种颜色,颜色在M种里选, 当涂满N个格子,并且M种颜色都使用了,叫一种有效方法。 求一共有多少种有效方法。 1 <= N,
2023-07-09:给定N.M两个参数, 一共有N个格子,每个格子可以涂上一种颜色,颜色在M种里选, 当涂满N个格子,并且M种颜色都使用了,叫一种有效方法. 求一共有多少种有效方法. 1 <= ...
- CF1728A Colored Balls: Revisited题解
去我的Blog观看 修改时间:2022/9/11修改了格式与标点 修改时间:2022/9/13修改了个别不严谨的语句 题目大意 有 \(n\) 种颜色的球,颜色为 \(i\) 的球为 \(cnt_i\ ...
- Day05_Java_作业
A:看程序写结果(写出自己的分析理由),程序填空,改错,看程序写结果. 1.看程序写结果 class Demo { public static void main(String[] args) { i ...
- 【环境搭建】vscode调试php
待解决问题 使用vscode和phpstudy实现PHP的本地调试 解决办法 1.打开xdebug 找到网站使用的PHP版本,在设置中将Xdebug调试组件打开,并确认端口是9000 找到php扩展目 ...
- 解决phpMyAdmin点击"结构"列页面失去响应的问题
最后更新时间 2017-12-05. 我的环境: phpMyAdmin:4.0.4.1 PHP:5.6.11 第一步 关闭自动更新 打开 ./libraries 目录下的 vendor_config. ...