zoukankan      html  css  js  c++  java
  • 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 (mogoweb@gmail.com)

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

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

  • 相关阅读:
    Delphi中WebBrowser自动填表模板
    对TMemoryStream的一些改进(用到了LockFile)
    用Delphi画圆角Panel的方法(使用CreateRoundRectRgn创造区域,SetWindowRgn显示指定区域)
    Delphi5的System.pas只有11514行
    《MFC游戏开发》笔记八 游戏特效的实现(二):粒子系统
    Delphi动态申请数组内存的方法(不使用SetLength,采用和C相似的方式)
    Delphi的类型转换 good
    New 和 GetMem 的不同之处
    XML SelectSingleNode的使用 根据节点属性获取该节点
    ADO面板上的控件简介
  • 原文地址:https://www.cnblogs.com/zoucaitou/p/4171462.html
Copyright © 2011-2022 走看看