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

 1 #ifndef WebCore_Horky_WebObject_h
 2
 3 #define WebCore_Horky_WebObject _h
 4
 5
 6
 7 #include <wtf/Forward.h>
 8
 9 #include <wtf/PassRefPtr.h>
10
11 #include <wtf/RefCounted.h>
12
13 #include <wtf/HashMap.h>
14
15 #include <wtf/RefPtr.h>
16
17
18
19 #include "PlatformString.h"
20
21
22
23 namespace WebCore {
24
25
26
27     class HorkyWebObject :publicRefCounted<HorkyWebObject> {
28
29     public:
30
31         staticPassRefPtr<HorkyWebObject> create()
32
33         {
34
35             returnadoptRef(newHorkyWebObject());
36
37         }
38
39
40
41         String description()const;
42
43     private:
44
45         HorkyWebObject();
46
47     };
48
49
50
51 } // namespace WebCore
52
53
54
55 #endif

HorkyWebObject.cpp

 1 #include "config.h"
 2
 3 #include "HorkyWebObject.h"
 4
 5
 6
 7 namespace WebCore {
 8
 9     HorkyWebObject::HorkyWebObject()
10
11     {
12
13     }
14
15
16
17     StringHorkyWebObject::description()const
18
19     {
20
21         return"Hello World!";
22
23     }
24
25
26
27 } // namespace WebCore
28
29
30
31     HorkyWebObject.idl
32
33    module window {
34
35
36
37     interface [
38
39         OmitConstructor  <---不提供getConstructor接口
40
41     ] HorkyWebObject {
42
43         readonly attribute DOMString description;
44
45     };
46
47 }

IDL定义中的module将此对象归属于window模块之下。在JavaScript下可以使用window.xxxx来使用新的对象, 也可以直接引用新对象。

Interface后所带的属性并不是在Web IDL定义的,而由WebKit自行定义,相关的属性列在WebCore/bindings/scripts/IDLAttributes.txt中,相应的对生成头文件及代码的影响需要对照CodeGeneratorJS.pm来理解。参考WebkitIDL说明:LINK .

b. 修改DOMWindow.h,添加如下代码:

 1   class HorkyWebObject;
 2
 3         ……
 4
 5         public:
 6
 7             HorkyWebObject* horkyWebObject()const;
 8
 9          private:
10
11             mutableRefPtr<HorkyWebObject> m_horkyWebObject;

c. 修改DOMWindow.cpp,添加如下代码

i. 在头文件添加:

#include "HorkyWebObject.h"

ii. 在Clear函数中,添加m_horkyWebObject =0;

iii. 添加函数:

 1 HorkyWebObject*DOMWindow::HorkyWebObject()const
 2
 3 {
 4
 5     if (!m_horkyWebObject)
 6
 7        m_horkyWebObject =HorkyWebObject::create();
 8
 9     returnm_horkyWebObject.get();
10
11 }

d. 修改DOMWindow.idl,添加如下一行 :

1 attribute [Replaceable] HorkyWebObject horkyWebObject;

e. 修改DerivedSources.make, 参考Navigator.idl添加如下代码:

1 $(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可以进行测试:

1 <script type=”text/javascript”>
2
3     document.write(horkyWebObject.description);
4
5     document.write("<br />");
6
7     document.write(window. horkyWebObject.description);
8
9   </script>

2. 根对象,单例

使用最直接的方式,在JSDOMWindowBase有finishCreation原本有一个动作将window和空的document对象加入到JSC堆中,在这里加入新的对象。

前三个步骤和第一个实作相似, 只是将类名称改为HorkyGlobalWebObject。新的流程设计如下:

a. 添加新的代码

因为是DOM有一个新全局对象,将新增的文件放到WebCore/dom下。代码和HorkyWebObject相同。

HorkyGlobalWebObject.h:

 1 #ifndef WebCore_Horky_GlobalWebObject_h
 2
 3 #define WebCore_Horky_GlobalWebObject_h
 4
 5
 6
 7 #include <wtf/Forward.h>
 8
 9 #include <wtf/PassRefPtr.h>
10
11 #include <wtf/RefCounted.h>
12
13 #include <wtf/HashMap.h>
14
15 #include <wtf/RefPtr.h>
16
17
18
19 #include "PlatformString.h"
20
21
22
23 namespace WebCore {
24
25
26
27     class HorkyGlobalWebObject :publicRefCounted<HorkyGlobalWebObject> {
28
29     public:
30
31         staticPassRefPtr<HorkyGlobalWebObject> create()
32
33         {
34
35             returnadoptRef(newHorkyGlobalWebObject());
36
37         }
38
39
40
41         String description()const;
42
43     private:
44
45         HorkyGlobalWebObject();
46
47     };
48
49
50
51 } // namespace WebCore
52
53 #endif
54
55
56
57      HorkyGlobalWebObject.cpp:
58
59 #include "config.h"
60
61 #include "HorkyGlobalWebObject.h"
62
63
64
65 namespace WebCore {
66
67
68
69     HorkyGlobalWebObject::HorkyGlobalWebObject()
70
71     {
72
73     }
74
75
76
77     StringHorkyGlobalWebObject::description()const
78
79     {
80
81         return"Hello World from Global Object!";
82
83     }
84
85
86
87 } // namespace WebCore

HorkyGlobalWebObject.idl:

 1 module core {
 2
 3     interface [
 4
 5         OmitConstructor
 6
 7     ] HorkyGlobalWebObject {
 8
 9         readonly attribute DOMString description;
10
11     };
12
13 }

b. 修改DOMWindow.h,添加如下代码:

 1 class HorkyGlobalWebObject;
 2
 3         ……
 4
 5         public:
 6
 7             HorkyGlobalWebObject* horkyGlobalWebObject()const;
 8
 9          private:
10
11            mutableRefPtr<HorkyGlobalWebObject> m_horkyGlobalWebObject;

c. 修改DOMWindow.h,添加如下代码:

i. 在头文件添加:

1  #include "HorkyGlobalWebObject.h"

ii. 在Clear函数中,添加m_horkyGlobalWebObject =0;

iii. 添加函数:

 1 HorkyGlobalWebObject*DOMWindow::horkyGlobalWebObject()const
 2
 3 {
 4
 5     if (!m_horkyGlobalWebObject)
 6
 7         m_horkyGlobalWebObject =HorkyGlobalWebObject::create();
 8
 9     returnm_horkyGlobalWebObject.get();
10
11 }

d. 修改JSDOMWindowBase.h,在updateDocument下添加一行 :

  void updateHorkyGlobalWebObject();

e. 修改JSDOMWindowBase.cpp.

i. 在文件头添加

    #include "JSHorkyGlobalWebObject.h"

ii. 添加函数:

 1 voidJSDOMWindowBase::updateHorkyGlobalWebObject()
 2
 3 {
 4
 5     ASSERT(m_impl->horkyGlobalWebObject());
 6
 7     ExecState* exec = globalExec();
 8
 9     symbolTablePutWithAttributes(exec->globalData(), Identifier(exec,"horkyglobalwebobject"),
10
11                                  toJS(exec, this, m_impl->horkyGlobalWebObject()), DontDelete | ReadOnly);
12
13 }

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):

 1 voidScriptController::updateHorkyGlobalWebObject()//20120605
 2
 3 {
 4
 5     JSLock lock(SilenceAssertionsOnly);
 6
 7     for (ShellMap::iterator iter = m_windowShells.begin(); iter != m_windowShells.end(); ++iter)
 8
 9         iter->second->window()->updateHorkyGlobalWebObject();
10
11 }

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可以进行测试:

1 <script type=”text/javascript”>
2
3     document.write(horkyWebObject.description);
4
5     document.write("<br />");
6
7     document.write( horkyglobalwebobject.description);
8
9 </script>

3. 多实例对象

这一类的对象,可以参考DOMWindows中的Image成员以及Float32Array的实现。

相对单例的对象,主要是提供了一个建构类。在IDL的声明时,将OmitConstructor去掉,替换为CustomConstructor, ConstructorParameters=1, Webkit就会自动生成一个Constructor类。然后再补齐constructXXXXX即可。 参考WebKitIDL中的说明:LINK.

以下为新增对象的类图:

经过两个实作,部分步骤不再细述。 为了区分,需然代码相同,类的名称改为HorkyNewObject。

a. 添加新的代码。

HorkyNewObject.cpp/.h参上面的实作。

HorkyNewObject.idl:

 1  module window {
 2
 3     interface [
 4
 5       CustomConstructor,
 6
 7       ConstructorParameters=1
 8
 9     ] HorkyNewObject {
10
11         readonly attribute DOMString description;
12
13     };
14
15 }

b. 新增JSHorkyNewObjectCustom.cpp

 1 #include "config.h"
 2
 3 #include "JSHorkyNewObject.h"
 4
 5 #include "HorkyNewObject.h"
 6
 7 #include <runtime/Error.h>
 8
 9
10
11 usingnamespaceJSC;
12
13
14
15 namespace WebCore {
16
17
18
19     EncodedJSValueJSC_HOST_CALLJSHorkyNewObjectConstructor::constructJSHorkyNewObject(ExecState* exec)
20
21     {
22
23         JSHorkyNewObjectConstructor* jsConstructor = jsCast<JSHorkyNewObjectConstructor*>(exec->callee());
24
25
26
27         RefPtr<HorkyNewObject> horkyNewObject =HorkyNewObject::create();
28
29         if (!horkyNewObject.get())
30
31             return throwVMError(exec, createReferenceError(exec,"Cannot create the new instance of HorkyNewObject!"));
32
33
34
35         return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(),horkyNewObject.get())));
36
37     }
38
39
40
41 } // 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 ([email protected])

2. 使用如下脚本可以直接基于idl文件生成代码:

./generate-bindings.pl ./test/Document.idl --generator=JS --outputDir=./test/Test

时间: 2024-10-12 06:06:36

WebKit JavaScript Binding添加新DOM对象的三种方式的相关文章

Java反射机制(创建Class对象的三种方式)

1:SUN提供的反射机制的类: java.lang.Class<T> java.lang.reflect.Constructor<T> java.lang.reflect.Field java.lang.reflect.Method java.lang.reflect.Modifier 2:什么是反射 JAVA反射机制是在运行状态中,对于任意一个类.都能都知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称

JDBC 创建连接对象的三种方式

创建连接对象的三种方式 //第一种方式 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb?user=root&password=root") ; //第二种方式 //读取properties文件 Properties pro = new Properties() ; InputStream in = JdbcDemo3.class.getClassLoader().ge

反射概念:获取class文件对象的三种方式

反射 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 要想解剖一个类,必须先要获取到该类的字节码文件对象.而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象. 利用class文件对象,去使用该文件中的成员变量,构造方法,成员方法. 例子1:获取class文件对象的三种方式 public cla

Java反射获取class对象的三种方式,反射创建对象的两种方式

Java反射获取class对象的三种方式,反射创建对象的两种方式 1.获取Class对象 在 Java API 中,提供了获取 Class 类对象的三种方法: 第一种,使用 Class.forName 静态方法. 前提:已明确类的全路径名. 第二种,使用 .class 方法. 说明:仅适合在编译前就已经明确要操作的 Class 第三种,使用类对象的 getClass() 方法. 适合有对象示例的情况下 package com.reflection; /** * Created by Liuxd

spring中创建bean对象的三种方式以及作用范围

时间:2020/02/02 一.在spring的xml配置文件中创建bean对象的三种方式: 1.使用默认构造函数创建.在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数函数,则对象无法创建. <bean id="one" class="sdnu.machi.one"></bean> 如果one.class中没有默认构造函数则会报

java webservice服务器端获取request对象的三种方式

有的时候在webservice里我们需要获取request对象和response对象,比如想要获得客户端的访问ip的时候就需要这么做,下面说三种方式,当然三种方式可能是针对不同方式部署webservice获取request对象的方法. 第一种:先配置注入: @Resource private WebServiceContext webServiceContext; 其次是下面的代码: MessageContext mc = webServiceContext.getMessageContext(

extjs组件添加事件监听的三种方式 http://blog.sina.com.cn/s/blog_48d7f92901011cfn.html

extjs对组件添加监听的三种方式 在定义组件的配置时设置 如代码中所示: Java代码 xtype : 'textarea', name : 'dataSetField', labelSeparator:'', fieldLabel:'', hideLabel: true, allowBlank: true, height: mainPanelHeight*0.8, anchor:'99%', listeners:{'blur':function(){ alert(1); }} 对组件变量通过

JavaScript 算法应用: 遍历DOM树的两种方式

1 常见的DOM树结构: 2  DOM数遍历有两种方式: 3 广度优先代码: 4 深度优先遍历代码 原文地址:https://www.cnblogs.com/autoXingJY/p/9193600.html

获取Class对象的三种方式

1:通过每个对象都具备的方法getClass来获取.弊端:必须要创建该类对象,才可以调用getClass方法. 2:每一个数据类型(基本数据类型和引用数据类型)都有一个静态的属性class.弊端:必须要先明确该类. 前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成. 3:使用的Class类中的方法,静态的forName方法. 指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可. // 1. 根据给定的类名来获得  用于类加载 String c