转载请注明原文地址:http://blog.csdn.net/milado_nju/article/details/7293012

# Canvas 2D及其在WebKit和Chromium中的实现

## 概述

Canvas是HTML5新引入的元素,它是一个画布。开发者可以用JavaScript脚本在该元素上绘制任意图形(2D或者3D)。Canvas元素有两个属性“width”和“height”,用来设置画布的宽度和高度。Canvas本身来讲并没有定义绘制图形的动作和行为,只是提供了一个获取绘图的上下文(context)对象的方法-getContext来获取绘制2D或者3D上下文。

Canvas的‘getContext’方法包含一个参数,该参数用来指定创建上下文对象的类型。对于2d的图形操作,通过传递参数值’2d’,浏览器会返回一个2d的绘图上下文,称为CanvasRenderingContext2D, 它提供了用于绘制2d图形的各种API, 包括基本图形绘制(例如线,矩形,圆弧),文字绘制,图形变换,图片绘制及合成等。我们把以上这些称之为Canvas2D。下图是一个使用Canvas2d的简单例子,后面的讨论都会基于它来进行。

Canvas 2D是HTML5草案的一部分,被众多的浏览器所支持, 包括chrome, IE, Firefox, Safari等等。 不仅如此,越来越多的浏览器开始支持在Canvas中绘制3D图形,该部分规范由Khronos组织定义。 也就是,通过传入适当的参数来调用Canvas的getContext函数以创建3D上下文对象用于绘制3D图形, 目前不同的浏览器支持不同的参数,例如chromium支持“webkit-3d”和”experimental-webgl”。

值得注意的是,2D和3D是互斥的,不能同时在同一个canvas中操作它们,也就是说,当创建了一个2D的上下文对象后,你不能再为其创建3D的上下文,反之亦然。本章将重点介绍Canvas 2D方面的只是及在WebKit和chromium中的实现, Canvas 3D也就是WebGL将在下一章中作介绍。

## CanvasRenderingContext2D 介绍

前面说到,CanvasRenderingContext2D是2d图形绘制的上下文对象,其提供了用于绘制2d图形的API,W3C工作组起草了标准的草案,详细见参考文献2。该对象由JavaScript代码创建后,JavaScript便可以调用它的API在画布上绘制图形了。这些API主要的作用就是在画布上绘制点,线,矩形,弧形,图片等等,除此之外,还提供了这些绘制的样式和合成效果等。下面按类简单介绍一下它所包含这些API。

第一部分,如下两个函数save和restore用来保存或者恢复2D上下文的状态;

第二部分,用来设置变换参数,例如缩放,旋转,平移等,这些构成了一个变换矩阵,缺省是Identity矩阵;

第三部分,对象的两个属性globalAlpha和globalCompositeOperation,用来设置alpha值和合成模式,alpha值表示将要绘制图形的透明度,合成模式表示将要绘制的图形和绘制对象如何合成,合成模式有多种,例如source-over, source-in, source-out, destination-over,destination-in, destination-in等等;

第四部分,有关设置颜色和样式,包括两个属性strokeStyle, fillStyle,gradient, pattern, 用来表示笔画和填充的格式,变化率,和用来填充图片的模式

第五部分,有关线的样式属性,它们包括线宽度,线端样式及其线与线的连接方式等;

第六部分,有关阴影方面的属性,这是全局的,影响所有绘制的图形;

第七部分,绘制矩形的相关操作,包括清除矩形区域,填充和绘制矩形边框;

第八部分,Path相关的操作,用来绘制自定义的路径的图形,这可以是图形可以是直线,弧形,曲线等;

第九部分,与文字相关的操作,包括字体,文字对齐方式等属性和绘制文字等操作;

第十部分,绘制图像到画布上,图像来源可以Image元素,Canvas元素,或者是Video元素。通过设置的样式,可以把待绘制的图像以不同的方式绘制到目标的Canvas上;

第十一部分,有关像素方面的操作,包括ImageData创建,以及从canvas读取内容创建ImageData和把ImageData内容写到canvas;

第十二部分,定义与上面一些API相关的类(接口),例如CanvasGradient,CanvasPattern等,这些类街头连同上面的API都被定义WebIDL格式。

通过以上解释,那么canvas2d例子中的代码就比较容易理解了。那段JS代码首先创建一个2D的上下文对象,然后设置填充的颜色为红色,最后填充一个80x100的矩形内部为红色。你可以尝试把例子放在chromium里面运行然后看看能得到什么。值得提醒的是,当画布的宽度或者高度发生改变时,该画布上的所有绘制的内容都将被移除。

## WebKit和Chromium的支持

W3C定义了2D context标准的草案, 这些接口保存在IDL文件中。 WebKit根据这IDL来直接生成相关的C++类的代码,这些类包括CanvasRenderingContext2D,CanvasPattern, CanvasGradient, ImageData, TextMetrics等, 它们和标准中的接口一一对应,你可以在WebKit/Source/WebCore/html/canvas中找到它们。那么它们被JS中的代如何码调用的呢?答案是生成JavaScript绑定。

Canvas2D上下文类的具体绘制动作由实现平台决定, 其由软件或者硬件来完成取决于移植。下面, 我们来看看WebKit如何支持Canvas2D以及如何提供合适的接口将实现交给移植来完成的。

首先,大致理解一下WebKit和chromium中支持Canvas2D的重要的类模块和它们之间关系,如下图所示。同以前一样, 包括WebKit的基础类和与平台相关的绘图类及支持canvas2D硬件加速的类。

让我们简单了解一下这些类的作用:

WebKit端:

HTMLCanvasElement:DOM中的对应着HTML5 的canvas元素,该类包含有关为2D或者3D context服务的相关接口,主要的作用创建JS使用的2D或者3D上下文对象,绘图的平台无关的GraphicsContext对象,后端存储的buffer

GraphicsContext:WebKit的平台无关的上下文类,用于绘制工作,具体调用平台相关的上下文类来实现绘制

PlatformGraphicsContext:平台绘制上下文类,不同的平台有不同的实现,在chromium中是PlatformContextSkia

ImageBuffer:WebKit平台无关后端存储类,不同平台会定义不同的结构,在chromium中会使用SkCanvas

RenderHTMLCanvas:RenderObject的子类,为canvas而设计的

Chromium端:

PlatformContextSkia: Chromium中的PlatformGraphicsContext类

SkCanvas:skia画布,包含所有的绘制状态,使用SkDevice来绘制图形

SkDevice:设备类,包含一个SkBitmap作为后端,利用光栅扫描算法来生成像素值保存于后端存储中,用于软件绘制方案

SkGpuDevice:设备类,包含一个绘制的目标对象,通过GrContext来绘制,其利用硬件加速的GL库来绘制2D图形

GrContext:  GPU绘制的上下文类,包含一个平台相关的3D上下文成员

Canvas2DLayerChromium:LayerChromium的子类,包含一个硬件加速的Canvas2D层

其他类:之前介绍过,不再赘述

上图中加速部分相关的GraphicsLayer, CCLayerImpl等,因为在之前介绍过,为方便起见,图中省略了它们。

Chromium中的Canvas2D的绘制操作的实现都是由图形库skia来完成,这里包括软件和硬件加速实现,chromium所要做的就是把WebKit中的调用交给skia来执行并和自己的绘制模型和硬件加速机制集成起来。

那么如何打开或者关闭Canvas2D的硬件加速功能呢? Chromium中提供了两个选项,分别是“--disable-accelerated-2d-canvas”和“--enable-accelerated-2d-canvas”,用户可以通过查看“about://gpu”来确认。

在介绍了基础设施之后,下面来看看具体的软件和硬件加速如何实现Canvas2D的。后面的软件实现和硬件加速实现都基于本章开始的canvas例子来说明。

## Canvas 2D的软件实现

这里我们以本章中的Canvas2D的例子来说这个过程。

首先,当执行到JS代码中的canvas.getContext时,WebKit通过V8 JS绑定会调用HTMLCanvasElement.getContext。该函数根据传入的参数来决定创建2D或者3D的上下文对象。 在这里, CanvasRenderingContext2D对象会被创建。此时其他有关的对象例如ImageBuffer,GraphicsContext等不会被创建,直到后面使用到时才会被创建,这是WebKit的做事原则。

其次,当设置fillStyle属性时,WebKit同样通过V8 JS绑定调用CanvasRenderingContext2D.setFillStyle,在这种情形下,2D上下文对象会开始创建相关对象(在软件实现情况下,上图中右侧框中的对象不会被创建,包括ImageBuffer, GraphicsContext, PlatformContextSkia, SkCanvas,SkDevice和 SkBitmap)。

当执行JS的fillRect时,CanvasRenderingContext2D调用GraphicsContext来完成绘制。 这两个类是WebKit的基础类,GraphicsContext需要有不同移植来具体实现绘制工作,在chromium中,这就是PlatformContextSkia。该类是一个转接口,调用skia来绘制。SkCanvas根据之前设定的样式,由SkDevice利用光栅扫描法来计算生成相应的像素值,结果保存在一个SkBitmap中。

最后,当fillRect操作调用完成之后,会安排一个Invalidate相关区域的命令。而后,当该命令被执行了,WebKit会遍历RenderLayer依次绘制RenderObject的内容,当绘制Canvas元素时,会把之前Canvas绘制在SkBitmap的内容绘制到网页的Bitmap上(该bitmap通过共享内存机制会被Browser进程绘制在Tab子窗口中)。下图显示的是当有更新请求时,WebKit遍历RenderLayer树和Render树来绘制网页及Canvas的详细调用过程。

## Canvas 2D的硬件加速实现

在硬件加速实现Canvas情况下,有一些地方是相似的,下面主要介绍它们的不同之处。

首先,硬件加速需要创建更多的对象和设施,主要有两点,一是如前面章节介绍的,会为Canvas元素创建一个新的RenderLayer及其相应的GraphicsLayer,Canvas2DLayerChromium,CCLayerImpl等。二是因为利用GL来渲染,所以为skia的SkCanvas创建一个SkGpuDevice, GrTexture, GrContext来使用GL绘制2D图形,同时,跟合成器一样,它也会创建3D的上下文对象- WebGraphicsContext3DCommandBufferImpl, 将skia的GrContext, GrTexture等对gl调用转发给GPU进程,具体的创建过程可参考ImageBufferSkia.cpp文件中的createAcceleratedCanvas函数。

其次,当调用fillRect时,canvas的内容由SkCanvas调用SkGpuDevice将其绘制在Texture,当然这些GL的操作都通过WebGraphicsContext3DCommandBufferImpl交给GPU进程来完成绘制。最后,会请求一个更新某个区域的任务。

最后,更新请求会调度合成操作,其首先调用Canvas2DLayerImpl::paintContentsIfDirty绘制自己,然后将Canvas的Texture合成起来生成网页内容。

## 源文件目录

WebKit/Source/WebCore/html/canvas/

WebKit支持Canvas相关的类,包括支持2D和3D上下文及其所涉及的其他类

WebKit/Source/WebCore/platform/graphics/skia/

实现WebKit中的平台相关的2D图形功能,Canvas2D在chromium中的实现依赖skia图形库

## 参考文献

1.      HTML5 canvas element http://www.w3schools.com/html5/html5_canvas.asp

2.      Canvas2D context http://www.w3.org/TR/2dcontext/

3.      WebKit HTMLCanvasElement

http://developer.apple.com/library/safari/#documentation/WebKit/Reference/HTMLCanvasElementRef/HTMLCanvasElementClassReference.html#//apple_ref/doc/uid/TP40009476

 By  yongsheng@chromium.org

转载于:https://www.cnblogs.com/xiaowangba/archive/2012/02/25/6313873.html

理解WebKit和Chromium: Canvas2D及其实现相关推荐

  1. 理解WebKit和Chromium: 前言

    注:朱永盛老师的<理解WebKit和Chromium>系列非常经典,在这里转发一下目录. 转载请注明原文地址:http://blog.csdn.net/milado_nju 这几年来,我阅 ...

  2. 理解WebKit和Chromium: Content API和CEF3

    转载请注明原文地址:http://blog.csdn.net/milado_nju/article/details/7455373 # Content API及CEF3 ## 概述 相信你一定看过下面 ...

  3. 理解WebKit和Chromium: WebKit的CSS实现

    转载请注明原文地址:http://blog.csdn.net/milado_nju/article/details/7685517 # CSS在WebKit和Chromium中的实现 ## 概述 前面 ...

  4. 理解WebKit和Chromium: WebKit, WebKit2, Chromium和Chrome介绍

    转载请注明原文地址:http://blog.csdn.net/milado_nju/article/details/7292164 ##概述 在介绍本系列各个专题之前,有必要先解释一下极其容易混淆的几 ...

  5. 理解WebKit和Chromium: WebKit渲染基础

    转载请注明原文地址:http://blog.csdn.net/milado_nju/article/details/7292131 # WebKit渲染基础 ## 概述 WebKit是一个渲染引擎,而 ...

  6. (转) 理解WebKit和Chromium

    WebKit是一个渲染引擎,而不是一个浏览器,它专注于网页内容展示,其中渲染是其中核心的部分之一.本章着重于对渲染部分的基础进行一定程度的了解和认识,主要理解基于DOM树来介绍Render树和Rend ...

  7. 理解WebKit和Chromium: Chromium for Android

    转载请注明出处:http://blog.csdn.net/milado_nju/ # Chromium的Android版 ## 概述 在前面的Chromium的移动版章节中,我们对Chromium的A ...

  8. 理解WebKit和Chromium: WebKit和Blink

    转载请注明出处:http://blog.csdn.net/milado_nju/ 关注Web和HTML5领域的人最近应该都有了解WebKit项目的重磅消息,那就是Google退出WebKit项目,创建 ...

  9. 理解WebKit和Chromium: WebKit和Chromium组成

    转载请注明原文地址:http://blog.csdn.net/milado_nju/article/details/7300074 在"WebKit,WebKit2,Chromium和Chr ...

最新文章

  1. 某华为程序员爆料:主动离职,公司竟也给n+1,到手15万,华为真良心!
  2. Google今天的logo
  3. 一般计算 【2007】三3 C++版
  4. 微型计算机应用重点,微型计算机原理以及的应用考试重点.doc
  5. python实现高校教务管理系统_python实现教务管理系统
  6. PetaPoco 快速上手
  7. 第13章:项目合同管理(1)-章节重点
  8. hbase实践之写流程拾遗
  9. 【转】OData的初步认识
  10. stl向量最大值_C ++ STL中向量的最小和最大元素
  11. 基于jQuery鼠标悬停上下滑动导航条
  12. ApiPost自动化测试基础之:接口参数依赖的情景处理...
  13. python学习笔记--python简介
  14. MQTT基础--MQTT 客户端和代理以及 MQTT 服务器和连接建立说明:第 3 部分
  15. 周期性的方波 matlab,matlab产生方波脉冲和周期性方波信号 - 副本
  16. Linux基本知识总结、常用命令教程、shell脚本开发、编辑器及调试器的使用教程
  17. win7没有显示wifi连接到服务器地址,Win7连接wifi出现感叹号
  18. 阿里云视频服务(视频边缘智能服务)接入流程
  19. larvel 路由未生效_laravel 路由修改不起作用解决方案
  20. SpringBoot整合Swagger2教程

热门文章

  1. 关于c语言的基本知识,第二章_关于C语言的基本知识.ppt
  2. 报错,> 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL
  3. B1.Java基础部分二
  4. 无心剑中译狄金森诗36首
  5. 查询:使用多表连接查询数据
  6. Java案例:静态内部类
  7. There is 和 There are的使用_28
  8. linux内核源码只有makefile文件没有c文件,linux内核代码的编写初步以及makefile的配置...
  9. java中String类是什么_Java中字符串的学习(一)String类的概述及常见方法使用
  10. 小学阅读方法六种_小学数学速算六种方法