2008年11月30日 星期日 上午 01:20
阅读了之后,觉得作为浏览器内核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方法最常用,其分别对应如何显示文字及图像。

针对图形库显示文字的基本原理可以参考及。



至于图形库如何显示不同格式的图像可参考如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等,其中阐述了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实现

在中提供了WebKit 对3D Port的支持与实现,其实现类似于Gtk+/Cairo图形库的实现,但其3D效果仅实现在Port层,没有对页面上的元素如文字、图像实现3D效果支持。



这里只是简单的了解WebKit中如何整合不同的图形库及其与WebCore的交互。要想更加深入的了解页面上的文字、图形、图像究竟是如何显示出来的,则需要更进一步的针对不同平台库进行学习与了解。



WebKit 中也支持canvas标签,该标签提供的接口与Gecko能提供的几乎一致,其具体实现可参考webcore\html \CanvasRenderingContext2D.cpp,结合GraphicsContext类的实现,应该能对canvas标签的实现有充分的理 解。



四、总结

其实关于图形库及其使用的内容非常的多,而对浏览器内核来讲能对图形库进行高效使用也是非常重要的一部分,所以在这里所谈到的内容也许只是一些皮毛,但希望能在此开阔一下了解浏览器内核特别是图形库使用方面的思路。



五、参考资源



Wiki Cairo

Cairo HomePage

Wiki Qt

Wiki GTK+

Wiki wxWidgets

Wiki GDI

Wiki DirectX

Wiki Quartz 2D

Wiki OpenGL

Wiki OpenGL ES



Wiki gif

Wiki jpeg

Wiki png



Clutter Toolkit
http://blog.chinaunix.net/uid-25554408-id-234904.html

转载于:https://www.cnblogs.com/Jason-Ch/articles/2855993.html

WebKit、Gecko使用图形库相关推荐

  1. preloadlazy load

    最近需要用到预加载和延迟加载的东东,就参考写了一个. 支持跨页面,支持超时设置与依赖设置. (function($) { (function($) {$.preload = function(data ...

  2. BOM之navigator对象和用户代理检测

    前面的话 navigator对象现在已经成为识别客户端浏览器的事实标准,navigator对象是所有支持javascript的浏览器所共有的.本文将详细介绍navigator对象和用户代理检测 属性 ...

  3. CSS3那些不为人知的高级属性

    尽管现代浏览器已经支持了众多的CSS3属性,但是大部分设计师和开发人员貌似依然在关注于一些很"主流"的属性,如border-radius.box-shadow或者transform ...

  4. 对于一个html元素,有几种方法修改样式方法的优先级,HTMLCSS常见面试题及疑难解答...

    HTML&CSS常见面试题及疑难解答 HTML篇 对web标准以及W3C的理解与认识? WEB标准不是某一个标准,而是一系列标准的集合.网页主要由三部分组成:结构(Structure).表现( ...

  5. html 正方形缩略图,html – 纯CSS图像缩略图

    我想在网格中显示图像缩略图的集合.图像将会有各种尺寸,但我想将缩略图限制在特定的大小(我们说宽200像素,高150像素). 我想要找到的是一些神奇的HTML标记和CSS规则 >允许图像包含在正常 ...

  6. 开发一款浏览器内核需要学习哪些方面的知识?

    开发一款浏览器内核需要学习哪些方面的知识? 最近参加毕业设计,题目选的是<基于Linux平台的网页浏览器设计与实现>. 想认真做一下,所以不准备直接用现成的开源浏览器内核(比如WebKit ...

  7. Web 浏览器相关的一些概念

    这篇文章没有多少深刻内容,它主要涉及两个问题: WebKit, Safari, Blink, Chromium, Chrome 之间是什么关系? WebKit, Chromium, Android W ...

  8. 使用XUL开发跨平台桌面应用

    先上图: 现在使用html,css,js开发桌面的优势越来越明显了,硬件性能的不断提升,人力成本越发昂贵,用户对界面要求越来越高,全球化下企业间的竞争越发激烈.桌面软件50%+的工作量都在界面开发这一 ...

  9. 通过JS解析手机浏览器UA标志中的各种设备信息

    通过获取手机浏览器的UA标志后,对UA字符串进行解析,得出手机的各种基本信息. /** @name Operating System* @desc Currently is only to userA ...

最新文章

  1. CUDA动态库封装以及调用
  2. Delphi 7下使用VT实现树型列表结合控件
  3. 掌握这 20 个容器实战技巧!
  4. P3146 [USACO16OPEN]248 G(python3实现)
  5. Android WebService
  6. 将字符转换成带有圆圈的字符
  7. 计算机程序编辑的英语,编译程序是为把高级语言书写的计算机程序翻译成面向计算机的目标程序而使用的计算机程序...
  8. HTML,CSS基础十大重点问题
  9. 【【★★★★★★CSS兼容IE6,IE7,FF的技巧 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★】】...
  10. C++ queue(STL queue)
  11. 关于安装NTKO Office插件的方法
  12. android使用SwipeRefreshLayout下拉刷新
  13. Android流式布局FlowLayout,一款针对Tag的布局
  14. 二叉平衡树的基本操作(完整代码)
  15. 数据库-mysql的配置
  16. VUE 尚硅谷 学习内容详解
  17. 自动驾驶算法详解(8):特斯拉Tesla决策规划算法Planning解析下
  18. 物流笔记 | 物流专业相关会议介绍
  19. 极致敏捷-使用C语言在Taskbus中一天实现ADS-B接收机和实时飞行地图
  20. python开发大型游戏_Python也有做大型游戏的潜力?原来我们小看了Python,无所不能...

热门文章

  1. 分布式账本(Distributed ledger)
  2. Python文件的使用
  3. python 数据类笔试题_一道 Python 类的笔试题详解
  4. 参加web前端培训要学哪些知识
  5. Java多线程001——一图读懂线程与进程
  6. 『流畅的Python』第14章:可迭代的对象、迭代器和生成器
  7. 【贪心】Google Code Jam Round 1A 2018 Waffle Choppers
  8. 前端工程师成长之多读好书
  9. 想知道垃圾回收暂停的过程中发生了什么吗?查查垃圾回收日志就知道了!
  10. 倍福TwinCAT(贝福Beckhoff)基础教程5.1 TwinCAT-2 运行可执行文件