[转载]浅谈Google Skia图形处理引擎

  2008 年九月, Google 宣布以改良过的 WebKit 为核心的网路浏览器 Chrome ,揭露了众多新特征,比方说崭新的 [ V8 ] JavaScript (ECMAscript) 执行引擎,或许因为太亮眼,掩蔽了所使用另一个开放源代码专案 [ skia ] ,后者是个 2D 向量图形处理函数库,包含字型、坐标转换,以及点阵图都有高效能且简洁的表现。不仅用于 Google Chrome 浏览器,新兴的 Android 开放手机平台也采用 skia 作为绘图处理,搭配 OpenGL/ES 与特定的硬体特征,强化显示的效果,本文简介 Google Skia 的历史背景、应用层面,并探讨其程序设计模型。 

Google
 为了搭建 Open Handset Alliance (OHA)  Android 平台,布局极久,背后的百人研发团队部份来自之前的并购案,其中两项具指标性意义: 

  • 2005 年八月 17 日,收购美国 Android 公司,业务是手机软体开发,这当然就是现在开放源码的 Android 计划的前身
  • 2005 年十一月,收购美国 Skia 公司,业务是向量绘图软体

  被 Google 收购前的 Android 公司有着在 IT 产业为人所津津乐道的成果,本文就不多谈,而 Skia 公司自然也不是省油的灯。 Skia Inc. 设立于北卡罗莱纳州的 Chapel Hill ,由 Michael Reed ( 也称为 Mike Reed) 所创办,他在图形技术领域是相当顶尖的人物,与 Benoit Schillings (BeOS 主要开发者, Be Inc . 第二位工程师,现为 Nokia CTO) 于专业手机软体开发公司 OpenWave 共事时,即在该公司产品 OpenWave Phone Suite Version 7.0 ( 以下简称 V7) 引入精湛的向量图形技术,在 50-300 kb 空间的实做中,提供了图层 overlay 之间 alpha blended 预览、全功能向量矩阵转换等进阶功能。在加入 OpenWave 之前, Mike Reed 服务于 Apple ,代表专案为 Quick Draw GX ,主导进阶图形与字型处理。 Benoit Schillings 离开 OpenWave 转任 Trolltech CTO 期间, Mike Reed 开创了 Skia Inc. ,该公司第一个产品为 SGL (Skia Graphics Library) ,一个非常严谨的向量显示引擎,能在低端设备比如手机、电视及其它手持设备之上,呈现高品质的 2D 图形。根据 LocalTechWire 的描述: 

"Skia's first product, SGL, is a portable graphics engine capable of rendering state-of-the-art 2D graphics on low-end devices such as mobile phones, TVs, and handhelds,” the Web site said. “SGL is feature- set compatible with existing 2D standards, making it ideal to serve as a back-end for public formats such as SVG, PDF, and OpenVG. SGL is licensed as source or binary, and can be customized to match specific HW/framebuffer requirements.”

 2005  Skia  Google 收购后,一直相当神秘低调,直到 2007 年初, Skia GL 相关的源代码才被揭露,作为 Google Android 平台的图形引擎,稍候的 Google Chrome 浏览器也采用 Skia 引擎。随着 Android  Chrome( 开放版本称为 "Chromium") 两大专案公布源代码后, skia 也一并公开原始程式码,以 Apache License V2 释出 ( 注意,这意味着与 GPLv2 授权不相容 ,而 Android  Chrome 的程式码库中都有一份 [ skia ] 的复制,因需求不同,做了部份的修改,比方说 Chrome 专案底下的 [ chrome/trunk/src/skia ] ,需要注意的是, Skia 本身是不涉及底层环境,如 Linux Framebuffer  Gtk+ 衔接的处理,这也是何以 Android ( 透过 Linux Framebuffer)  Chrome ( 开发中的 Linux 版本使用 Gtk+) 需要提供一份修改,以便系统接轨,关于这方面的资讯,可参照 Google Chromium 的开发日志 [ Graphics in Google Chrome ]

相较于 Firefox 1.x ,后继的 Firefox 2.x/3.x 在图形显示方面有相当大的进展,很大层面归功于引入 Cario 向量图形程式库来处理网页绘制,而 Skia 就相当于扮演 Cairo 的角色,不过更轻量些。快速发展的 WebKit 俨然是从桌面应用跨足移动装置之网页引擎解决方案的首选, Apple  Google 都有为数可观的全职工程师投入,拜网际网路的威力,也有其他厂商与团体个人积极投入开发,目前 WebKit 支持的图形函式库计有 Cairo, Gtk+, Qt4, WxWidgets, Cg (Mac 的非开放原始码函式库 ), Skia 等等,并以 WebKit  class GraphicsContext 处理前述图形函式库的实做,可针对不同平台的特性,规范不同平台所需的巨集与成员,详情可参考程式码 WebCore/platform/graphics/GraphicsContext.{h,cpp}  
Skia
  C++ 实做,程式码约八万行,基本某些未知的因素,可参考的文件相当有限,但 Chromium  SVN log 与程式码则是现在最完整的文件,以下是其特征: 

  • 高度优化的软体 rasteriser (module sgl/)
  • 选择性透过 OpenGL/ES ,加速特定操作,如 shader  textures (module gl/)
  • 动画处理能力 (module animator/)
  • 内建 SVG 支援 (module (svg/)
  • 内建若干 image codec ,如 PNG, JPEG, GIF, BMP (modules images/)
  • 内建文字处理,但缺乏泰文、藏文一类复杂文字处理的能力
  • 效能特性:
    •  image 与特定资料型态的 Copy-on -write
    • 内部记忆体管理,谨慎地被免 fragmentation
    • Thread-safety

Skia 实做所需的相依性:

  • 字型 : FreeType ( 值得注意的是, FreeType 的维护者 David Turner 目前任职于 Google), Windows GDI
  • 多执行绪模型 : pthread, Windows threads
  • XML: expat, tinyxml

理解历史背景,我们终于可以来作点有趣的事。首先,自 Google Code 取得 Skia 原始程式码:

# svn co http://skia.googlecode.com/svn/trunk skia-trunk

乍看这「清爽」的目录架构,很难想像过去这是商业软体,或许 Google 有些「不能说的秘密」,除了 samplecode/ 目录若干的程式码之外,就几乎没有充分的文档了。用 svn log 可浏览 Skia 开发的纪录, "reed@android.com" 就是 Mike Reed 本人,至今仍相当活跃地改良 Skia 的实做。编译方式很单纯,先看看说明: ( 本文对应于 svn r130)

# cd skia-trunk

  # make help

可得到以下说明:

Targets:

    : out/libskia.a

     bench: out/bench/bench

     tests: out/tests/tests

     clean: removes entire out/ directory

     help: this text

  Options: (after make, or in bash shell)

     SKIA_DEBUG=true for debug build

     SKIA_SCALAR=fixed for fixed-point build

     SKIA_BUILD_FOR=mac for mac build (eg CG for image decoding)

期望的编译输出就是静态函式库 out/libskia.a ,而 Skia 的内部运算可选择浮点数与定点 (fixed-point) ,不过笔者发现,目前尙未能透地选择,但这不影响我们理解 Skia 的使用与体验其威力。以笔者使用的 GNU/Linux 来说,可下达以下指令要求编译:

# make SKIA_BUILD_FOR=linux

没意外的话,系统就会乖乖的编译:

compiling out/src/core/Sk64.o

  compiling out/src/core/SkAlphaRuns.o

  compiling out/src/core/SkBitmap.o

  ...

至于编译 benchmark 程式,则可透过以下指令:

# make SKIA_BUILD_FOR=linux bench

benchmark 程式算是除了 Chromium 之外,最佳的「文件」了,不过 SKia API 本来就简洁强大,这也不妨碍。执行 benchmark 程式:

./out/bench/bench -o `pwd`

陆续会有类似以下的输出:

running bench polygon

  running bench lines

  running bench points

  running bench rrects3

  running bench rrects1

  running bench ovals3

  running bench ovals1

  running bench rects3

  running bench rects1

  running bench bitmap_index8

  running bench bitmap_4444

  running bench bitmap_565

  running bench bitmap_8888

可大概窥知 Skia 涵盖的范畴,接着笔者就写个小程式,使用 Skia C++ API  [ test-skia.c ]

/* Simple vector graphics demo utilizing Skia toolkit.

  * Authored by Jim Huang <jserv.tw@gmail.com>

  */

 

#include "SkBitmap.h"

#include "SkDevice.h"

#include "SkPaint.h"

 

#include "SkRect.h"

#include "SkImageEncoder.h"

 

int main()

  {

        // Declare a raster bitmap, which has an integer width and height,

        // and a format (config), and a pointer to the actual pixels.

        // Bitmaps can be drawn into a SkCanvas, but they are also used to

 

        // specify the target of a SkCanvas' drawing operations.

        SkBitmap bitmap;

  bitmap.setConfig(SkBitmap::kARGB_8888_Config, 200, 200);

  bitmap.allocPixels();

 

        // A Canvas encapsulates all of the state about drawing into a

        // device (bitmap). This includes a reference to the device itself,

        // and a stack of matrix/clip values. For any given draw call (eg

        // drawRect), the geometry of the object being drawn is transformed

        // by the concatenation of all the matrices in the stack. The

        // transformed geometry is clipped by the intersection of all of the

 

        // clips in the stack.

        SkCanvas canvas( new SkDevice(bitmap));

 

        // SkPaint class holds the style and color information about how to

        // draw geometries, text and bitmaps.

        SkPaint paint;

 

        // SkIRect holds four 32 bit integer coordinates for a rectangle.

 

        SkRect r;

 

  paint.setARGB(255, 255, 0, 0);

  r.set(25, 25, 145, 145);

  canvas.drawRect(r, paint); /** Draw the specified rectangle using

  the specified paint. The rectangle

  will be filled or stroked based on

  the Style in the paint. */

 

        paint.setARGB(255, 0, 255, 0);

  r.offset(20, 20);

  canvas.drawRect(r, paint);

 

  paint.setARGB(255, 0, 0, 255);

  r.offset(20, 20);

  canvas.drawRect(r, paint);

 

        // SkImageEncoder is the base class for encoding compressed images

        // from a specific SkBitmap.

        SkImageEncoder::EncodeFile( "snapshot.png" , bitmap,

  SkImageEncoder::kPNG_Type,

               /* Quality ranges from 0..100 */ 100);

        return 0;

  }

编译方式:

g++ \

         -I./include \

         -I./include/core \

         -I./include/images \

         -Wall -o test-skia test-skia.c \

         out/src/images/SkImageDecoder_libpng.o out/libskia.a \

         -lpng -lpthread -g

笔者做了简要的注解,大概可知晓 Sk 开头的这些 API 的功用,而上述的范例程式一开始就要求 Skia 配置画布 (SkCanvas) ,接着透过一份 SkRect 物件 r ,给定 ARGB 的描述,使其有着不同的颜色,再来就是调整向量物件的位移并绘制。正如前文提及, Skia 仅是绘图引擎,并未如 Cairo 一般广泛对应到 PDF, X11, GDI 等等底层绘图装置,所以为了方便观察绘图结果,我们透过 Skia 内建的 image codec 来输出 PNG 图档,所以执行前述编译后的执行档 "test-skia" ,应该会得到以下图档: ( 本无外框与底色,但为了清楚于文章呈现,额外用绘图软体追加 )

 

 

叠合的三个不同色的矩形物件,就是透过以下 API 呼叫达成:

        paint.setARGB(255, 0, 255, 0);

  r.offset(20, 20);

  canvas.drawRect(r, paint);

由于 Skia  Cairo 的同质性相当高,也可参照 [ Cairo :: documentation ] 建立所需的背景知识。 
 jserv 发表于 March 21, 2009 07:42 PM

回响

不知道 skia  performance 能达到多少 , 还是和 Cairo 一样很慢

 lurker0 发表于 March 22, 2009 02:51 PM

Skia vs. Cairo 粗略地效能比较,可参考: 
http://d.hatena.ne.jp/gyuque/20090211

 jserv 发表于 March 23, 2009 01:26 AM

我以为 jserv 会把它拿来 cmake 化一下 XD

 Drake 发表于 March 23, 2009 01:59 PM

看不懂日文实在是太痛苦了 . 最要紧的部分刚好没有英文翻译 . 从仅有的信息来看 , 大的纹理拷贝是 Cairo  , 小的纹理拷贝是 SKia  . 不知道对不对 ?

 lurker0 发表于 March 31, 2009 10:35 PM

读了你的诸篇博文,受益匪浅。

能不能拨冗谈谈 Webkit 是怎么处理事件的?譬如,在一个 HTML 里有这么一段,


function whichButton(event)
{
if (event.button==2)
{
alert("You clicked the right mouse button!");
}
else
{
alert("You clicked the left mouse button!");
}
}

WebKit 是如何捕捉并处理 mousedown 这个事件的?具体而言,可能有三个问题。

1. WebKit 是从哪里得到 mousedown 这个事件的通知的?具体的源码是哪个 class 

2. WebKit 是如何确定与事件关联的是哪一个 DOM element 

这个问题,我的理解似乎与 RenderLayer::hitTest ,以及 RenderObject::hitTest 有关。不知道正确否?

2.1. 为什么要分 fro ntground  background 

2.2. HitTestRequest  HitTestResult 分别有什么用?似乎有用的部分通通在 Result ,那么 Request 是用来做什么的?

2.3. 如何从 RenderObject ,对应到 DOM element ?虽然 RenderObject  m_node ,但是没有见到怎么具体使用 m_node 的代码。


3. WebKit
 是如何解析 HTML 语句,如,尤其是,如何动态调用 whichButton ()这样的 JS 函数库?

多谢!

 【本文转自:http://blog.linux.org.tw/~jserv/archives/002095.html

 

posted on 2011-01-13 08:40  ZWXXForever  阅读(4420)  评论(0编辑  收藏  举报

导航