WebKit JavaScript Binding添加新DOM对象的三种方式
一.基础知识
首先WebKit IDL并非完全遵循Web IDL,只是借鉴使用。WebKit官网提供了一份说明(WebKitIDL),比如Web IDL称"operation”(操作), 而WebKitIDL称为"method"(方法), 另外Web IDL也不像WebKitIDL那样将属性和参数分开。
为JavaScript绑定对象,可以使用module来定义所从属的模组。
典型的module包括: core, window, event, traversal, ranges, html, storage. 其中一部分是HTML5定义的。虽然定义的模组不同,并不影响该对象在DOM Tree位置。关于DOM的规格定义,参考以下文档:
DOM 1 Core and HTML: LINK
DOM2 HTML: LINK
DOM2 Core: LINK
DOM2 Traversal and Range: LINK
DOM对象有三种型态:
a. 寄生于现有对象,单实例。
从属于某个全局对象,访问时透过宿主对象完成。如document.object或window.object, 也可以直接调用object.method.这个实现最为简单,按需分配,并且随着宿主对象释放就可以了。主要参考window的Navigator实现。
b. 和window、document一样成为全局对象,单实例。
这个实现最为复杂,且还没有看到相关文档说明。关键要将对象在合适的位置创建,并更新到JSC的堆中才能达到功能。可以参考document的实现,并且需要考虑执行流程,必须对代码做过一些了解,才可能知道相关的改动量。
c. 多实例对象。可以在脚本中使用new创建。
myObj = new Object();
较第一类需要指定自定义建构函数,主要参考DOM中的Image和Float32Array实现。
提示:1.如果尝试这样使用单例对象,会出现类似下面的错误。不是一个建构对象:
2.将新对象作为一个新属性寄生到window中提供扩展服务,更符合DOM的框架,它代表的是和浏览器相关的属性。如果需要扩展页面功能,为document增加属性或方法即可。
三种型态下的类的基本代码相同,最大的差异在于是如何引用及实例的管理。难点是在合适的位置绑定给JavaScript Core使用。
二.实作
下面从最简单的开始,进行三种型态的实作。
1. 寄生于现有对象,单例
这一段的实现,可以参考DOMWindow中的Navigator。(参考:LINK)
a. 添加新的代码
为了和DOMWindow就近,将新增的文件放到WebCore/page下。
HorkyWebObject.h
- #ifndef WebCore_Horky_WebObject_h
- #define WebCore_Horky_WebObject _h
- #include <wtf/Forward.h>
- #include <wtf/PassRefPtr.h>
- #include <wtf/RefCounted.h>
- #include <wtf/HashMap.h>
- #include <wtf/RefPtr.h>
- #include "PlatformString.h"
- namespace WebCore {
- class HorkyWebObject :publicRefCounted<HorkyWebObject> {
- public:
- staticPassRefPtr<HorkyWebObject> create()
- {
- returnadoptRef(newHorkyWebObject());
- }
- String description()const;
- private:
- HorkyWebObject();
- };
- } // namespace WebCore
- #endif
HorkyWebObject.cpp
- #include "config.h"
- #include "HorkyWebObject.h"
- namespace WebCore {
- HorkyWebObject::HorkyWebObject()
- {
- }
- StringHorkyWebObject::description()const
- {
- return"Hello World!";
- }
- } // namespace WebCore
- HorkyWebObject.idl
- module window {
- interface [
- OmitConstructor <---不提供getConstructor接口
- ] HorkyWebObject {
- readonly attribute DOMString description;
- };
- }
IDL定义中的module将此对象归属于window模块之下。在JavaScript下可以使用window.xxxx来使用新的对象, 也可以直接引用新对象。
Interface后所带的属性并不是在Web IDL定义的,而由WebKit自行定义,相关的属性列在WebCore/bindings/scripts/IDLAttributes.txt中,相应的对生成头文件及代码的影响需要对照CodeGeneratorJS.pm来理解。参考WebkitIDL说明:LINK .
b. 修改DOMWindow.h,添加如下代码:
- class HorkyWebObject;
- ……
- public:
- HorkyWebObject* horkyWebObject()const;
- private:
- mutableRefPtr<HorkyWebObject> m_horkyWebObject;
c. 修改DOMWindow.cpp,添加如下代码
i. 在头文件添加:
#include "HorkyWebObject.h"
ii. 在Clear函数中,添加m_horkyWebObject =0;
iii. 添加函数:
- HorkyWebObject*DOMWindow::HorkyWebObject()const
- {
- if (!m_horkyWebObject)
- m_horkyWebObject =HorkyWebObject::create();
- returnm_horkyWebObject.get();
- }
d. 修改DOMWindow.idl,添加如下一行 :
attribute [Replaceable] HorkyWebObject horkyWebObject;
e. 修改DerivedSources.make, 参考Navigator.idl添加如下代码:
$(WebCore)/page/HorkyWebObject.idl \
f.修改CMakeLists.txt和WebCore.gypi,参考Navigator.idl, Navigator.h, Navigator.cpp以及JSNavigator.cpp添加相应的文件。
g. 对于XCode Project, 先将HorkyWebObject.cpp添加到项目中。待编译一次后,将生成的JSHorkyWebObject.cpp拖到项目中。
最后使用下面的JavaScript可以进行测试:
- <script type=”text/javascript”>
- document.write(horkyWebObject.description);
- document.write("<br />");
- document.write(window. horkyWebObject.description);
- </script>
2. 根对象,单例
使用最直接的方式,在JSDOMWindowBase有finishCreation原本有一个动作将window和空的document对象加入到JSC堆中,在这里加入新的对象。
前三个步骤和第一个实作相似, 只是将类名称改为HorkyGlobalWebObject。新的流程设计如下:
a. 添加新的代码
因为是DOM有一个新全局对象,将新增的文件放到WebCore/dom下。代码和HorkyWebObject相同。
HorkyGlobalWebObject.h:
- #ifndef WebCore_Horky_GlobalWebObject_h
- #define WebCore_Horky_GlobalWebObject_h
- #include <wtf/Forward.h>
- #include <wtf/PassRefPtr.h>
- #include <wtf/RefCounted.h>
- #include <wtf/HashMap.h>
- #include <wtf/RefPtr.h>
- #include "PlatformString.h"
- namespace WebCore {
- class HorkyGlobalWebObject :publicRefCounted<HorkyGlobalWebObject> {
- public:
- staticPassRefPtr<HorkyGlobalWebObject> create()
- {
- returnadoptRef(newHorkyGlobalWebObject());
- }
- String description()const;
- private:
- HorkyGlobalWebObject();
- };
- } // namespace WebCore
- #endif
- HorkyGlobalWebObject.cpp:
- #include "config.h"
- #include "HorkyGlobalWebObject.h"
- namespace WebCore {
- HorkyGlobalWebObject::HorkyGlobalWebObject()
- {
- }
- StringHorkyGlobalWebObject::description()const
- {
- return"Hello World from Global Object!";
- }
- } // namespace WebCore
HorkyGlobalWebObject.idl:
- module core {
- interface [
- OmitConstructor
- ] HorkyGlobalWebObject {
- readonly attribute DOMString description;
- };
- }
b. 修改DOMWindow.h,添加如下代码:
- class HorkyGlobalWebObject;
- ……
- public:
- HorkyGlobalWebObject* horkyGlobalWebObject()const;
- private:
- mutableRefPtr<HorkyGlobalWebObject> m_horkyGlobalWebObject;
c. 修改DOMWindow.h,添加如下代码:
i. 在头文件添加:
- #include "HorkyGlobalWebObject.h"
ii. 在Clear函数中,添加m_horkyGlobalWebObject =0;
iii. 添加函数:
- HorkyGlobalWebObject*DOMWindow::horkyGlobalWebObject()const
- {
- if (!m_horkyGlobalWebObject)
- m_horkyGlobalWebObject =HorkyGlobalWebObject::create();
- returnm_horkyGlobalWebObject.get();
- }
d. 修改JSDOMWindowBase.h,在updateDocument下添加一行 :
- void updateHorkyGlobalWebObject();
e. 修改JSDOMWindowBase.cpp.
i. 在文件头添加
- #include "JSHorkyGlobalWebObject.h"
ii. 添加函数:
- voidJSDOMWindowBase::updateHorkyGlobalWebObject()
- {
- ASSERT(m_impl->horkyGlobalWebObject());
- ExecState* exec = globalExec();
- symbolTablePutWithAttributes(exec->globalData(), Identifier(exec,"horkyglobalwebobject"),
- toJS(exec, this, m_impl->horkyGlobalWebObject()), DontDelete | ReadOnly);
- }
iii. 修改finishCreation函数在数组staticGlobals中增加一行:
- GlobalPropertyInfo(Identifier(globalExec(),"horkyglobalwebobject"), jsNull(), DontDelete | ReadOnly)
提示:别忘了在上一行尾加个逗点。
e. 修改ScriptController.h,在updateDocument下添加新的函数定义:
- void updateHorkyGlobalWebObject();
f. 修改ScriptController.cpp:
i. 在头文件添加
- #include "HorkyGlobalWebObject.h"
ii. 添加函数(参考updateDocument):
- voidScriptController::updateHorkyGlobalWebObject()//20120605
- {
- JSLock lock(SilenceAssertionsOnly);
- for (ShellMap::iterator iter = m_windowShells.begin(); iter != m_windowShells.end(); ++iter)
- iter->second->window()->updateHorkyGlobalWebObject();
- }
iii. 修改initScript函数在updateDocument下增加一行:
- windowShell->window()->updateHorkyGlobalWebObject();
g. 修改Frame.cpp在setDocument函数中呼叫m_script.updateDocument下面加入一行:
- m_script.updateHorkyGlobalWebObject();
提示:这一句可以保证文档刷新时,新增的全局对象仍然有效。
h. 修改DerivedSources.make, 参考HorkyWebObject.idl添加如下代码:
- $(WebCore)/page/HorkyGlobalWebObject.idl \
i.修改CMakeLists.txt和WebCore.gypi,参考HorkyWebObject.idl, HorkyWebObject.h, HorkyWebObject.cpp以及JSHorkyWebObject.cpp添加相应的文件。对于XCode Project, 先将HorkyGlobalWebObject.cpp添加到项目中。待编译一次后,将生成的JSHorkyGlobalWebObject.cpp拖到项目中。
最后使用下面的JavaScript可以进行测试:
- <script type=”text/javascript”>
- document.write(horkyWebObject.description);
- document.write("<br />");
- document.write( horkyglobalwebobject.description);
- </script>
3. 多实例对象
这一类的对象,可以参考DOMWindows中的Image成员以及Float32Array的实现。
相对单例的对象,主要是提供了一个建构类。在IDL的声明时,将OmitConstructor去掉,替换为CustomConstructor, ConstructorParameters=1, Webkit就会自动生成一个Constructor类。然后再补齐constructXXXXX即可。 参考WebKitIDL中的说明:LINK.
以下为新增对象的类图:
经过两个实作,部分步骤不再细述。 为了区分,需然代码相同,类的名称改为HorkyNewObject。
a. 添加新的代码。
HorkyNewObject.cpp/.h参上面的实作。
HorkyNewObject.idl:
- module window {
- interface [
- CustomConstructor,
- ConstructorParameters=
- ] HorkyNewObject {
- readonly attribute DOMString description;
- };
- }
b. 新增JSHorkyNewObjectCustom.cpp
- #include "config.h"
- #include "JSHorkyNewObject.h"
- #include "HorkyNewObject.h"
- #include <runtime/Error.h>
- usingnamespaceJSC;
- namespace WebCore {
- EncodedJSValueJSC_HOST_CALLJSHorkyNewObjectConstructor::constructJSHorkyNewObject(ExecState* exec)
- {
- JSHorkyNewObjectConstructor* jsConstructor = jsCast<JSHorkyNewObjectConstructor*>(exec->callee());
- RefPtr<HorkyNewObject> horkyNewObject =HorkyNewObject::create();
- if (!horkyNewObject.get())
- return throwVMError(exec, createReferenceError(exec,"Cannot create the new instance of HorkyNewObject!"));
- return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(),horkyNewObject.get())));
- }
- } // namespace WebCore
c. 修改DOMWindow.idl, 参考Image增加一行:
- attribute [JSCustomGetter, CustomConstructor] HorkyNewObjectConstructor horkyNewObject;
提示:这里在Constructor类名称前不要加JS. 不然就会遇到JSDOMWindow.cpp找到不对应头文件的编译错误。
d. 修改JSDOMWindowCustom.cpp.
i. 在头文件添加
- #include "JSHorkyNewObject.h"
ii. 添加函数:
- JSValueJSDOMWindow::horkyNewObject(ExecState* exec)const
- {
- return getDOMConstructor<JSHorkyNewObjectConstructor>(exec,this);
- }
提示:关于c/d两个步骤,如果不需要提供自定义的绑定函数(在这个实作是不需要的),可以不要attribut后面两个属性,也不需要步骤d.
其余的步骤,参考实作一即可。
测试脚本如下:
- <script type=”text/javascript”>
- document.write("<br />");
- var myObj = new horkyNewObject();
- document.write(myObj.description);
- </script>
参考:
1. WebKit的JavaScript对象扩展 http://mogoweb.net/archives/194 (mogoweb@gmail.com)
2. 使用如下脚本可以直接基于idl文件生成代码:
./generate-bindings.pl ./test/Document.idl --generator=JS --outputDir=./test/Test
WebKit JavaScript Binding添加新DOM对象的三种方式的更多相关文章
- Java反射机制(创建Class对象的三种方式)
1:SUN提供的反射机制的类: java.lang.Class<T> java.lang.reflect.Constructor<T> java.lang.reflect.Fi ...
- Java反射机制(创建Class对象的三种方式)
1:了解什么是反射机制? 在通常情况下,如果有一个类,可以通过类创建对象:但是反射就是要求通过一个对象找到一个类的名称: 2:在反射操作中,握住一个核心概念: 一切操作都将使用Object完成,类 ...
- JDBC 创建连接对象的三种方式 、 properties文件的建立、编辑和信息获取
创建连接对象的三种方式 //第一种方式 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/ ...
- 反射:获取Class对象的三种方式
获取Class对象的三种方式 package lianxiApril18; /** * 获取Class对象的三种方式 * 1 Object ——> getClass(); * 2 任何数据类型( ...
- Java反射获取类对象的三种方式
package demo01; /* * 获取一个类的class文件对象的三种方式 * 1.对象获取 * 2.类名获取 * 3.Class类的静态方法获取 */ public class Reflec ...
- Java反射获取class对象的三种方式,反射创建对象的两种方式
Java反射获取class对象的三种方式,反射创建对象的两种方式 1.获取Class对象 在 Java API 中,提供了获取 Class 类对象的三种方法: 第一种,使用 Class.forName ...
- 3、获取Class对象的三种方式
3.获取Class对象的三种方式 要想对字节码文件进行解刨,必须要有字节码文件对象 Object类中的getClass方法 通过对象静态属性 .class来获取对应的Class对象 只要通过给定类的字 ...
- Java反射学习-2 - 获取Class对象的三种方式
package cn.tx.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import ...
- spring中创建bean对象的三种方式以及作用范围
时间:2020/02/02 一.在spring的xml配置文件中创建bean对象的三种方式: 1.使用默认构造函数创建.在spring的配置文件中使用bean标签,配以id和class属性之后,且没有 ...
随机推荐
- 搭建docker私有仓库 笔记
抄送消息到企业微圈 avalon组件 twitterCopy/twitterCopy 说明 说明 说明 说明 说明 说明 该组件提供接口 开发者可以吧 有需要分享到微圈的的信息 发布到微圈中去. 应用 ...
- Qt 学习之路:文件
文件操作是应用程序必不可少的部分.Qt 作为一个通用开发库,提供了跨平台的文件操作能力.从本章开始,我们来了解下 Qt 的文件以及输入输出的功能,也就是 I/O 系统. Qt 通过QIODevice提 ...
- Form实现无刷新上传文件并返回自定义值
今天开发过程中遇到了这样一个问题:需要将Excel上传至服务器进行解析,但是在文档不合适的情况下希望可以不刷新页面提示用户文档不合适.冥思苦想了半天,在网上找了不少资料最终试验成功,在此分享下处理方法 ...
- 如何设计一个简单的C++ ORM
2016/11/15 "没有好的接口,用C++读写数据库和写图形界面一样痛苦" 阅读这篇文章前,你最好知道什么是 Object Relation Mapping (ORM) 阅读这 ...
- Linux Increase The Maximum Number Of Open Files / File Descriptors (FD)
How do I increase the maximum number of open files under CentOS Linux? How do I open more file descr ...
- js时间字符串转Date对象
var DATE_REGEXP = new RegExp("(\\d{4})-(\\d{2})-(\\d{2})([T\\s](\\d{2}):(\\d{2}):(\\d{2})(\\.(\ ...
- MEF依赖注入调试小技巧!
自从哥的项目使用MEF以来,天天那个纠结啊,甭提了.稍有错误,MEF就报错,但就不告诉你哪错了,大爷的. 后来看了MEFX的相关调试方法,感觉也不太理想,根本不够直观的看到错误原因,也许是没有深入学习 ...
- C++ hello world
日文版本的vs 2008 , 在 < 新建 里面先创建一个项目 然后点击项目去创建一个C++的主启动文件 选择创建的文件类型 然后在文件里面写入代码 #include<iostream&g ...
- Android layout的横竖屏处理
一.layout-land和layout-prot的区别与使用 默认情况下,创建的Android项目里只有一个layout文件夹,尽管这样也可以横竖屏切换用,但是某些布局横屏过后闲的格外的丑,如下图 ...
- git代码库的使用
代码库/使用指南 http://learn.zone.jd.com/cmsuser/index.htm 在win7系统下使用TortoiseGit(乌龟git)简单操作Git@OSC http://m ...