一 . WebKit 简介
Webkit 是一个开放源代码的浏览器引擎 (web browser engine) ,最初的代码来自 KDE 的 KHTML 和 KJS( 均开放源代码 ) 。苹果公司在 Webkit 的基础上做了大量优化改进工作 ,此时的 Apple Webkit 已经和 Webkit 有了不少差别,最后开发出了著名的 Safari ,可以说 Safari 是一个相当成功的产品,但是 Safari 却不是开放源代码的。
基于 WebKit 的浏览器产品有:苹果的 Safari 和 iPhone , Google 的 Chrome 和 Android , Nokia 的 S60 ,傲游 3(Maxthon3) ;
WebKit 目前支持 HTML4/5 , CSS1/2 , DOM1/2 , HTTP/FILE , GIF/JPEG/PNG , XML , SVG , RSS2.0 等;
同类的浏览器引擎有: Trident ( IE 内核), Gechko ( Netscape, Mozilla 和 Firefox 内核), Presto ( Opera 内核,不免费), Tasman ( IE for MAC 内核),等等,而 WebKit 因为其功能强大、速度快而且免费备受欢迎。
二 . 用到的库:
除了平台相关的库, WebKit 需要用到的一些主要的后台库有:
ICU : International Components for Unicode , 一个成熟,广泛使用的一套为 C / C + + 和 Java 库提供 Unicode 的 全球化支持软件;
XSLT : eXtensible Stylesheet Language Transformation, W3C 定义的用于 XML 文档转换的规范;
Curl : 一个利用 URL 语法的命令行数据传输工具,基于 libcurl 。
Sqlite : SQLite 是实现了 SQL92 标准的 SQL 数据库引擎,它能在一个库里组合数据库引擎和接口 , 将所有数据存储于单个文件 ;
Gperf :一个很完美的哈希函数生成器;
Flex : Fast Lex, 快速词法分析生成器;
Bison :语法分析生成器,可以将一段带注释的上下文无关语法转化成 LALR 或 GLR 语法;
Enchant :一个拼写检查库,提供单词的拼写检查、纠错等功能;
三 . 代码目录结构
WebKitTools
一些测试 WebKit 实现功能的程序;
WebKitLibraries
WebKit 用到的库以及系统调用接口定义;
WebKitExamplePlugins
一些来自 Netscape 的插件,比如输入法、动画和 Cocoa 环境等;
WebKitSite: 保存了
www.webkit.org 网站的
WebKit
此目录位于 WebKit 的最上层,定义了与应用相关的一些接口,因此它是平台相关的,每个子目录都是对应平台的完整实现:
cf : Core Foundation, MAC OS X 上的系统级 C 语言 API 接口;
win : Windows ;
mac : MAC OS X ;
qt : Q Toolkit ,其公司已被 Nokia 收购;
gtk : Gimp Toolkit ;
scripts :一些脚本,目前只有一个关于 WebKit 版本的脚本程序;
chromium : Google Chrome 开发平台;
wx : wxWindows ,一种可移植的 C++ 和 Python GUI 工具箱, by Julian Smart ;
haiku :一种开源 OS ,从 BeOS 而来, 2001 开始, 2009 发布首版;
efl: Enlightenment Foundation Libraries, Enlightenment 平台;
WebCore
WebKit 的核心部分,定义了浏览相关的数据 IO 、页面加载、脚本分析、 UI 组织、事件处理、网络分析、平台相关的具体实现等内容。
xml :提供 xml 相关的内容;
html :提供 html 相关的内容;其下的 Canvas 目录定义了 3D 画布以及 WebGL 库相关的内容;
wml: Wireless Markup Language ;
css :提供 css 相关的内容;
dom :提供 dom 相关的内容;
editing :编辑相关的功能;
page :浏览相关内容,并非是我们看到的一个页面,在一次浏览会话中,它只有一个实例;
rendering :页面渲染相关的内容,在对页面脚本进行 DOM 树分析之后,需要对这些元素进行渲染和显示;
notification :内部模块间的事件通信;
history :页面浏览历史记录相关的内容;
svg :矢量图形功能,有选项, --svg ;
mathml : W3C 为网页中的数学表达式制定的规范;有编译选项, --mathml ;
loader : 加载资源及 Cache ;
workers :“ Web Workers 为 WEB 前端网页上的脚本提供了一种能在后台进程中运行的方法。一旦它被创建, Web Workers 就可以通过 postMessage() 向任务池发送任务请求,执行完之后再通过 postMessage() 返回消息给创建者指定的事件处理 程序 ( 通过 onmessage 进行捕获 ) 。
Web Workers 进程能够在不影响用户界面的情况下处理任务,并且,它还可以使用 XMLHttpRequest 来处理 I/O ,无论 responseXML 和 channel 属性是否为 null 。”
storage : Web Storage 相关的内容,保存页面的数据,可以看成是 Cookie 的升级;
websockets :与网络连接相关的内容;
bridge: 主要包含 NPPlugin(Netscape Plugin) 方面的接口访问等内容;
binding : Dom 与 JavaScriptCore 绑定的功能;
accessibility :提供控件的可用性相关的内容, accessibility 常用来形容对一些特殊人群的功能支持,比如残障者、老人等;
icu :里面放了专门为 Mac OS X 10.4 编译的 icu 相关头文件 ;
platform :提供了平台相关的具体实现,如事件响应、本地化、网络连接等;
plugins :插件相关内容;
ForwardingHeaders :头文件;
inspector : Inspector 是 WebKit 提供的查看网页源代码, DOM 树,以及调试脚本的工具,本目录包含了实现此功能的内容;
Configurations : X Code 环境相关的配置文件;
English.lproj :本地化文件;
manual-tests :测试用的 html 文件;
Resources :资源,图标;
WebCore.gyp :工程文件。 GYP ( Generate Youre Project )是 google 自己开发了一个脚本工具,这个工具也 是采用 python 编写的。它采用了自定义的一套规则,用于生成各种工程文件;
WebCore.vcproj : VC 工程文件;
WebCore.xcodeproj : X Code 工程文件;
WTF : Apple 的 C++ 库,可以看作精简的 STL ; SunSpider
一个 JavaScript 的检测程序,它不检测 DOM 或者浏览器其他的 API ,只用来检测 Javascript 。
JavaScriptGlue
JavaScriptCore :有关 JavaScript 的相关内容,包括了脚本解释器、分析器以及执行程序;
PlanetWebkit: 一个比较灵活的 RSS 阅读器; Webkit 网站上的 Planet :一站式的 Webkit 开发与动态信息;
四 . 体系结构
WebKit 主要包括三部分: WebKit , WebCore ,以及 JavaScriptCore ,加上所使用的库,依托的平台,其基本的体系结构 (Architecture) 如下所示:
注意有的模块相对于下面的模块有突出,这是因为此模块与下面几个模块直接相关,比如 WebCore 模块就与JavaScriptCore 、 Libraries 和 Platforms 模块直接相关。
usidc52011-10-28 21:08
五 . 调用过程
知道了 WebKit 的大体结构,我们就可以深究下去,看看这个浏览器引擎具体是怎么工作的。首先介绍几个基本且重要的类:
Page :打开 page.h 头文件,我们似乎看不到我们概念中的“页面”相关的东西,没错,这里的 Page 并非就是我们印象中的简单网页,在头文件中我们发现很多关于 history 的东西, goBack(),goForward(), 等等,关于主题的设定,关于Frame 的描述等等,因此,这里的 Page 更像是我们见到的浏览器,抽象起来,应该算是我们访问网站的一次浏览会话;
在 page.cpp 文件里,还有个重要的全局指针变量: static HashSet<Page*>* allPages; 这个变量包含了所有的page 实例,没错!就像 FireFox 一样,我们可以启动几个浏览器,而且就是在一个进程里;
allPages 在 Page 的构造函数里将每次新产生的 Page 对象加入;每次启动新的 window ,才会新建一个 Page 对象,并触发 PageGroup::addPage() ;
Frame :与 Page 相比, Frame 更像我们印象中的一个网页,它关注的是页面的显示 (FrameView) 、页面数据的加载(FrameLoader) 、页面内的各种控制器 (Editor, EventHandler, ScriptController, etc.) 等等,可以说,这个结构表示浏览器开始从外部控制转向关注一个页面的具体描述了;
Document :这个类的爷爷类是 Node ,它是 DOM 树各元素的基类; Document 有个子类是 HTMLDocument ,它是整个文档 DOM 树的根结点,这样就明白了:原来 Document 就是描述具体文档的代码,看一下它的头文件,就更明白了,它的属性与方法就是围绕着各种各样的结点: Text , Comment , CDATASection , Element……
当然, Document 不止描述了 HTML 相关的结点,还有 XHTML 、 SVG 、 WML 等等其他类型的页面;
另外, Node 的父类之一是 EventTarget ,也就是所有元素都有事件响应的能力,由于 Document 类作为 DOM 根结点的位置,因此在窗口事件发生时,它第一个接收到事件,并寻找到事件发生的目标元素,然后从目标元素开始以树的路径向上依次处理事件。
RenderObject :在形成 DOM 树结点的时候, Node 会根据需要调用 RenderObject 的方法,生成 Render 结点并最终形成 Render 树,因此此类是 Render 树各种结点类的基类,它的一个孙子类—— RenderView ,就是整个 Render 树的根结点。
对于调用过程,这里有一段话,我认为比较明确地描述了一个场景:
“ 浏览器的一个经典应用场景是用户给出一个 URL (直接输入或者点击链接或者 JavaScript 解析等方式)。然后浏览器外壳调用 FrameLoader 来装载页面。 FrameLoader 首先检查一些条件 (policyCheck()) ,如 URL 是否非空、 URL 是否可达,用户是否取消等等。然后通过 DocumentLoader 启动一个 MainResourceLoader 来装载页面。MainResourceLoader 调用 network 模块中的接口来下载页面内容( ResourceHandle ),实际上这里的Resourcehandle 已 经是平台相关的内容了,比如在 Qt 里面,会有 ResourceHandleQt 来控制,然后调用QtNetworkReplyHandler 来处理 HTTP 请求( GET , POST 等)。接收到数据以后,会有回调函数,告诉MainResourceLoader 数据已经接收到了。然后一路返回到 FrameLoader 开始调用 HTMLTokenizer 解析 HTML 文本。解析过程中,如果遇到 Javascript 脚本的话,也会调用 Javascript 引擎( Webkit 中的 JavascriptCore , chrome 中的 V8 )来解析。数据被解析完了以后,成了一个一个的 node ,生成 DOM 树和 Render 树,然后通过 FrameLoaderClient 调用外部的壳把内容显示出来。”
下面我们以 Qt 平台为例,看看这个场景下的具体函数调用关系:
首先是 整理并向服务器发送客户请求 :
WebCore:: FrameLoader::load()
→ WebCore:: FrameLoader::loadWithDocumentLoader() →WebCore:: FrameLoader::continueLoadAfterNavigationPolicy() →WebCore:: FrameLoader::continueLoadAfterWillSubmitForm() →WebCore:: DocumentLoader::startLoadingMainResource()
→ WebCore:: MainResourceLoader::load()
→ WebCore:: MainResourceLoader::loadNow()
这里,注意到本函数在调用 ResourceHandle::create() 时, MainResourceLoader 把自己作为 create() 的第二个参数传入,这个参数是 MainResourceLoader 的祖父类 ResourceHandleClient ,这样便于下面当调用祖父类的虚函数 didReceiveData() 时,实际调用的是 MainResourceLoader 的 didReceiveData() 方法。
继续:
→ WebCore:: ResourceHandle::create()
→ WebCore:: ResourceHandleQt::start()
→ WebCore:: QnetworkReplyHandler::start()
截至本函数,用户请求才会被最终发送出去 ,然后用 connect() 方法挂载了几个信号回调函数,比如针对 finished() 信号的 finish() 函数,针对 readyRead() 信号的 forwardData() 函数,针对 processQueuedItems() 信号的sendQueuedItems() 函数,其中最重要的就是 forwardData() 函数,此函数就是 对服务器返回数据的接收与处理 。
让我们来看看 返回数据的处理过程 :
WebCore:: QnetworkReplyHandler::forwardData()
→ WebCore:: (QNetworkReply)QIODevice::read(),ResourceHandleClient:: didReceiveData()
可见,首先 forwardData() 函数会利用 QIODevice 的 read() 方法从网络数据缓冲区中读取接收数据,然后调用didReceiveData() 方法,在类 ResourceHandleClient 中,这个方法实际上是个虚函数,因此实际调用的是其子类ResourceLoader 的同名函数:
→ WebCore:: ResourceLoader::didReceiveData(ResourceHandle*, const char* data, int length, int lengthReceived)
→ WebCore:: MainResourceLoader::didReceiveData()
→ WebCore:: ResourceLoader::didReceiveData(const char* data, int length, long long lengthReceived, bool allAtOnce)
在这个函数中,有个直接调用 addData(data, length, allAtOnce); 虽然这个语句在 ResourceLoader 中,但是实际上调用的并非 ResourceLoader::addData(), 而是 MainResourceLoader::addData() ,又一个虚函数覆盖的例子:
→ WebCore:: MainResourceLoader::addData()
→ WebCore:: ResourceLoader::addData(), FrameLoader::receivedData()→WebCore:: DocumentLoader::receivedData()
→ WebCore:: DocumentLoader::commitLoad()
→ WebCore:: FrameLoader::committedLoad()
→ WebCore:: FrameLoaderClient::committedLoad()
→ WebCore:: FrameLoaderClientQt::committedLoad()
→ WebCore:: FrameLoader::addData()
→ WebCore:: DocumentWriter::addData()
至此,一次 URL 请求就完成了初始化设置,请求发送,以及数据接收,接下来就是 HTML / JS 分析 。
→ WebCore:: Tokenizer::write()
→ WebCore:: HTMLTokenizer::write()
在此函数中有个循环,针对每个 Tag 进行分析,下面是对某个 Tag 的分析过程:
→ WebCore:: HTMLTokenizer::advance()
→ WebCore:: HTMLTokenizer::parseTag(),HTMLTokenizer::processToken()
→ WebCore:: HTMLParser::parseToken()
→ WebCore:: HTMLParser::insertNodeAfterLimitDepth()
→ WebCore:: HTMLParser::insertNode()
→ WebCore:: Element::attach()
当分析了一个 Tag ,如果不是 HTML 的 Tag ,则调用相关的 parse 函数解析(如 parseNonHTMLText );如果它是HTML 的 Tag ,就将其加入 Dom 树的一个节点,接下来根据这个节点 生成 Render 树节点 :
→ WebCore:: Node::createRendererIfNeeded()
→ WebCore::Text::createRenderer()
→ WebCore::RenderText::RenderText()
另外,在 HTMLTokenizer::parseTag() 中,也会调用 HTMLTokenizer::parseNonHtmlText, 之后调用:
→ WebCore::HTMLTokenizer::scriptHandler()
→ WebCore::HTMLTokenizer::scriptExecution()
→ WebCore::ScriptController::executeScript()
→ WebCore::ScriptController::evaluate()
→ WebCore::ScriptController::evaluateInWorld()
→ WebCore::JSMainThreadExecState::evaluate()
→ JSC::evaluate()
→ JSC::Interpreter::execute()
→ JSC::JITCode::execute()
→ JSC::JITThunks::tryCacheGetByID()
→ cti_op_put_by_id()
→ JSC::JSValue::put()
→ WebCore::JSHTMLInputElement::put()
→ JSC::lookupPut<WebCore::JSHTMLInputElement, WebCore::JSHTMLElement> ()
→ JSC::lookupPut<WebCore::JSHTMLInputElement>()
→ WebCore::setJSHTMLInputElementSelectionStart()
→ WebCore::JSHTMLInputElement::setSelectionStart()
→ WebCore::HTMLTextFormControlElement::setSelectionStart()
→ WebCore::HTMLTextFormControlElement::textRendererAfterUpdateLayout()
→ WebCore::Document::updateLayoutIgnorePendingStylesheets()
→ WebCore::Document::updateLayout()
→ WebCore::FrameView::layout ()
之后有可能会调用 FrameView::adjustViewSize(), FrameView::setContentsSize(), ScrollView::updateScrollbars(), FrameView::visibleContentsResized(), FrameView::endDeferredRepaints(), FrameView::doDeferredRepaints() 等函数, 然后调用:
→ WebCore::ScrollView::repaintContentRectangle()
→ WebCore::Chrome::invalidateContentsAndWindow()
在此函数中,有关键的一句: emit m_webPage->repaintRequested(windowRect) ,意思是 将 paint 的信号最终发送出去 。
在 qt 中,函数 QEventLoop::exec() 负责对事件的检测,当检测到事件发生(信号),会调用以下函数进行处理:
→ QeventLoop::processEvents()
→ ?
→ QEventDispatcherGlib::processEvents
→ g_main_context_iteration()
→ ?
→ g_main_context_dispatch()
→ ?
→ QCoreApplication::sendPostedEvents()
→ QCoreApplicationPrivate::sendPostedEvents()
→ QCoreApplication::notifyInternal()
→ QApplication::notify()
→ QApplicationPrivate::notify_helper()
→ QMainWindow::event(QEvent*)
→ QWidget::event(QEvent*)
→ QWidgetPrivate::syncBackingStore()
→ ?
→ QWidgetPrivate::drawWidget()
→ QCoreApplication::notifyInternal()
→ QApplication::notify()
→ QApplicationPrivate::notify_helper()
→ QWebView::event()
→ Qwidget::event()
以上是 Qt 事件处理的通用过程,从下面的函数开始, Qt 识别出此信号是 paint 信号:
→ QWebView::paintEvent()
→ QWebFrame::render()
→ QWebFramePrivate::renderRelativeCoords()
→ WebCore::FrameView::paintContents()
→ WebCore::RenderLayer::paint()
→ WebCore::RenderLayer::paintLayer()
→ WebCore::RenderLayer::paintList()
→ WebCore::RenderLayer::paintLayer()
→ WebCore::RenderLayer::paintList()
→ WebCore::RenderLayer::paintLayer()
→ WebCore::RenderBlock::paint()
→ WebCore::RenderBlock::paintObject()
→ WebCore::RenderBlock::paintContents()
→ WebCore::RenderBlock::paintChildren()
→ WebCore::RenderBlock::paint()
→ WebCore::RenderBlock::paintObject()
→ WebCore::RenderBlock::paintContents()
→ WebCore::RenderBlock::paintChildren()
→ WebCore::RenderBlock::paint()
→ WebCore::RenderBlock::paintObject()
→ WebCore::RenderBlock::paintContents()
→ WebCore::RenderLineBoxList::paint()
→ WebCore::RootInlineBox::paint()
→ WebCore::InlineFlowBox::paint()
→ WebCore::InlineFlowBox::paint()
→ WebCore::InlineTextBox::paint()
→ paintTextWithShadows()
→ WebCore::GraphicsContext::drawText()
→ WebCore::Font::drawText()
→ WebCore::Font::drawComplexText()
→ QPainter::drawText()
可以看到,以上有的函数会重复调用,因为现在所展示的只是一个执行流程,于 WebKit 全体只是冰山一角。到此, WebKit最终调用 Qt 的 QPainter 画出文字。
这样,从最初的数据载入到将一个文字最终画出,基本上完成了,其他如图片的过程类似。
之后,在 resize 、 mouse-click 等事件的驱动下, WebKit 仍然会不停地进行 relayout 和 repaint 。
usidc52011-10-28 21:09
支持CSS属性
Safari和WebKit实施大子的CSS 2.1规格所界定的万维网联盟( W3C ) ,以及部分的CSS 3规格。 。
这个CSS属性本条划分的群体界定由W3C的CSS规格:
*“盒模型”的具体描述性质的包围盒块内容,包括边界,填充,和利润率。附加框相关属性的特定表中分别介绍了“表。 ”
*“视觉格式化模型”描述性质,确定了位置和大小的块元素。
*“视觉效果”描述属性,调整的视觉效果块内容,包括溢出行为,调整行为,能见度,动画,变换,和过渡。
*“生成的内容,自动编号,并列出”描述属性,允许您更改内容的一个组成部分,创建自动编号的章节和标题,和操纵的风格清单的内容。
*“分页媒体”描述性能与外观的属性,控制印刷版本的网页,如分页符的行为。
*“颜色和背景”描述属性控制背景下的块级元素和颜色的文本内容的组成部分。
* “字型”的具体描述性质的文字字体的选择范围内的一个因素。报告还描述属性用于下载字体定义。
*“文本”描述属性的特定文字样式,间距和自动滚屏(帐篷) 。
*“表格”描述的布局和设计性能表的具体内容。
*“用户界面”描述属性,涉及到用户界面元素在浏览器中,如滚动文字区,滚动条,等等。 报告还描述属性,范围以外的网页内容,如光标的标注样式和显示当您按住触摸触摸目标,如在iPhone上的链接。
★1,webkit Box模型
CSS定义:-webkit-border-bottom-left-radius: radius;
CSS定义:-webkit-border-top-left-radius: horizontal_radius vertical_radius;
CSS定义:-webkit-border-radius:radius;
CSS定义:-webkit-box-sizing: sizing_model; 边框常量值:border-box
CSS定义:-webkit-box-sizing: sizing_model; 内容常量值:content-box
CSS定义:-webkit-box-shadow: hoff voff blur color;
CSS定义:-webkit-margin-bottom-collapse: collapse_behavior;常量值:collapse
CSS定义:-webkit-margin-bottom-collapse: collapse_behavior;常量值:discard
CSS定义:-webkit-margin-bottom-collapse: collapse_behavior;常量值:separate
CSS定义:-webkit-margin-start: width;
CSS定义:-webkit-padding-start: width;
CSS定义:-webkit-border-image:url(borderimg.gif) 25 25 25 25 round round;
CSS定义:-webkit-border-image:url(borderimg.gif) 25 25 25 25 stretch stretch;
★2,可视化格式模型
CSS定义:direction:rtl
CSS定义:unicode-bidi:bidi-override常量:bidi-override,embed,normal
★3,视觉效果
CSS定义:clip: rect(10px, 5px, 10px, 5px)
CSS定义:resize:auto;常量:auto, both, horizontal, none, vertical
CSS定义:visibility:visible;常量: collapse, hidden, visible
CSS定义:-webkit-transition: opacity 1s linear; 动画效果 ease,linear,ease-in,ease-out,ease-in-out
CSS定义:-webkit-backface-visibility: visibler; 常量:visible(默认值),hidden
CSS定义:-webkit-box-reflect: right 1px; 镜向反转
CSS定义:-webkit-box-reflect:below 4px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(0.5, transparent), to(white));
CSS定义:-webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,1)), to(rgba(0,0,0,0)));;CSS遮罩/蒙板效果
CSS定义:-webkit-mask-attachment:fixed; 常量:fixed,scroll
CSS定义:-webkit-perspective: value; 常量:none(默认)
CSS定义:-webkit-perspective-origin:left top;
CSS定义:-webkit-transform:rotate(5deg);
CSS定义:-webkit-transform-style:preserve-3d; 常量:flat,preserve-3d;(2D与3D)
★4,生成目录
CSS定义:content: “Item” counter(section) ” “;
This resets the counter.
First section
>two section
three section
CSS定义:counter-increment: section 1;
CSS定义:counter-reset:section;
★5,分页媒体
CSS定义:page-break-after:auto; 常量:always, auto, avoid, left, right
CSS定义:page-break-before:auto; 常量:always, auto, avoid, left, right
CSS定义:page-break-inside:auto; 常量:auto, avoid
★6,颜色与背景
CSS定义:-webkit-background-clip:content; 常量:border,content,padding,text
CSS定义:-webkit-background-origin:padding; 常量:border,content,padding,text
CSS定义:-webkit-background-size:55px; 常量:length,length_x,length_y
★7,字体
CSS定义:unicode-range: U+00-FF, U+980-9FF;
★8,文字
CSS定义:text-shadow:#00FFFC 10px 10px 5px;
CSS定义:text-transform:capitalize; 常量:capitalize, lowercase, none, uppercase
CSS定义:word-wrap:break-word; 常量:break-word, normal
CSS定义:-webkit-marquee:right large infinite normal 10s; 常量:direction(方向) increment(迭代次数) repetition(重复) style(样式) speed(速度);
-webkit-marquee-direction:ahead,auto,backwards,down,forwards,left,reverse,right,up
-webkit-marquee-incrementt:1-n,infinite[无穷次]
-webkit-marquee-speed:fast,normal,slow
-webkit-marquee-style:alternate,none,scroll,slide
CSS定义:-webkit-text-fill-color:#ff6600; 常量:capitalize, lowercase, none, uppercase
CSS定义:-webkit-text-security:circle; 常量:circle,disc,none,square
CSS定义:-webkit-text-size-adjust:none; 常量:auto,none;
CSS定义:-webkit-text-stroke:15px #fff;
CSS定义:-webkit-line-break:after-white-space; 常量: normal,after-white-space
CSS定义:-webkit-appearance:caps-lock-indicator;
CSS定义:-webkit-nbsp-mode:space; 常量: normal,space
CSS定义:-webkit-rtl-ordering:logical; 常量:visual,logical
CSS定义:-webkit-user-drag:element; 常量:element,auto,none
CSS定义:-webkit-user-modify:read-write-plaintext-only; 常量:read-write-plaintext-only,read-write,read-only
CSS定义:-webkit-user-select:text; 常量:text,auto,none
★9,表格
CSS定义:-webkit-border-horizontal-spacing:2px;
CSS定义:-webkit-border-vertical-spacing:2px;
CSS定义:-webkit-column-break-after:right; 常量:always,auto,avoid,left,right
CSS定义:-webkit-column-break-before:right; 常量:always,auto,avoid,left,right
CSS定义:–webkit-column-break-inside:logical; 常量:avoid,auto
CSS定义:-webkit-column-count:3;
CSS定义:-webkit-column-rule:1px solid #fff; style:dashed,dotted,double,groove,hidden,inset,none,outset,ridge,solid
★10,用户接口
CSS定义:-webkit-box-align:baseline,center,end,start,stretch 常量:baseline,center,end,start,stretch
CSS定义:-webkit-box-direction:normal;常量:normal,reverse
CSS定义:-webkit-box-flex:flex_valuet
CSS定义:-webkit-box-flex-group:group_number
CSS定义:-webkit-box-lines:multiple;常量:multiple,single
CSS定义:-webkit-box-ordinal-group:group_number
CSS定义:-webkit-box-orient:block-axis; 常量:block-axis,horizontal,inline-axis,vertical;-webkit-box-orient: orientation;
CSS定义:–webkit-box-pack: alignment; 常量:center,end,justify,start
支持;safari3.0+,iPhone OS 1.0+
usidc52011-10-28 21:15
阅读了Graphics in Google Chrome 之后,觉得作为浏览器内核WebKit、Gecko,为了能高效美观的显示页面的内容,选择适当的图形库非常重要。如果图形库选择不当,往往会导致页面上显示的文字、图片不美观,看起来总让人觉得别扭,更为糟糕的是排列布局出现紊乱,简直无法阅览。
从浏览器发展的历史来看,IE系列浏览器的网页布局、文字图片显示的美观程度还是相当高的,也许这与Microsoft图形显示方面的功力相关,到目前为止linux桌面显示还是与传统的windows桌面显示有相当的差距。
相 比较Firefox1.5,Firefox3.0图形显示方面也有相当大的进步,这应该归功于完全采取Cario图形库来显示页面,目前应当完全达到了 IE6的显示效果。可见图形显示的好与坏,直接决定了一款浏览器的质量以及用户接受程度。那究竟什么是图形库?其主要功能是什么?目前WebKit、 Gecko可使用哪些图形库?它们在浏览器中是如何发挥其应有的作用呢?
一、图形库概述及其主要功能
A graphics library is a program designed to aid in rendering computer graphics to a monitor. This typically involves providing optimized versions of functions that handle common rendering tasks.
This can be done purely in software and running on the CPU, common in embedded systems, or being hardware accelerated by a GPU, more common in PCs. By employing these functions, a program can assemble an image to be output to a monitor. This relieves the programmer of the task of creating and optimizing these functions, and allows them to focus on building the graphics program.
目前主要的图形库有:
windows提供的GDI/GDI+、DirectX、OpenGL;
支持X的有Cario、GTK、QT、OpenGL;
其他的还有Skia(google提供)、Quartz 2D(apple提供)、wxWidget等;
一 般说来图形库只提供绘画图形,渲染文字、图片等,不管是2D还是3D,其往往不提供消息处理,简单的说来就是如何高效的在一块指定的画布上将线条、文字、 图片显示出来,其中往往涉及字体、颜色等;典型的图形库如GDI/GDI+、Cario、DirectX、Quartz 2D等;
而按钮、菜单、窗口等图形组件往往是基于图形库的基础上绘画出来的并有相对固定形状,同时一般具有消息处理功能;相关实现有GTK、QT、wxWidget、windows组件等;
其中GTK、QT、wxWidget、Skia等不仅提供图形组件,同时提供图形库的功能;而Cario则是一个纯粹的图形库,类似与Quartz 2D,目前GTK2则完全基于Cario来实现;
由 于浏览器页面元素的数量存在不确定性,将页面上的一些元素对应成图形组件可能导致一个页面使用组件过多的问题(早期的IE就曾出现使用GDI对象过多的现 象)。因此尽可能的将一个页面的所有元素显示在一个图形组件上,至于其显示交给图形库来处理,其消息响应交互交给DOM及原生窗口消息循环来完成。
从这里我们可以进一步的确认图形库在浏览器中的重要性,以及随着用户需求的增加及硬件的提升,浏览器中使用3D效果应该是一个大的方向。
二、Gecko中使用图形库Cario
1、Cario概述
Cairo is a 2D graphics library with support for multiple output devices. Currently supported output targets include the X Window System , Quartz , Win32 , image buffers, PostScript, PDF, and SVG file output. Experimental backends include OpenGL (through glitz ), XCB, BeOS, OS/2, and DirectFB.
Cairo is designed to produce consistent output on all output media while taking advantage of display hardware acceleration when available (eg. through the X Render Extension).
其主要优点在于其在X、Win32、Quartz的基础上统一了图形库的操作方式,同时支持PS、PDF、SVG、PNG/JPEG等图像格式的输出,极大的方便页面的再次利用,在glitz的支持下支持部分3D效果。
2、Cario在Gecko中的使用
首先 提供一个gfxASurface抽象类,代表一块可以作画的画布;提供一个gfxContext类,它用来管理究竟如何作画,如画圆形、旋转,维护画布的状态、当前颜色、路径等,其往往需要一个gfxASurface子类实例来初始化;
其次 不同的图形输出实现不同的gfxASurface子类如gfxWindowsSurface、gfxXlibSurface、gfxQuartzSurface、gfxGlitzSurface、gfxQuartzPDFSurface、gfxPSSurface等;
其次 提供一个DeviceContextImpl类实现nsIDeviceContext接口,以描述指定原生Widget相关的字体属性及创建可以在该原生Widget上作画的nsIRenderingContext接口实现;
而nsThebesRenderingContext类实现了nsIRenderingContext接口,以供外部(如不同的DOM Node页面元素对应的不同Frame)在其上显示文字、图像、作图形等;
然后 当解析、布局完DOM页面元素后需要画出不同的页面元素时则由DeviceContextImpl类实例来创建nsThebesRenderingContext类实现,并初始化它,其初始化代码如下:
nsThebesRenderingContext::Init(nsIDeviceContext* aContext, nsIWidget *aWidget)
{
nsThebesDeviceContext *thebesDC = static_castnsIRenderingContext接口究竟有哪些主要方法?
// RenderingContext interface
class nsIRenderingContext : public nsISupports
{
public:
.........................................................................
/**
* Initialize the RenderingContext
* @param aContext the device context to use.
* @param aWidget the widget to hook up to
* @result The result of the initialization, NS_Ok if no errors
*/
NS_IMETHOD Init(nsIDeviceContext* aContext, nsIWidget *aWidget) = 0;
/**
* Get the DeviceContext that this RenderingContext was initialized
* with. This function addrefs the device context. Though it might
* be better if it just returned it directly, without addrefing.
* @result the device context
*/
NS_IMETHOD GetDeviceContext(nsIDeviceContext *& aDeviceContext) = 0;
/**
* Sets the forground color for the RenderingContext
* @param aColor The color to set the RenderingContext to
*/
NS_IMETHOD SetColor(nscolor aColor) = 0;
/**
* Get the forground color for the RenderingContext
* @return The current forground color of the RenderingContext
*/
NS_IMETHOD GetColor(nscolor &aColor) const = 0;
/**
* Sets the font for the RenderingContext
* @param aFont The font to use in the RenderingContext
*/
NS_IMETHOD SetFont(const nsFont& aFont, nsIAtom* aLangGroup) = 0;
/**
* Sets the font for the RenderingContext
* @param aFontMetric The font metrics representing the
* font to use in the RenderingContext
*/
NS_IMETHOD SetFont(nsIFontMetrics *aFontMetrics) = 0;
/**
* Get the current fontmetrics for the RenderingContext
* @return The current font of the RenderingContext
*/
NS_IMETHOD GetFontMetrics(nsIFontMetrics *&aFontMetrics) = 0;
/**
* Add in a translate to the RenderingContext's transformation matrix
* @param aX The horizontal translation
* @param aY The vertical translation
*/
NS_IMETHOD Translate(nscoord aX, nscoord aY) = 0;
/**
* Add in a scale to the RenderingContext's transformation matrix
* @param aX The horizontal scale
* @param aY The vertical scale
*/
NS_IMETHOD Scale(float aSx, float aSy) = 0;
/**
* Draw a line
* @param aXO starting horiztonal coord in twips
* @param aY0 starting vertical coord in twips
* @param aX1 end horiztonal coord in twips
* @param aY1 end vertical coord in twips
*/
NS_IMETHOD DrawLine(nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1) = 0;
/**
* Draw a rectangle
* @param aRect The rectangle to draw
*/
NS_IMETHOD DrawRect(const nsRect& aRect) = 0;
/**
* Draw a string in the RenderingContext
* @param aString The string to draw
* @param aLength The length of the aString
* @param aX Horizontal starting point of baseline
* @param aY Vertical starting point of baseline.
* @param aSpacing inter-character spacing to apply
*/
NS_IMETHOD DrawString (const char *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
const nscoord* aSpacing = nsnull) = 0;
/*
* Tiles an image over an area
* @param aImage Image to tile
* @param aXImageStart x location where the origin (0,0) of the image starts
* @param aYImageStart y location where the origin (0,0) of the image starts
* @param aTargetRect area to draw to
* @param aSubimageRect the subimage (in tile space) which we expect to
* sample from; may be null to indicate that the whole image is
* OK to sample from
*/
NS_IMETHOD DrawTile (imgIContainer *aImage,
nscoord aXImageStart, nscoord aYImageStart,
const nsRect * aTargetRect,
const nsIntRect * aSubimageRect) = 0;
...............................................................................
};
其中DrawString、DrawTile方法最常用,其分别对应如何显示文字及图像。
针对图形库显示文字的基本原理可以参考Font technology and Freetype 及FreeType Glyph Conventions 。
至于图形库如何显示不同格式的图像可参考如gif 、jpeg 、png 等。
Gecko对Cario的使用还体现在对canvas标签的实现,具体可参考nsCanvasRenderingContext2D.cpp、nsHTMLCanvasElement.cpp等。
三、WebKit中使用图形库
1、WebKit支持的图形库
目 前WebKit支持的图形库包括Cairo、Gtk、Qt、Wx、Cg、Mac、Skia等,虽然不同的图形库能支持不同的平台,但其在不同平台上的显示 效果也不尽相同。至于在一个指定的平台上究竟使用何种库,则显示出很大的灵活性。就目前来看,在windows平台上可选的图形库有Cairo、Qt、 Wx、Cg、Skia等,其中Graphics in Google Chrome 阐述了Chrome关于图形库的选择。
其实从WebKit的角度来看,它通过提供一组与Gecko中nsIRenderingContext类似的公共图形接口,而不同的图形库则根据自身的不同实现了这些公共图形接口,以提供给WebCore元素使用,从而可以让WebKit支持不同的图形库。
2、WebKit支持不同图形库的实现
在WebKit中提供了一个GraphicsContext类,其中包括所有的图形接口,完全类似nsIRenderingContext,针对不同平台的特性,其定义中包含一些不同平台特有的
宏及元素定义。
在 目录webcore/platform/graphics/下的子目录Cairo、Cg、Gtk、Mac、Qt、Win、Wx分别提供了 GraphicsContext类部分方法的实现,而公共的实现则在webcore/platform/graphics /GraphicsContext.cpp中提供。
其中我们非常值得关注的方法有drawText与drawImage,其实现如下:
void GraphicsContext::drawText(const TextRun& run, const IntPoint& point, int from, int to)
{
if (paintingDisabled())
return;
font().drawText (this, run, point, from, to);
}
void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
{
if (paintingDisabled() || !image)
return;
float tsw = src.width();
float tsh = src.height();
float tw = dest.width();
float th = dest.height();
if (tsw == -1)
tsw = image->width();
if (tsh == -1)
tsh = image->height();
if (tw == -1)
tw = image->width();
if (th == -1)
th = image->height();
if (useLowQualityScale) {
save();
setUseLowQualityImageInterpolation(true);
}
image->draw (this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op);
if (useLowQualityScale)
restore();
}
最 终的实现转交给类Font、Image的方法drawText、draw来实现,而不同实现如Cairo、Cg、Gtk、Mac、Qt、Win、Wx则会 针对类Font、Image分别提供部分对应的实现,而公共的实现则在webcore/platform/graphics/Font.cpp及 Image.cpp中提供。
3、不同平台GraphicsContext实例创建及使用
GraphicsContext 创建的时机往往在对应平台的WebView获得Paint消息事件时,进而将该GraphicsContext类实例传递给FrameView及其不同的 RenderObject实例,由不同的RenderObject实例来决定究竟如何来显示自身的内容,而GraphicsContext类实例提供了各 种的显示文字、图形、图像的方法以供RenderObject实例调用。其调用关系基本上与Gecko中的不同Frame对象使用 nsIRenderingContext接口方法类似。
创建GraphicsContext实例的示例如下:
//Gtk
static gboolean webkit_web_view_expose_event(GtkWidget* widget, GdkEventExpose* event)
{
WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
WebKitWebViewPrivate* priv = webView->priv;
Frame* frame = core(webView)->mainFrame();
GdkRectangle clip;
gdk_region_get_clipbox(event->region, &clip);
cairo_t* cr = gdk_cairo_create(event->window);
GraphicsContext ctx(cr);
ctx.setGdkExposeEvent(event);
if (frame->contentRenderer() && frame->view()) {
frame->view()->layoutIfNeededRecursive();
if (priv->transparent) {
cairo_save(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
cairo_restore(cr);
}
frame->view()->paint(&ctx, clip);
}
cairo_destroy(cr);
return FALSE;
}
//win
void WebView::paintIntoBackingStore(FrameView* frameView, HDC bitmapDC, const IntRect& dirtyRect)
{
LOCAL_GDI_COUNTER(0, __FUNCTION__);
RECT rect = dirtyRect;
#if FLASH_BACKING_STORE_REDRAW
HDC dc = ::GetDC(m_viewWindow);
OwnPtr yellowBrush = CreateSolidBrush(RGB(255, 255, 0));
FillRect(dc, &rect, yellowBrush.get());
GdiFlush();
Sleep(50);
paintIntoWindow(bitmapDC, dc, dirtyRect);
::ReleaseDC(m_viewWindow, dc);
#endif
FillRect(bitmapDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
if (frameView && frameView->frame() && frameView->frame()->contentRenderer()) {
GraphicsContext gc(bitmapDC);
gc.save();
gc.clip(dirtyRect);
frameView->paint(&gc, dirtyRect);
gc.restore();
}
}
//wx
void wxWebView::OnPaint(wxPaintEvent& event)
{
if (m_beingDestroyed || !m_impl->frame->view() || !m_impl->frame)
return;
wxAutoBufferedPaintDC dc(this);
if (IsShown() && m_impl->frame && m_impl->frame->document()) {
#if USE(WXGC)
wxGCDC gcdc(dc);
#endif
if (dc.IsOk()) {
wxRect paintRect = GetUpdateRegion().GetBox();
WebCore::IntSize offset = m_impl->frame->view()->scrollOffset();
#if USE(WXGC)
gcdc.SetDeviceOrigin(-offset.width(), -offset.height());
#endif
dc.SetDeviceOrigin(-offset.width(), -offset.height());
paintRect.Offset(offset.width(), offset.height());
#if USE(WXGC)
WebCore::GraphicsContext* gc = new WebCore::GraphicsContext(&gcdc);
#else
WebCore::GraphicsContext* gc = new WebCore::GraphicsContext((wxWindowDC*)&dc);
#endif
if (gc && m_impl->frame->contentRenderer()) {
if (m_impl->frame->view()->needsLayout())
m_impl->frame->view()->layout();
m_impl->frame->paint(gc, paintRect);
}
}
}
}
//Qt
void QWebFrame::render(QPainter *painter, const QRegion &clip)
{
if (!d->frame->view() || !d->frame->contentRenderer())
return;
d->frame->view()->layoutIfNeededRecursive();
GraphicsContext ctx(painter);
QVector vector = clip.rects();
WebCore::FrameView* view = d->frame->view();
for (int i = 0; i <>paint(&ctx, vector.at(i));
}
/*!
Render the frame into /a painter.
*/
void QWebFrame::render(QPainter *painter)
{
if (!d->frame->view() || !d->frame->contentRenderer())
return;
d->frame->view()->layoutIfNeededRecursive();
GraphicsContext ctx(painter);
WebCore::FrameView* view = d->frame->view();
view->paint(&ctx, view->frameGeometry());
}
4、WebKit 3D Port实现
在Clutter WebKit port 中提供了WebKit 对3D Port的支持与实现,其实现类似于Gtk+/Cairo图形库的实现,但其3D效果仅实现在Port层,没有对页面上的元素如文字、图像实现3D效果支持。
这里只是简单的了解WebKit中如何整合不同的图形库及其与WebCore的交互。要想更加深入的了解页面上的文字、图形、图像究竟是如何显示出来的,则需要更进一步的针对不同平台库进行学习与了解。
WebKit 中也支持canvas标签,该标签提供的接口与Gecko能提供的几乎一致,其具体实现可参考webcore/html /CanvasRenderingContext2D.cpp,结合GraphicsContext类的实现,应该能对canvas标签的实现有充分的理 解。
四、总结
其实关于图形库及其使用的内容非常的多,而对浏览器内核来讲能对图形库进行高效使用也是非常重要的一部分,所以在这里所谈到的内容也许只是一些皮毛,但希望能在此开阔一下了解浏览器内核特别是图形库使用方面的思路。