gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] gnash ChangeLog doc/C/extensions.xml


From: Rob Savoye
Subject: [Gnash-commit] gnash ChangeLog doc/C/extensions.xml
Date: Fri, 16 Feb 2007 04:16:49 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Rob Savoye <rsavoye>    07/02/16 04:16:49

Modified files:
        .              : ChangeLog 
Added files:
        doc/C          : extensions.xml 

Log message:
                * doc/C/extensions.xml: New file on the extension mechanism, and
                on writing extensions.
                * doc/C/gnash.xml: Add extensions chapter.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/doc/C/extensions.xml?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.2369&r2=1.2370

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.2369
retrieving revision 1.2370
diff -u -b -r1.2369 -r1.2370
--- ChangeLog   15 Feb 2007 21:16:29 -0000      1.2369
+++ ChangeLog   16 Feb 2007 04:16:49 -0000      1.2370
@@ -8,6 +8,10 @@
 
 2007-02-15  Rob Savoye  <address@hidden>
 
+       * doc/C/extensions.xml: New file on the extension mechanism, and
+       on writing extensions.
+       * doc/C/gnash.xml: Add extensions chapter.
+       
        * extensions/gtk2: New directory for Gtk2 API extension.
        * extensions/gtk2/hello.as: The well known Gtk "Hello" example
        program written in ActionScript.

Index: doc/C/extensions.xml
===================================================================
RCS file: doc/C/extensions.xml
diff -N doc/C/extensions.xml
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ doc/C/extensions.xml        16 Feb 2007 04:16:49 -0000      1.1
@@ -0,0 +1,293 @@
+<sect1 id="extensions">
+  <title>Gnash Extensions</title>
+
+  <para>
+    Gnash supports extending the Flash specification by creating
+    custom ActionScript classes that are compiled code, as opposed to
+    the existing method of defining custom classes as
+    ActionScript. Executing compiled code has many performance
+    benefits over having to interpret the byte stream of the
+    ActionScript opcodes.
+  </para>
+
+  <para>
+    I can already hear people complaining now about the concept of
+    extending Flash, so this in no way effects Gnash's ability to play
+    Flash movies when functioning as a browser plugin. The goals of
+    Gnash's goals are still to function in a way that is compatible
+    with the current proprietary Flash player.
+  </para>
+
+  <para>
+    But at the same time, we see Flash as the ideal scripting language
+    for a digital multi-media streaming environment. There are many
+    resources for Flash movie creators for widgets, higher level APIs,
+    all sorts of desirable things. But for those of use committed to
+    using free software tools for Flash, our options are very
+    limited. 
+  </para>
+
+  <para>
+    Rather than launching a multi-year project to duplicate all
+    classes in the commercial Flash IDE, it's much more efficient to
+    use existing development libraries much like Python or Perl
+    do. The extension mechanism in Gnash allows wrappers to be created
+    for any C or C++ development library. Unlike the proprietary Flash
+    IDE, which compiles all the extension libraries into byte codes
+    from ActionScript, the support is moved to the player side. Movies
+    with all of the goodies of the proprietary IDE in them play in
+    Gnash just fine, as it's all just byte codes by then.
+  </para>
+
+  <para>
+    This trick works because until Flash player version 9, all the
+    ActionScript class names and methods are passed as ASCII strings
+    into the Flash movie. So the Gnash Virtual Machine just loads the
+    extension file if that class name is invoked in the movie. All
+    extension files specify the class name and methods it implements
+    in an identical style as adding any new ActionScript class. The
+    advantage is the class itself is compiled code, and runs much
+    faster than the equivilant byte codes which all have to be
+    interpreted..
+  </para>
+
+  <para>
+  </para>
+
+  <sect2 id="newext">
+    <title>Creating A New Extension</title>
+
+    <para>
+      Each new extension should live in it's own directory. The
+      extensions included in Gnash are all in the
+      <code>gnash/extensions</code> directory. Creating an extension
+      requires a Makefile.am,
+    </para>
+
+    <para>
+      If you are adding this extension to the Gnash source tree
+      itself, then you need to make two changes to add the new
+      extension.
+    </para>
+
+    <para>
+      The first change is to add the directory to the list in
+      extensions/Makefile.am. This can be done either by adding the
+      new directory to the SUBDIRS setting, or by wrapping it in a
+      conditional test.
+    </para>
+
+    <para>
+      The other change is to add it to the AC_OUTPUT list in
+      <emphasis>configure.ac</emphasis> so the new directory will be
+      configured along with the rest of Gnash.
+    </para>
+
+    <para>
+      Each extension should have an ActionScript source file included
+      that tests the new class, and this file should be referenced in
+      the new Makefile.am in the <emphasis>check_PROGRAMS</emphasis>
+      variable so that "make check" works.
+    </para>
+
+    <para>
+      When creating an extension that is a wrapper for an existing
+      development library API, it's often better to make this a thin
+      layer, than to get carried away with creating beautiful
+      abstractions. Higher-level classes that offer a lot of new
+      functionality are fine, but is different than wrapping a library
+      so it can be used from withint Gnash.
+    </para>
+
+    <sect3 id="craftext">
+      <title>Crafting an Extension</title>
+
+      <para>
+       All extensions have the same requirements, namely setting up a
+       few defined function callbacks, which the Gnash VM then uses
+       to do the right thing. The initial two function callbacks are
+       for handling the interface of the newly created object so that
+       Gnash can find and use it.
+      </para>
+
+      <para>
+       The first function is commonly called
+       <emphasis>attachInterface</emphasis>, and this sets the other
+       function callbacks for all the methods this class
+       supports. The method callbacks are attached to the parent
+       class by using <emphasis>set_member()</emphasis> to set a C
+       function pointer to the string value used in the Flash movie.
+      </para>
+
+      <programlisting>
+       // setup so DummyClass.func1() and DummyClass.func2() work from Flash.
+       static void
+       attachInterface(as_object *obj)
+       {
+            obj->set_member("func1", &amp;ext_func1);
+            obj->set_member("func2", &amp;ext_func2);
+       }
+      </programlisting>
+
+      <para>
+       The second function is commonly called
+       <emphasis>getInterface()</emphasis>, and this returns a
+       smart pointer to the new object. Gnash uses smart pointers for
+       all ActionScript class definitions. (and many other things)
+      </para>
+      <programlisting>
+       static as_object*
+       getInterface()
+       {
+           static boost::intrusive_ptr&lt;as_object&gt; o;
+           if (o == NULL) {
+               o = new as_object();
+           }
+           return o.get();
+       }
+      </programlisting>
+
+      <para>
+       This is the callback that gets executed when constructing a
+       new object for the VM. In this example we'll assume the new
+       ActionScript class is called <emphasis>DummyExt</emphasis>,
+       and has two methods, <emphasis>func1</emphasis> and
+       <emphasis>func2</emphasis>.
+      </para>
+      <programlisting>
+       static void
+       dummyext_ctor(const fn_call&amp; fn)
+       {
+           DummyExt *obj = new DummyExt();
+
+           attachInterface(obj);
+           fn.result->set_as_object(obj); // will keep alive
+       }
+      </programlisting>
+
+      <para>
+       Allocate the new object and return a smart pointer.
+      </para>
+      <programlisting>
+       std::auto_ptr&lt;as_object&gt;
+       init_dummyext_instance()
+       {
+           return std::auto_ptr&lt;as_object&gt;(new DummyExt());
+       }
+      </programlisting>
+
+      <para>
+       Initialize the extension. This is looked for by the extension
+       handling code in each extension, and is executed when the
+       extension is loaded. This is the main entry point into the
+       extension. This function can be found because the prefix of
+       <emphasis>dummyext</emphasis>, which also matches the file
+       name of the extension. Gnash uses the name of the extension
+       file itself when looking for the init function.
+      </para>
+      <programlisting>
+        extern "C" {
+           void
+           dummyext_class_init(as_object &amp;obj)
+           {
+               static boost::intrusive_ptr&lt;builtin_function&gt; cl;
+               if (cl == NULL) {
+                   cl = new builtin_function(&amp;dummyext_ctor, 
getInterface());
+                   attachInterface(cl.get());
+               }
+       
+               VM&amp; vm = VM::get();
+               std::string name = "DummyExt";
+               if ( vm.getSWFVersion() &lt; 7 ) {
+                   boost::to_lower(name, vm.getLocale());
+               }
+               obj.init_member(name, cl.get());
+           }
+        } // end of extern C
+      </programlisting>
+
+      <para>
+       The callbacks are all C functions. Like all the other code
+       that implements ActionScript, parameters to the function are
+       passed in using the <emphasis>fn_call</emphasis> data
+       structure. The return code, if any, is also returned using
+       this data structure. <emphasis>this_ptr</emphasis> is the
+       object that the method is a member of.
+      </para>
+      <programlisting>
+       // Creates a new button with the label as the text.
+       void func1(const fn_call&amp; fn)
+       {
+           DummyExt *ptr = dynamic_cast&lt;DummyExt *&gt;(fn.this_ptr);
+           assert(ptr);
+       
+           if (fn.nargs > 0) {
+               const char *label = fn.arg(0).to_string();
+               bool ret = ptr->dummy_text_label(label);
+               fn.result->set_bool(ret);
+           }
+       }
+      </programlisting>
+
+    </sect3>
+
+  </sect2>
+
+  <sect2 id="debuext">
+    <title>Debugging An Extension</title>
+    
+    <para>
+      As extensions are loaded dynamically at runtime, debugging one
+      can be difficult. You can use GDB, but you have the problem of
+      not being able to set a breakpoint in Gnash until
+      <emphasis>after</emphasis> the extension has been loaded into
+      Gnash's VM. The easy solution is to use the Gnash debugger.
+    </para>
+
+    <para>
+      You can insert these few lines in any file that you wish to
+      manually start the debugger. Once at the console, you can attach
+      GDB to the process. Then you can set breakpoints, etc... and you
+      are at the point of execution where the console was started. To
+      then continue playing the movie, type the <emphasis>c</emphasis>
+      (for continue) command to the Gnash console.
+    </para>
+    <programlisting>
+      // Get the debugger instance
+      static Debugger&amp; debugger = Debugger::getDefaultInstance();
+
+      // Enable the debugger
+      debugger.enabled(true);
+      // Stop and drop into a console
+      debugger.console();
+    </programlisting>
+
+    <para>
+      You can also resort to the time honored technique of creating a
+      loop before the point you want to set a breakpoint for. Gnash
+      will stop playing the movie at this point, and then you can
+      externally attach GDB to the running process, or type
+      <emphasis>^C</emphasis> to drop into the GDB command console.
+    </para>
+    <programlisting>
+      bool stall = true;
+      while (stall) {
+          sleep 1;
+      }
+    </programlisting>
+
+    <para>
+      Once you have set the breakpoints you want, reset the value of
+      the <emphasis>stall</emphasis> variable to break out of the
+      loop, and the Flash movie will then continue playing.
+    </para>
+    <programlisting>
+      (gdb) set variable stall = false;
+      continue
+    </programlisting>
+
+  </sect2>
+
+</sect1>
+
+




reply via email to

[Prev in Thread] Current Thread [Next in Thread]