Gnash Manual V0.3.9

Rob Savoye


    
  

This manual describes version 0.7.2 of Gnash.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. You can find a copy of the GFDL at this link or in the file COPYING-DOCS distributed with this manual.

Revision History
Revision Gnash Manual V0.3.9Feb 2007

Rob Savoye Updated for the alpha release.

Free Software Foundation


Table of Contents

Introduction
Gnash Overview
Gnash Usage
Gnash Command Line Options
Gnash Interactive Control Keys
User Configuration File
Flash Debugger
Building From Source
Overview
Code Dependencies
Documentation Dependencies
Configuring The Code
Building Gnash
Installation
Software Internals
A Tour of Gnash
ActionScript Support
Flash Opcodes
The Interpreter Engine
Sound handling in Gnash
Testing
Gnash Extensions
Creating A New Extension
Debugging An Extension
Included Extensions
Appendix
Code Style
RTMP Protocol
Authors
A. GNU Free Documentation License
0. PREAMBLE
1. APPLICABILITY AND DEFINITIONS
2. VERBATIM COPYING
3. COPYING IN QUANTITY
4. MODIFICATIONS
5. COMBINING DOCUMENTS
6. COLLECTIONS OF DOCUMENTS
7. AGGREGATION WITH INDEPENDENT WORKS
8. TRANSLATION
9. TERMINATION
10. FUTURE REVISIONS OF THIS LICENSE
Addendum

Introduction

Gnash is a free Flash movie player, which can be used standalone or as a Firebox/Mozilla plugin.

Gnash Overview

Gnash is originally based on the code of GameSWF, by Thatcher Ulrich. GameSWF was the most advanced of the free flash movie player projects, and implemented a fairly broad set of Flash Format v7 compliance. GameSWF was unsupported public domain software however, and not really designed as an industrial strength project which could be used by everyone who uses Firefox. So in early December of 2005, GameSWF was forked. After being rearranged in GNU project style, development of the plugin was started.

Gnash works as standalone player; as a Mozilla Firefox plugin; and as a Konqueror plugin, called Klash. The plugins use the standalone player for processing, but embed the output into the browser.

Currently, Gnash uses OpenGL to get a high quality rendered image. There are plans to write a Cairo back-end to give Gnash a performance boost on graphics processors without 3D hardware acceleration. Other plans involve running Gnash in a framebuffer, with no windowing system at all.

Included in the Gnash is an XML-based messaging system, as specified in the Flash specification. This lets a flash movie communicate over a TCP/IP socket, and parse the incoming XML message. This allows a movie be a remote control for other devices or applications.

Plugin Overview

The plugin currently works by creating a new window in the standalone player which is connected to the browser window in Firefox.

All movies are downloaded to /tmp and played from there. Many web pages use IE-specific JavaScript to initiate movies, which means that Firefox does not load the Gnash plugin.

Standalone Player Overview

The standalone player supports both SDL and GTK2. The SDL support is more portable, and the GTK support allows better integration as a Firefox plugin. When using GTK, a right-button mouse click will activate a menu which can be used to control the movie.

Flash Support:

Many movies play without any difficulty in Gnash. Gnash supports the majority of Flash opcodes up to SWF version 7, and a wide sampling of ActionScript classes for SWF version 7. All the core ones are implemented, and many of the newer ones work, but may be missing some of the methods. All unimplemented opcodes and ActionScript classes and methods print a warning when using -v with gnash or gprocessor. Using gprocessor -v is a quick way to see why a movie isn't playing correctly.

There are plans to work towards supporting all the SWF version 8 and greater opcodes, as well as as implementing the missing methods and ActionScript classes. During the first few months of Gnash's existence as a project, most of the focus has been towards portability issues, and getting the plugin to work. Now that the plugin works, more focus will be spent on catching up to full compliance with version 7 and beyond.

Currently implemented ActionScript classes are: Array, Boolean, Date, Key, Math, Mouse, MovieClip, Number, Object, Sound, String, XML, XMLNode, and XMLSocket.

Partially implemented classes are: MovieClipLoader, NetConnection, LocalConnection, TextField, and TextFormat.

Unimplemented classes are: Accessibility, Error, Function, LoadVars, Microphone, NetStream, Selection, SharedObject, Stage, System, Button, Camera, Color, ContextMenu, CustomActions, and Video.

Unimplemented Opcodes are: Throw, Implements, Extends, enum_object, Try, new_method, enum_object, md length, md substring, md chr, delete, and get target.

There is currently no support for FLV video, more than minimal AMF data, or loading external jpegs.

Gnash Usage

Gnash can be used as a standalone player or as a plugin. Using it as a standalone player, you can execute any flash movie from the command line by just supplying the file name. No command line options are required to just play the movie using the default actions. So if you type:

gnash samples/car_smash.swf

It will create a window and play the movie. In this case it's a simple animation of a car driving, swerving, and finally crashing.

Gnash Command Line Options

While by default no options are necessary, there are options that can be used to change Gnash's basic behavior.

gnash [options] file

-h

Print usage information.

-s factor

Scale the movie up/down by the specified factor.

-c

Produce a core file instead of letting SDL trap it. By default, SDL traps all signals, but sometimes a core file is desired to assist with debugging.

-d num

Number of milliseconds to delay in main loop. The main loop polls continuously with a delay to adjust how long Gnash sleeps between iterations of the loop. The smaller the number, the higher the CPU load gets, and of course, the more iterations of the main command loop.

-p

Run full speed (no sleep) and log frame rate.

-a

Enable Actionscript debugging.

-v

Be verbose; i.e. print debug messages to stdout.

-va

Be verbose about movie Actions.

-vp

Be verbose about parsing the movie. Warning: this can generate a lot of text, and can affect the performance of the movie you are playing.

-ml bias

Specify the texture LOD bias (float, default is -1) This affects the fuzziness of small objects, especially small text.

-w

Write a debug log called gnash-dbg.log. This will record of all the debug messages whether they are printed to the screen or not.

-j

Specify the width of the window. This is mostly used only by the plugin.

-k

Specify the height of the window. This is mostly used only by the plugin.

-1

Play once; exit when/if movie reaches the last frame. This is the default.

-r [0|1|2|3]

0 disables rendering and sound (good for batch tests).

1 enables rendering and disables sound (default setting).

2 enables sound and disables rendering.

3 enables rendering and sound.

-t sec

Timeout and exit after the specified number of seconds. This is useful for movies which repeat themselves.

-g

Start Gnash with a Flash debugger console so one can set break points or watchpoints.

-x id

This specifies the X11 window ID to display in; this is mainly used by plugins.

-b bits

Bit depth of output window (for example, 16 or 32). Appropriate bit depths depend on the renderer and GUI library used. FIXME: add information about which depths are suitable for each renderer.

-u url

Set the _url member of the root movie. This is useful when you download a movie and play it from a different location. See also the -U switch.

-U baseurl

Set base url for this run. URLs are resolved relative to this base. If omitted defaults to the _url member of the top-level movie (see the -u switch).

-P parameter

Parameters are given in ParamName=Value syntax and are mostly useful to the plugin to honour EMBED tags attributes or explicit OBJECT PARAM tags. A common use for -P is to provide FlashVars (ie: -P "FlashVars=home=http://www.gnu.org").

Gnash Interactive Control Keys

While a movie is playing, there are several control keys. These can be used to step through frames, pause the playing, and control other actions.

CTRL-Q

Quit/Exit.

CTRL-W

Quit/Exit.

ESC

Quit/Exit.

CTRL-P

Toggle Pause.

CTRL-R

Restart the movie.

CTRL-[ or kp-

Step back one frame.

CTRL-] or kp+

Step forward one frame.

CTRL-T

Debug. Test the set_variable() function.

CTRL-G

Debug. Test the get_variable() function.

CTRL-M

Debug. Test the call_method() function.

CTRL-B

Toggle the background color.

User Configuration File

Gnash supports a configuration file which lives in the users home directory. This file is called .gnashrc. In this you can have default settings which will be used by Gnash when running standalone, or as a browser plugin. Any command line options override these values.

Gnash supports three types of configuration variables. The three types are an on/off value, a numeric value, or in the case of the whitelist and blacklist, a list of hostnames as ASCII text.

localdomain

This value can be set to either on or off, and controls the loading of external Flash movies over a network. Traditionally this tells Gnash to only load Flash movies from the existing domain.

localhost

This value can be set to either on or off, and controls the loading of external Flash movies over a network. This is a stricter version of the localdomain setting as this allows the loading of Flash movies to the same host Gnash is running on.

whitelist

This is a list of hostnames, seperated by a colon :. If this list is not empty, only external flash movies from these hosts are allowed to load.

blacklist

This is a list of hostnames, seperated by a colon :. External flash movies from these domains are never allowed to load. If whitelist is present and not empty, blacklist is not used.

delay

Gnash uses a timer based event mechanism to advance frames at a steady rate. This lets one override the default setting in Gnash to play a movie slower or faster.

verbosity

This is a numeric value which defines the default level of verbosity from the player.

MalformedSWFVerbosity

This value can be set to either on or off, and controls whether malformed SWF errors should be printed. If set to true, verbosity level is automatically incremented. Set 'verbosity' to 0 afterwards to hush.

ASCodingErrorsVerbosity

This value can be set to either on or off, and controls whether ActionScript coding errors should be printed. If set to true, verbosity level is automatically incremented. Set 'verbosity' to 0 afterwards to hush.

debuglog

This is the full path and name of debug logfile as produced by Gnash.

writelog

This value can be set to either on or off, and controls whether a debug log is always written by Gnash, or not at all.

sound

This value can be set to either on or off, and controls the sound of the standalone player. By default Gnash enables playing the sound in any Flash movie. Refer to pluginsound to control sound for the browser plugin.

pluginsound

This value can be set to either on or off, and controls the sound of the player when running as a browser plugin. By default, sound is enabled when using Gnash as a browser plugin. Refer to sound for information about standalone player sound control.

My current Gnash configuration file looks like this:

  
    #
    # Gnash client options
    #

    # Only access remote content from our local domain
    set localdomain on

    # Only access content from our local host
    set localhost on

    # These sites are OK
    # uncommenting the following line will allow load of external
    # movies *only* from the specified hosts.
    #set whitelist www.doonesbury.com:www.cnn.com:www.9news.com

    # Don't access content from these sites
    set blacklist www.doubleclick.com:mochibot.com

    # The delay between timer interupts
    set delay 50

    # The default verbosity level
    set verbosity 1

    # Be verbose about malformed SWF
    set MalformedSWFVerbosity true

    # Be verbose about AS coding errors
    set ASCodingErrorsVerbosity true

    # The full path to the debug log
    set debuglog ~/gnash-dbg.log

    # Write a debug log to disk
    set writelog on

    # Enable or Disable sound for the standalone player
    set sound on

    # Enable or Disable sound for the standalone player
    set pluginsound on

  

Flash Debugger

Built into Gnash is a debugger for Flash movies. As there are no line numbers nor real addresses in memory for symbols, it's difficult to know now to set breakpoints. The existing debugger implementation is limited to variables watch points and function breakpoints.

Most of the debugger commands display information about variables, the stack, registers, or ActionScript objects. It is also possible to change these values in place when debugging to help change the behaviour of a movie to determine the true problem.

Gnash developers can also insert a break where ever they want by adding a few lines of code to the source file and recompiling. The initial line gets a handle for the running debugger, and the second, a call to Debugger::console() will break at that point.

      static gnash::Debugger& debugger = gnash::Debugger::getDefaultInstance();
      debugger.console();
    

?

Display a help screen of commands.

q

Quit Gnash.

t

Toggle Trace Mode on or off. Trace mode prints a dissasemble for each opcode as it executes in a similar fashion to the -va option.

c

Continue executing the movie. It will continue until a break or watch point is hit, or continue to the end of the movie if not.

d

Dissasemble the current opcode.

Info commands are all started with the i command, which is an abbreviation for "info". The info commands dump out information on the state of the program.

i

Dumps the movie infomation, version number, filename, etc...

f

Dumps the stack frame entries.

s

Dump the symbol tables. Everytime a function or method is created it's stored in a symbol table along with it's address. This function is probably only useful to Gnash developers.

g

Display the values of the 4 global registers.

r

Display the values of the local registers, if any exist.

l

Display the values of all the local variables..

w

List the watchpoints.

b

List all the breakpoints.

c

List the Call Stack.

Watch points are debugger commands that drop you into the debugger console when the specified variable's value is either read, or changed.

name r

Set a watch point that triggers when the variable is read.

name w

Set a watch point that triggers when the variable is written to.

name b

Set a watch point that triggers when the variable is read or written to.

d

Delete a watchpoint by name.

Break points are debugger commands that drop you into the debugger console when the specified function is about to be executed by the Flash VM.

t

Enable a breakpoint on a function.

f

Disable an existing breakpoint without deleting it.

d

Delete a breakpoint by name.

Watch points are debugger commands that drop you into the debugger console when the specified variable's value is either read, or changed.

name r

Set a watch point that triggers when the variable is read.

name w

Set a watch point that triggers when the variable is written to.

name b

Set a watch point that triggers when the variable is read or written to.

d

Delete a watchpoint by name.

Break points are debugger commands that drop you into the debugger console when the specified function is about to be executed by the Flash VM.

set var [name] [value]

set stack [index] [value]

set reg [index] [value]

set global [index] [value]

Building From Source

Overview

The typical process of building from source will involve resolving dependencies, configuration, compilation, testing, and installation. A simplified overview of the process would be:

        ./autogen.sh
        ./configure 
        make
        make check
        make install
      

Continue reading for detailed step-by-step instructions of the entire procedure.

Code Dependencies

Gnash has dependencies on other packages. When installing from a packaged release file (rpm, deb, etc.), you'll need to install the development versions to get the tools used to compile Gnash. The normal runtime packages installed are usually missing the headers needed to compile Gnash.

OpenGL

Gnash uses OpenGL for rendering the images. OpenGL is a 3D graphics package which supports hardware acceleration. You can get the free version of OpenGL at this link: http://www.mesa3d.org

To install a binary package using apt-get (on Debian based systems), install libgl1-mesa-dev. For RPM or Yum based systems, install the libmesa-devel package.

AGG

AGG is the AntiGrain low-level 2D graphics library used instead of OpenGL on embedded systems. This can be used on the desktop as well, but its primary purpose is to run without OpenGL.

To install a binary package using apt-get (on Debian based systems), install libagg-dev. For RPM or Yum based systems, install the agg-devel package.

GtkGlExt

GtkGlExt is an optional package used instead of SDL. Gtk enables better integration with Firefox, as well as better event handling and higher level GUI constructs like menus and dialog boxes.

To install a binary package using apt-get (on Debian based systems), install libgtkglext1-dev. For RPM or Yum based systems, install the gtkglext-devel package.

Pango

Pango is a dependency of GtkGlExt, and is used for font handling.

To install a binary package using apt-get (on Debian based systems), install libpango1.0-dev. For RPM or Yum based systems, install the pango-devel package.

Atk

Atk is a dependency of GtkGlExt, and is used for accessibility support.

To install a binary package using apt-get (on Debian based systems), install atk-dev. For RPM or Yum based systems, install the atk-devel package.

Cairo

Cairo is a dependency of GtkGlExt, and is used for 2D rendering.

To install a binary package using apt-get (on Debian based systems), install libcairo2-dev. For RPM or Yum based systems, install the cairo-devel package.

Boost

Boost is a library of portable C++ classes and templates which layer on top of STL. Boost is used for thread and mutext handling.

To install a binary package using apt-get (on Debian based systems), install libboost-thread-dev. For RPM or Yum based systems, install the libboost-devel package.

Glib

Glib is a dependency of GtkGlExt, and is a collection of commonly used functions.

To install a binary package using apt-get (on Debian based systems), install glib-dev. For RPM or Yum based systems, install the glib-devel package.

Gstreamer

Gstreamer is used for sound and video support. It is not needed to build this release. Currently only Gstreamer version 0.10 or higher can be used.

To install a binary package using apt-get (on Debian based systems), install libgstreamer0.10-dev. For RPM or Yum based systems, install the gstreamer-devel package. Version 0.10 or greater will be required.

FFMPEG

FFMPEG can also be used for sound and video support. It is not needed to build this release, but is recommended if you want working sound.

To install a binary package using apt-get (on Debian based systems), install ffmpeg-dev. For RPM or Yum based systems, install the libffmpeg-devel package. Version 0.10 or greater will be required.

SDL

The Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer. You can get SDL from this link: http://www.libsdl.org

To install a binary package using apt-get (on Debian based systems), install libsdl1.2-dev. For RPM or Yum based systems, install the SDL-devel package.

PNG

PNG is a patent-free image format that is comparable to GIF.

To install a binary package using apt-get (on Debian based systems), install libpng12-dev. For RPM or Yum based systems, install the libpng package.

JPEG

JPEG is a lossy image format, heavily used for images because of the smaller size of the file.

To install a binary package using apt-get (on Debian based systems), install libjpeg62-dev. For RPM or Yum based systems, install the libjpeg package.

libxml2

Libxml2 is the GNOME XML parser library. This is used when Gnash is configured with XML support. Libxml2 is used to parse any incoming messages when using the XML or XMLSocket ActionScript classes. You can get libxml2 from this link: http://xmlsoft.org

To install a binary package using apt-get (on Debian based systems), install libxml2-dev. For RPM or Yum based systems, install the libxml2-devel package.

Ogg Vorbis

Ogg Vorbis is a patent free audio format that is comparable (many people say better) to MP3. This is used by SDL to play Ogg files. You can get Ogg Vorbis from this link: http://www.vorbis.com/.

To install a binary package using apt-get (on Debian based systems), install libogg-dev. For RPM or Yum based systems, install the libogg package.

libMAD

libMad is a high-quality MPG decoder for audio files. All variations of the MP3 format are supported. http://www.underbit.com/products/mad/. You can get libMAD from this link: http://xmlsoft.org

To install a binary package using apt-get (on Debian based systems), install libmad0-dev. For RPM or Yum based systems, install the libmad package.

Mozilla/Firefox

The Mozilla development package is no longer needed to build the plugin. The required header files are now included in Gnash, so it builds without Mozilla or Firefox installed at all.

To install a binary package using apt-get (on Debian based systems), install mozilla-dev or firefox-dev. For RPM or Yum based systems, install the mozilla-devel or firefox-devel package.

Documentation Dependencies

Docbook

Docbook is an industry standard XML format for technical documentation. It is used by many projects, as there are free software implementations of the Docbook style-sheets and tools. It is used by both the GNOME project, and the Linux Documentation Project. It is customizable by using style-sheets for each output device. Default style-sheets are included for a variety of print formats, like PDF and HTML.

You can get Docbook from this link: http://sourceforge.net/project/showfiles.php?group_id=21935#files.

To install a binary packages using apt-get (on Debian based systems), install the docbook, docbook-xsl, docbook-xml, docbook-dsssl,and docbook-utils packages. For RPM or Yum based systems, install the docbook, docbook-style-xsl, docbook-style-dsssl, and docbook-utils packages.

DocBook2X

DocBook2X is a software package that converts DocBook documents into the traditional Unix man page format and the GNU Texinfo format. It supports tables for man pages, internationalization, and easy customization of the output using XSLT. This package is used to convert the Gnash documentation into HTML and Texinfo formats. Texinfo can later be converted to standard GNU info pages.

You can get DocBook2X from this link: http://docbook2x.sourceforge.net/. Texinfo is available at this link: http://ftp.gnu.org/gnu/texinfo/.

To install a binary package of DocBook2X using apt-get (on Debian based systems), install docbook2x. For RPM or Yum based systems, install the docbook2x package. To install a binary package of DocBook2X using apt-get (on Debian based systems), install texinfo. For RPM or Yum based systems, install the texinfo package.

FOP

FOP (Formatting Objects Processor) is the world's first print formatter driven by XSL formatting objects (XSL-FO) and the world's first output independent formatter. It is a Java application that reads a formatting object (FO) tree and renders the resulting pages to a specified output. Output formats currently supported include PDF, PCL, PS, SVG, XML, Print, AWT, MIF and Text. The default output target is PDF.

You can get fop from this link: http://xmlgraphics.apache.org/fop/. Presently only fop version 0.20.5 works with current DocBook tools.

Java

The fop processor is a Java application, so it needs a Java runtime to work. This is installed on many platforms by default, but unfortunately fop doesn't work with the GCJ runtime. There is apparently work being done on FOP to make it usable, but for now, this means installing Sun Java.

In addition to the default j2re package, you also need to install JAI, the Java Advanced Imaging library. You can get JAI from this link. JAI is not required, and the PDF file will be generated. It will just be missing all the graphics.

Fop also requires an environment variable to be set. This is JAVA_HOME. This needs to point to the top directory where your Sun j2re is installed. If you have any other problems with your Java installation, you can also try adding the Sun j2re path to the CLASSPATH environment variable.

Configuring The Code

Gnash uses GNU Autoconf ( http://www.gnu.org/software/autoconf) for configuration. All the standard configure options apply.

The configure script is not included in the CVS sources. It must be produced by running the ./autogen.sh script in the top level source directory. This script requires you have autoconf, automake, and libtool installed. After building this script, you can configure Gnash by running it from the source directory like this: ./configure, or from another directory by specifying the full path to configure.

By default, `make install' will install all the files in `/usr/local/bin', `/usr/local/lib' etc. You can specify an installation prefix other than `/usr/local' using `--prefix', for instance `--prefix=$HOME'.

Occasionally the default paths for a development package aren't correct. There are several options which can be used to adjust these paths to your own setup. By default, Gnash will look in all the standard places for these tools.

A configure script can support many options, but they fall into two main types. The first type are options to enable or disable features. The second type is used to specify custom paths for development packages which can't be found by the default searching and testing.

Specifying A Custom Path

This set of options typically use a --with-[name] naming convention. A Prefix can often be supplied, which is the top level directory which can be used to look for the other sub directories. Most options of this type have two variations, one to specify a path to the header files, and another to specify a path to the libraries. This lets you override the default paths configure finds, or specify your own paths.

By default, none of the options should be required unless you want Gnash to use a specific version of a development package, or the configure test for Gnash fails to find the component. There are a lot of options, but Gnash has a lot of dependencies. If you find a configure test is failing on your machine, please submit a patch or file a bug report.

--x-includes=DIR

X include files are in DIR.

--x-libraries=DIR

X library files are in DIR.

--with-libxml=PFX

Prefix to where libxml is installed.

--with-libxml-libraries=DIR

Directory where libxml library is installed.

--with-libxml-includes=DIR

Directory where libxml header files are installed.

--with-docbook=DIR

Directory where the DocBook style-sheets are installed.

--with-sdl-prefix=PFX

Prefix where SDL is installed.

--with-zlib-incl

Directory where zlib header is installed.

--with-zlib-lib

Directory where zlib library is installed.

--with-jpeg-incl

Directory where jpeg header is installed.

--with-jpeg-lib

Directory where jpeg library is installed.

--with-png-incl

Directory where png header is installed.

--with-png-lib

Directory where png library is installed.

--with-qt-dir

Directory where QT is installed. This is only used by the Klash plugin.

--with-qt-includes

Directory where the QT header files are installed. This is only used by the Klash plugin.

--with-qt-libraries

Directory where the QT libraries are installed. This is only used by the Klash plugin.

--with-plugindir

This is the directory to install the Firefox plugin in.

--with-ming

Ming is used to build test cases, but not by the Gnash player itself.

--with-mad_incl

Directory where libmad header is installed.

--with-mad_lib

Directory where libmad library is installed.

--with-ogg_incl

Directory where the libogg headers are installed.

--with-ogg_lib

Directory where the libogg library is installed.

--with-gstreamer-incl

Directory where the Gstreamer headers are installed. Gstreamer version 0.10 or greater must be used.

--with-gstreamer-lib

Directory where the Gstreamer library is installed. Gstreamer version 0.10 or greater must be used.

--with-opengl-includes

Directory where OpenGL (libMesa) headers are installed.

--with-opengl-lib

Directory where the OpenGL (libMesa) library is installed.

--with-glext-incl

Directory where GtkGlExt headers are installed.

--with-glext-lib

Directory where the GtkGlExt library is installed.

--with-gtk2-incl

Directory where the Gtk2 headers are installed.

--with-gtk2-lib

Directory where the Gtk2 library is installed.

--with-cairo_incl

Directory where the Cairo headers are installed.

--with-cairo-lib

Directory where the Cairo library is installed.

--with-glib-incl

Directory where the Glib headers are installed.

--with-glib-lib

Directory where the Glib library is installed.

--with-pango-incl

Directory where the Pango headers are installed.

--with-pango-lib

Directory where the Pango library is installed.

--with-atk-incl

Directory where the ATK headers are installed.

--with-atk-lib

Directory where the ATK library is installed.

--with-pthread-incl

Directory where the Pthread headers are installed.

--with-pthread-lib

Directory where the Pthread library is installed.

--with-agg-incl

Directory where the AGG (Antigrain) headers are installed.

--with-agg-lib

Directory where the AGG (Antigrain) library is installed.

--with-ffmpeg-incl

Directory where the FFMPEG headers are installed.

--with-ffmpeg-lib

Directory where the FFMPEG library is installed.

--with-boost-incl

Directory where the Boost headers are installed.

--with-boost-lib

Directory where the Boost library is installed.

--with-curl-incl

Directory where the libCurl headers are installed.

--with-curl-lib

Directory where the libCurl library is installed.

Configure Options

In addition to being able to specify your the directories for various sub-components, there are also some switches which can be used at configuration time to enable or disable various features of Gnash. There are defaults for all of these options. These are typically used only by developers who don't have all the other development packages installed, and want to limit what is required for a quite build of Gnash.

--disable-fork

Disable the plugin forking the standalone player, and using a thread for the player instead. Currently forking the standalone player will give you the best results.

--enable-plugin

Enable building the plugin. By default the Mozilla Firefox plugin won't be built, even if all the required files are found by configure. Configure --with-plugindir= to specify where the plugin should be installed.

--disable-glext

Disable using GtkGlExt, which forces the use of SDL instead. By default if the GtkGL extension for Gtk is found by configure, the GTK enabled GUI is built.

--disable-klash

Disable support for Konqueror plugin. If --enable--plugin is specified, and support for building KDE programs is found, Klash is built by default. This option limits the plugin to only the Mozilla/Firefox one.

--disable-debugger

Disable support for the Flash debugger. The debugger is mainly of interest to Flash developers.

--enable-libsuffix

/lib directory suffix (64,32,none=default). This is only used by Klash.

--enable-embedded

Link to Qt-embedded, don't use X. This is only used by Klash.

--enable-qtopia

Link to Qt-embedded, link to the Qtopia Environment. This is only used by Klash.

--enable-mac

Link to Qt/Mac (don't use X). This is only used by Klash.

--enable-sdk-install

Enable installing the libraries and headers as an SDK.

--enable-testing

Enable testing-specific methods.

--enable-strict

Turn on tons of GCC compiler warnings. By default only -Wall is used with GCC.

--enable-ghelp

Enable support for the GNOME help system.

--enable-dom

When using the XML library, parse the messages using a DOM based parser. This is the default.

--enable-xmlreader

When using the XML library, parse the messages using a SAX based parser.

--enable-dmalloc

Enable support for the DMalloc memory debugging tool.

--enable-i810-lod-bias

Enable fix for Intel 810 LOD bias problem. Older versions of libMesa on the Intel i810 or i815 graphics processor need this flag or Gnash will core dump. This has been fixed in newer versions (summer 2005) of libMesa.

--enable-sound=gst|sdl

Enable support for the a sound handing system. Currently only sdl works sufficiently. This is enabled by default when building Gnash.

--with-mp3-decoder=ffmpeg|mad

Specified the MP3 decoder to use with sdl sound handler. Mixing this with --enable-sound=gst is invalid. Using mad is the default decoder.

--enable-renderer=opengl|cairo|agg

Enable support for the a graphics backend. Currently only opengl and agg work sufficiently. OpenGL is used when you have hardware accelerated graphics. AGG i used when you don't have hardware accelerated graphics. Typically most desktop machines have OpenGL support, and most embedded systems don't. OpenGl is the default when building Gnash.

You can control other flags used for compiling using environment variables. Set these variables before configuring, and they will be used by the configure process instead of the default values.

CXX

C++ compiler command.

LDFLAGS

linker flags, e.g. -L[library directory] if you have libraries in a nonstandard directory.

CPPFLAGS

C/C++ preprocessor flags, e.g. -I[headers directory] if you have headers in a nonstandard directory.

CXXFLAGS

C++ compiler flags.

Cross Compiling And Configuration

To cross configure and compile Gnash, you first need to build a target system on your workstation. This includes cross compilers for the target architecture, and typically some system headers. You will also need libxml2, libpng, libjpeg, sdl, opengl, and ogg development packages built for the target system.

If you need to build up a target system from scratch, there is a good document and shell script at this web site: http://frank.harvard.edu/~coldwell/toolchain/.

After I built up an ARM system in /usr/arm using the shell script from this web site, I then cross compiled all the other libraries I needed. The fun part is trying to get libMesa to cross compile, because it's not really set up for that.

So to build for an ARM based system on an x86 based systems, configure like this:

        ../../gnash/configure --build=i686-pc-linux-gnu --host=arm-linux --prefix=/usr/local/arm/oe --disable-plugin --enable-renderer=agg --disable-shared --with-mp3-decoder=mad
      

The important options here are the ones that specify the architectures for the build.

--target

The target architecture. This is the architecture the final executables are supposed to run on.

--host

The host architecture. This is the architecture the executables are supposed to run on. This is usually the same as --target except when building a compiler as a Canadian Cross. This is when you build a cross compiler on a Unix machine, that runs on a win32 machine, producing code for yet a third architecture, like the ARM.

--build

This is the system this build is running on.

Building Gnash

After managing to configure Gnash, building the code is simple. Gnash is built using GNU make.

Compiling The Code

After configuring, typing make will compile the code. No options are necessary. If desired, you can redefine the variables used by make on the command line when invoking the program. The few flags of interest are CFLAGS and CXXFLAGS, often used to turn on debugging or turn off optimizing. Invoking make as in this example would build all the code with debugging turned on, and optimizing turned off. The default values for both of these variables is -O2 -g.

	  make CFLAGS=-g CXXFLAGS=-g
	

If the compilation ends with an error, check the output of configure and make sure nothing required to build Gnash is missing.

Processing The Documentation

By default, the documentation isn't built at all. It isn't even built when typing make install from the top level build directory. It's only built when specified with a specific target in the generated Makefile in the doc/C/ sub-directory. All the documents are built in this directory when executing a make install.

There is a target for each output format, make html, make pdf, make info, and make man. A higher level target, make alldocs, builds the four main formats for the documentation.

Gnash also has support to use Doxygen to produce HTML pages documenting the internals of Gnash. While this is not necessarily internals documentation, it does give very useful information about all the files, the classes, a cross reference, and other data.

You need to have Doxygen installed to produce these documents. If you do have it installed, typing make apidoc in the doc directory will make these documents under a sub directory of apidoc/html

Running the Tests

Using DejaGnu

FIXME: Add a section on running tests without DejaGnu. The easiest way to run Gnash's test suite is to install DejaGnu. After installing DejaGnu, run:

            make check
          

Increasing Verbosity

If you encounter a problem with a test, increasing the verbosity may make the issue easier to spot. Additional details are visible when RUNTESTFLAGS are used to add the verbose and all options. Verbose prints more information about the testing process, while all includes details on passing tests.

              make check RUNTESTFLAGS="-v -a"
            

Running Some Tests

It is possible to run just a particular test, or subdirectory of tests, by specifying the directory or compiled test file.

Some tests rely on testsuite/Dejagnu.swf, which in turn relies on Ming. This file is created when you run 'make check' for the entire testsuite, and can also be created on demand:

              make -C testsuite Dejagnu.swf 
            

In this example, the 'clip_as_button2' test is compiled and run:

              make -C testsuite/samples clip_as_button2-TestRunner 
              cd testsuite/samples && ./clip_as_button2-TestRunner
            

This would create and run all the tests in the directory 'movies.all':

              make -C testsuite/movies.all check
            

Running The Tests Manually

You may also run test cases by hand, which can be useful if you want to see all the debugging output from the test case. Often the messages which come from deep within Gnash are most useful for development.

The first step is to compile the test case, which can be done with 'make XML-v#.swf' where the '#' is replaced with the target SWF version or versions. For example:

            make XML-v{5,6,7,8}.swf
          

Movie tests

This creates a Flash movie version of the test case, which can be run with a standalone Flash player. For instance, the target for SWF version 6 could be run with Gnash:

              gnash -v XML-v6.swf
            

ActionScript Unit Tests

Unit tests for ActionScript classes in 'testsuite/actionscript.all' are run without a graphical display:

              gprocessor -v XML-v6.swf
            

Installation

Gnash installs its libraries so they can be found in the runtime path for the Gnash executable. Unless the --prefix option is used at configuration time, the libraries get installed in /usr/local/lib. If you install Gnash in a non-standard location, you have to specify this runtime path by one of two means.

The traditional way that works on all Unix platforms is to set the LD_LIBRARY_PATH environment variable to $prefix/lib. You can have multiple paths in this variable as long as they are seperated by a colon ":" character.

For GNU/Linux systems, the custom path to the libraries can be added to the /etc/ld.so.conf file. After adding the custom path, then run (as root) the ldconfig command to update the runtime cache.

What Code Gets Installed and Where

Several libraries get installed, as well as the three executables. All the libraries, libbase, libgeometry, libgbackend, libserver, and libmozsdk get installed in the directory pointed to by $prefix. This variable is set by the --prefix option at configure time, and if not specified, it defaults to /usr/local. All the libraries get installed in $prefix/lib where most packages also install their libraries.

The plugin gets installed in the plugins directory of the version of theFirefox or Mozilla you have the development packaged installed for. For builds from Mozilla CVS, the default installation directory is /usr/local/lib/firefox-[version number]/plugins/. The default system directory used when installing packages is /usr/lib/mozilla/plugins. Note that you have to be root to install files in a system directory. For some reason when the plugin is installed in the users $HOME/.mozilla/plugins or $HOME/.firefox/plugins directory, unresolved symbols from deep within Firefox appear.

The executables get installed in a bin directory of the directory specified by $prefix. Once again, this path defaults to /usr/local/bin if a special prefix wasn't configured in.

If using a single file-system NFSmounted to multiple platforms, you can specify an additional option, --exec-prefix. This is where all the platform dependent executables and libraries can get installed.

What Documentation Gets Installed and Where

The documentation only installs when GNOME Help support is enabled by using --enable-ghelp. Because GNOME help files get installed in a system directory when building from source, you need to either change the permissions on the destination directory, or do the install as root. The default directory for GNOME Help files is: /usr/local/share/gnash/doc/gnash/C/.

A configuration file in the Gnash source tree, doc/C/gnash.omf is used to specify under which menu item Gnash is listed in the GNOME Help system.

Software Internals

A Tour of Gnash

The top level of Gnash has several libraries, libgnashbase, libgnashgeo, libgnashserver, libgasnhasobjs and libgnashbackend. There are two utility programs included for debug parsing and processing of Flash movie files which test the Actionscript interpreter. There is also a standalone flash movie player.

The Libraries

libgnashbase

Libgnashbase contains support classes used by the rest of the code. Among these classes is a small and efficient STL library clone that uses smart pointers. A current goal is to replace this small STL clone with standard STL containers to reduce the amount of code which has to be maintained, and to add functionality not currently in the smaller implementation.

Gnash makes heavy use of smart pointers, so memory allocations are freed up automatically by the interpreter.

libgnashgeo

Libgnashgeo contains code for device independent graphics routines.

libgnashui

Libgnashgui contains code for a portable GUI class that supports using GTK2, a framebuffer, SDL, or KDE.

libgnashserver

Libgnashserver is the guts of the interpreter itself. This is where the main code for the interpreter lives.

libgnashasobjs

Libgnashasobjs contains all the ActionScript classes used by the interpreter.

libgnashamf

AMF is the data format used internally by Flash. This is Gnash's support library to handle AMF data. This is currently unused, but when the LocalConnection class is more fully implemented, this will be used to transfer data between flash movies.

libgnashbackend

Libgnashbackend is a small library containing OpenGL and SDL code that glues this display to the Gnash display.

libgnashplugin

Libgnashplugin is the Mozilla/Firefox plugin.

libklashpart

Libklashpart is the Konqueror plugin.

The Applications

There are currently a few standalone programs in Gnash, which serve to either assist with Gnash development or play flash movies.

The Standalone Player

This is the standalone OpenGL back-end used to play movies. There are several command-line options and keyboard control keys used by Gnash which are documented here.

Gparser

Gparser uses the Gnash parser to disassemble the flash movie, and dumps the object types, the depth, and other information to make sure Gnash is parsing the file correctly.

Gprocesser

Gprocesser is used to print out the actions (using the -va option) or the parsing (using the -vp option) of a flash movie. It is also used to produce the .gsc files that Gnash uses to cache data, thereby speeding up the loading of files.

The Plugin

The plugin is designed to work within Mozilla or Firefox, although there is Konqueror support as well. The plugin uses the Mozilla NSPR plugin API to be cross platform, and is portable, as well as being well integrated into Mozilla based browsers.

One future thought for the plugin is to use the new Firefox 1.0.5 or greater version of Firefox. This version has added a GTK drawable window which supports hardware acceleration, and is designed to support things like rendering directly into the window without needing OpenGL.

Current Status

As of March 30, 2006, the plugin works! This works in a fashion similar to MozPlugger in that the standalone player is used instead of using a thread. This gets around the issue of having to maintain a separate player to support the plugin. It also gets around the other issues that Gnash itself is not thread safe at this time.

There are a few limitations in the current implementation, but it works well enough to be used for web surfing. The main limitations are the SDL version has no event handling, and sound doesn't work yet.

GUI Support

Any plugin that wants to display in a browser window needs to be tied into the windowing system of the platform being used. On GNU/Linux systems, Firefox is a GTK2+ application. There is also KDE support through the use of the Klash plugin.

Gnash can use either SDL or GTK now to create the window, and to handle events for the standalone player. Work is underway to add a portable interface for more windowing toolkits to allow better embedded device support when running in framebuffer only devices.

The SDL version is more limited, but runs on all platforms, including win32. It has no support for event handling, which means mouse clicks, keyboard presses, and window resizing doesn't work. I personally find the default event handler slow and unresponsive. Gnash has support to use fast events, (currently not enabled) which is an SDL hack using a background thread to pump events into the SDL event queue at a much higher rate.

There are a variety of development libraries that build a GUI widget system on top of SDL and OpenGL. The use of these to add menus and dialog boxes to the SDL version is being considered.

The GTK support is currently the most functional, and the best integrated into Firefox. The performance of this version is better than the SDL version because of the more efficient event handling within GTK. For the best end user experience, use the GTK enabled version.

GTK also allows Gnash to have menus and dialog boxes. Currently this is only being utilized in a limited fashion for now. There is a right mouse button menu that allows the user to control the movie being player the same way the existing keyboard commands do.

Mozplugger

Mozplugger is a Mozilla/Firefox plugin that uses external programs to play video, audio, and other multimedia content in the browser. With some support added to the external application, it's possible to force the external program to use the internal window in the browser where this plugin is supposed to display. This enables one to then run the standalone player and display its output in the browser.

While this is not an optimal solution, it does enable one to use Gnash as the flash player when browsing. The main issue appears to be that the Flash movie being played doesn't get any mouse or keyboard input. That may be a mozplugger configuration issue, however.

Use of MozPlugger is obsolete now that the Gnash plugin works. Still, this may be useful still on some platforms.

Add this to your $(HOME)/.mozilla/mozpluggerrc file to enable this:

	    application/x-shockwave-flash:swf:Shockwave Gnash
        nokill embed noisy ignore_errors hidden fill swallow(Gnash) loop: gnash -v "$file" -x $window
        : gnash -v "$file" -x $window
	  

Once this is added, you must delete the $(HOME)/.mozilla/firefox/pluginreg.dat file to force Firefox to register the plugins again. This is an ASCII text file, so if the patch has been added correctly, you'll see an entry for swf files after it is recreated. You will need to restart Firefox to recreate this file.

This file is not recreated immediately when restarting Firefox, but waits till the first time a plugin is used. You can force creation of this file by typing about:plugins into the URL entry of the browser window. The output will also contain information about the mozplugger. You should see an entry for Gnash now.

Klash

Klash is MozPlugger type support for KDE's Konqueror web browser. Klash makes Gnash a kpart, so it's integrated into KDE better than when using MozPlugger. Klash uses the standalone player, utilizing Gnash's "-x" window plugin command line option.

By default, Klash is not built. To enable building Klash, use the --enable-klash option when configuring. Other than installing, there is nothing else that needs to be done to install Klash.

Mozilla/Firefox Plugin

The Mozilla SDK has two API layers for plugins. The older layer is documented in the Geeko Plugin API Reference, and the newer layer doesn't appear to be documented. The new API is simpler, and is portable across multiple versions of Mozilla or Firefox. The new API is just a layer on top of the older one, so this manual still applies.

Most of the programming of a plugin is filling in real emphasis for the standard API functions and methods. Firefox uses these to create the plugin, and to send it data.

When initializing or destroying a plugin, no matter how many instances are being used, the C API is used. These functions are typically called once for each plugin that is loaded.

Plugin C API

The lower layer is a C based API which is used by Firefox to initialize and destroy a plugin. This is so a plugin can be portable across multiple systems, since C++ emphasis is not portable between most C++ compilers. This where most of the behind the scenes work is done in a plugin. For Gnash, the sources this lower layer are in plugin/mozilla-sdk. They were added to the Gnash source tree so it wouldn't be necessary to have the Mozilla development packages installed to compile the Gnash plugin.

This is also the older API used for plugins, so is usually the one used if you dig around for plugin examples on the web. These are the main functions which have to be implemented in a plugin for it to be recognized by the browser, and to be initialized and destroyed.

NS_PluginInitialize

This C function gets called once when the plugin is loaded, regardless of how many instantiations there are actually playing movies. So this is where all the one time only initialization stuff goes that is shared by all the threads.

NS_NewPluginInstance

This instantiates a new object for the browser. Returning a pointer to the C++ plugin object is what ties the C++ and C emphasis parts of the API together.

NS_DestroyPluginInstance

This destroys our instantiated object when the browser is done.

NS_PluginShutdown

This is called when a plugin is shut down, so this is where all the one time only shutdown stuff goes.

NPP_GetMIMEDescription

This is called to get the MIME types the plugin supports.

NS_PluginGetValue

This is used by Firefox to query information from the plugin, like the supported MIME type, the version number, and a description.

Plugin C++ API

The higher level layer is the one we are most concerned with. This is an instantiation of the nsPluginInstanceBase class, as defined by the Mozilla SDK, for our plugin. With this API, a plugin is mostly defining the standard entry points for Firefox, and the emphasis that implements the glue between the Firefox and our plugin.

These are called for each instantiation of plugin. If there are three Flash movies on a web page, then three instances are created. Unfortunately for plugin programmers, these functions may randomly be called more than once, so it's good to use initialization flags for things that should only be done one per thread. For instance, nsPluginInstance::init() and nsPluginInstance::SetWindow() are called more than once, so the plugin must protect against actions that could be destructive.

nsPluginInstance::nsPluginInstance

Create a new plugin object.

nsPluginInstance::init

This methods initializes the plugin object, and is called for every movie which gets played. This is where the thread-specific information goes.

nsPluginInstance::SetWindow

This sets up the window the plugin is supposed to render into. This calls passes in various information used by the plugin to setup the window. This may get called multiple times by each instantiated object, so it can't do much but window specific setup here. This is where the main emphasis is that sets up the window for the plugin.

nsPluginInstance::NewStream

Opens a new incoming data stream, which is the flash movie we want to play. A URL can be pretty ugly, like in this example: http://www.sickwave.com/swf/navbar/navbar_sw.swf?atfilms=http%3a//www.atm.com/af/home/&shickwave=http%3a//www.sickwave.com&gblst=http%3a//gbst.sickwave.com/gb/gbHome.jsp&known=0 ../flash/gui.swf?ip_addr=foobar.com&ip_port=3660&show_cursor=true&path_prefix=../flash/&trapallkeys=true" So this is where we parse the URL to get all the options passed in when invoking the plugin.

nsPluginInstance::Write

Read the data stream from Mozilla/Firefox. For now we read the bytes and write them to a disk file.

nsPluginInstance::WriteReady

Return how many bytes we can read into the buffer.

nsPluginInstance::DestroyStream

Destroy the data stream we've been reading. For Gnash, when the stream is destroyed means we've grabbed the entire movie. So we signal the thread to start reading and playing the movie.

nsPluginInstance::shut

This is where the movie playing specific shutdown emphasis goes.

nsPluginInstance::~nsPluginInstance

This destroys our plugin object.

NS_PluginInitialize::initGL

This is a Gnash internal function that sets up OpenGL.

NS_PluginInitialize::destroyContext

This is a Gnash internal function that destroys a GLX context.

nsPluginInstance::getVersion

This returns the version of Mozilla this plugin supports.

nsPluginInstance::GetValue

This returns information to the browser about the plugin's name and description.

nsPluginInstance::URLNotify

OpenGL and Threads

Neither OpenGL nor X11 has any built-in support for threads. Most actions aren't even atomic, so care has to be made to not corrupt any internal data. While it is difficult to render OpenGL from multiple threads, it can be done with the proper locking. The downside is the locking adds a performance hit, since all the threads will have to have the access synchronized by using mutexes.

The X11 context is maintained one per instantiation of the plugin. It is necessary to lock access to the X11 context when using threads by using XLockDisplay() and XUnlockDisplay(). A connection to the X11 server is opened for every instantiation of the plugin using XOpenDisplay().

The The GLX Context is maintained one per instantiation of the plugin for a web page. If there are more than one Flash movie, there is more than one GLX Context. A GLX context can be created by using glXCreateContext(), and then later destroyed by using glXDestroyContext(). When swapping threads, the context is changed using glXMakeCurrent().

All the emphasis that directly accesses a GLX context or the X11 display must be wrapped with a mutex.

Plugin Event Handling

Firefox on most UNIX systems is a GTK+ application, so it is possible to have the plugin hook into the X11 event handling via GLX or GTK. Since Firefox uses GTK, so does Gnash. This also allows the addition of a right-click mouse menu for controlling the player. The GTK build of Gnash offers the best browsing experience as it's more functional than the SDL version.

It is also possible to disable the GTK support so only the older SDL support is used. In this case Gnash can't support event handling within the browser. This means that when using the SDL of the plugin, mouse clicks and keys pressed get ignored. Windows also can't be resized, and sometimes they overrun their boundaries as well. To disable the GTK support and force SDL to be used anyway, configure with --disable-glext

The Debug Logging System

Gnash supports a debug logging system which supports both C and C++ natively. This means you can use both printf() style debug messages and C++ iostreams style, where you can print C++ objects directly as you would when using cout.

In the beginning, Gnash only supported the C API for debug logging, so it is the most heavily used in Gnash. This API was used in the log_msg() and log_error() functions, and used a callback to set them up.

It became apparent one day the callback was never needed, and I got tired of having to use c_str() on string data just to print them out.

If a filename is not specified at object construction time, a default name of gnash-dbg.log is used. If Gnash is started from the command line, the debug log will be created in the current directory. When executing Gnash from a launcher under GNOME or KDE the debug file goes in your home directory, since that's considered the current directory.

There is common functionality between using the C or C++ API. Optional output is based on flags that can be set or unset. Multiple levels of verbosity are supported, so you can get more output by supplying multiple -v options on the command line. You can also disable the creation of the debug log.

Logging System C API

These functions are clones of the originals as they were used for Gnash. These function the same as always except output can be logged to disk now as well. These currently print no timestamp with the output, which is the older functionality. As these functions are implemented on top of the C++ API now, they can be used without corrupting the output buffers.

void log_msg(const char* fmt, ...)

Display a message if verbose output is enabled. By default the messages are always written to the disk file, but optionally displayed in the terminal.

log_error(const char* fmt, ...)

Display an error message if verbose output is enabled. By default the error messages are always written to the disk file, but optionally displayed in the terminal.

log_warning(const char* fmt, ...)

Display a warning message if verbose output is enabled. By default the error messages are always written to the disk file, but optionally displayed in the terminal.

Logging System C++ API

This is the new C++ streams based API that can be used to print C++ objects natively. All output lines are timestamped.

There are two macros used for program tracing. these can be used in both C or C++ code with one little difference. Since C doesn't have destructors, you must call GNASH_REPORT_RETURN at the end of a function to display the function returning message.

GNASH_REPORT_FUNCTION;

When this is included in a C++ method, a message is printed when entering and exiting this method by hooking into the constructor and destructor. These are always written to the disk file, but optionally written to the screen only at the highest levels of verbosity.

GNASH_REPORT_RETURN;

This is used by C functions to print the returning from function debug message. For C++, this macro is executed automatically by the destructor.

This is the main API for the logging system. By default everything is setup to write to the default gnash-dbg.log file whenever a verbose option is supplied. Optionally it is possible to open a log file with a specified name, allowing multiple output files.

openLog(const char *filespec)

Open the debug file with the name specified by filespec. This file goes in the current directory, or your home directory if using a menu based launcher.

closeLog(void)

Close a debug log. The disk file remains.

removeLog(void)

Delete the debug log file from disk.

setVerbosity(void)

Increment the verbosity level.

setVerbosity(int)

Set the verbosity level.

setStamp(bool flag)

If flag is true, then print a timestamp prefixed to every output line. If flag is false, then don't print a timestamp.

setWriteDisk(bool flag)

If flag is true, then create the disk file. If flag is false, then don't create the disk file.

ActionScript Support

Adding New ActionScript Classes

Adding a new ActionScript class is a relatively simple process. A new file is created to hold the code, with an associated header file. The file name is usually the name of the ActionScript class itself, something like XML. All implementations are written in C++. In the CVS source tree for Gnash, there is a utility file called gen-files.sh that can be used to generate a template for a new ActionScript class. At this time templates have been generated for all documented ActionScript classes.

Defining a new ActionScript Class

The header file defines the class and its methods. The symbol name used to look up the code which implements the ActionScript class is added later.

Each class needs an associated version which is a derived form of the as_object class used to internally represent objects in Gnash. At its simplest, this structure just encapsulates an object of the desired class.

	    class Foo {
	        public:
		    foo() {};
		    ~foo() {};
		    bool GetBar() { return _bar; }
		private:
		    bool _bar;
	    }
	    struct foo_as_object : public gnash::as_object {
	        Foo obj;
	    }
	  

The obj is an instantiation of the data for this object. It isn't required unless this object needs internal data that has to stay resident in the player.

Whenever this object is being handed the code for this class, it is initially accessed by its derived binding. Internal data for this object can be accessed through the obj.

	    foo_as_object *foo = env.top(0).to_object();
	    bool result = foo->obj.GetBar();
	  

A more complex example might be to add hooks to the constructor an destructor for the class to keep track of memory allocations and cleanup. In this case only a debug statement is printed.

	    struct foo_as_object : public gnash::as_object {
	        Foo obj;
	        foo_as_object() {
	            log_msg("\tCreating foo_as_object at %p \n", this);
	        };
	        ~foo_as_object() {
	            log_msg("\tDeleting foo_as_object at %p \n", this);
	        };
	    }:
	  

An even more complex example might be to add hooks to how the list of member of a class is kept. The element m_members, is a list of each symbol name and its associated code. Normally this is kept internally within the interpreter engine, but in this example for certain methods we want to return a point to itself, instead of getting the data from the list.

	    struct xml_as_object : public gnash::as_object {
	        XML obj;
	        xmlnode_as_object() {
	            log_msg("\tCreating xmlnode_as_object at %p \n", this);
	        };
	        ~xmlnode_as_object() {
	            log_msg("\tDeleting xmlnode_as_object at %p \n", this);
	        };
	        virtual bool get_member(const tu_stringi& name, as_value* val) {
	            if ((name == "firstChild") || (name == "childNodes")) {
	                val->set_as_object_interface(this);
		        return true;
	            }
		    if (m_members.get(name, val) == false) {
		        if (m_prototype != NULL) {
		            return m_prototype->get_member(name, val);
	                }
		        return false;
		    }
	          return true;
	      }
	  };
	  

Instantiating a new Class

To add a new object to the list maintained by Gnash, it needs to be added to the function gnash::action_init(), in action.cpp. The symbol name is specified along with a function pointer that will be called when the symbol name is seen by the interpreter.

	    obj->set_member("XML", as_value(xml_new));
	  

The function used to instantiate a new object is passed the creation data in a fn_call data structure. This is used to pass data both into and returned from this function.

The fn_call data structure has several methods for operating on the data for the function. fn_call::nargs is a variable that specifies how many arguments are being passed in. All the arguments are on a stack. To pop an argument off the stack, use fn.env->top(0). In this case popping the first argument off the stack.

The object popped off the stack also has its own methods. The main one of interest is get_type. This returns the type of the object being referred to.

	  if (fn.env->top(0).get_type() == as_value::STRING) {
	     ...
	  }
	  

The supported data types for an object are BOOLEAN, STRING, NUMBER, OBJECT, C_FUNCTION, AS_FUNCTION. Because they are defined as part of the as_value class, they need to always have the class name prefixed to use these as a constant. You can retrieve the value of an as_value using the conversion methods. For example, to_tu_string returns the value as string using the Gnash small STL library. Similarly, to_number would return this same value as a double.

To add methods to the class, a new class needs to be instantiated as an object. Each ActionScript object can have child methods attached in a similar way as the object was. In this case, the built-in set_member function is used.

	    xml_obj = new xml_as_object;
	    xml_obj->set_member("load", &xml_load);
	  

To make the object active within the interpreter, the new object gets returned by the function using the fn_call typed parameter.

	    fn.result->set_as_object_interface(xml_obj);
	  

A complete example of a function used to instantiate a new ActionScript object is as follows. This example also calls internally defined methods in the class, in this case to process and XML file, and to create the parsed XML tree.

	    void
	    xml_new(const fn_call& fn) {
	        as_value      inum;
	        xml_as_object *xml_obj;
	    
	        if (fn.nargs > 0) {
	            if (fn.env->top(0).get_type() == as_value::STRING) {
	                xml_obj = new xml_as_object;
		        tu_string datain = fn.env->top(0).to_tu_string();
		        xml_obj->obj.parseXML(datain);
		        xml_obj->obj.setupFrame(xml_obj, xml_obj->obj.firstChild(), true);
	            } else {
	                xml_as_object *xml_obj = (xml_as_object*)fn.env->top(0).to_object();
		        fn.result->set_as_object_interface(xml_obj);
		        return;
	            }
	        } else {
	            xml_obj = new xml_as_object;
	            xml_obj->set_member("load", &xml_load);
	            xml_obj->set_member("loaded", &xml_loaded);
	        }
	        fn.result->set_as_object_interface(xml_obj);
	    }
	  

Adding a Property

Adding a new new property to an object is similar to adding a callback for a method. Instead of using a C function, a string or number is used.

	      as_obj->set_member("nodeName", as_value("HelloWorld"));
	    

When a Flash movie looks this up as a property, the value can be found directly without a function call. This scrap of ActionScript code as compiled by Ming's makeswf compiler shows the difference.

	      // Call the hasChildNodes() function
	      if (node.hasChildNodes() == true) {
	          trace("CHILDREN");
	      }
	      // Get the value of the nodeName property
	      if (node.nodeName == "HelloWorld") {
	          trace("MATCHED");
	      }
	    

Parameter Passing

Parameters are passed to the callback functions for a class's methods and properties using the fn_call data structure. This data structure contains all the incoming parameters for a callback, as well as it contains the final result from the callback to be passed back into the player.

Getting Parameter Data

Parameter data is passed on the stack in a similar way to any function call in any language. There are several fields of the fn_call data structure that get used in this example:

	    xml_as_object *xml_obj = (xml_as_object*)fn.this_ptr;
	    if (fn.nargs) {
	        filespec = fn.env->bottom(fn.first_arg_bottom_index).to_string;
	    }
	  

Using the fn variable which was passed as the sole parameter of the callback, we can access the data. The fn.this_ptr returns a reference to the class which is invoking this method. This is how the object data can be retrieved. The fn.nargs is a count of how many objects are being passed into the callback.

The current stack of the player is passed in via the fn.env field. This is used to access the data passes to this callback. To find the location of this particular stack frame, the fn.first_arg_bottom_index field is used to point to the stack frame. More detail on the environment stack can be found here..

For this example, the stack has a as_environment::top() and a as_environment::bottom() that are used to pull arguments off the stack. When using fn.first_arg_bottom_index, the as_environment::bottom() method should be used as in the example.

The top of the stack for this frame can also be accessed using the as_environment::top() method. Top takes an integer index as to which value to retrieve,

	  if (fn.nargs > 0) {
	   name = fn.env->top(0).to_string());
	  }
	

If the type of the object is needed, that can be accessed by using the as_value::get_type() method. There are more details on the types of values in the Handling Values section of this manual.

	  if (fn.nargs > 0) {
	      if (fn.env->top(0).get_type() == as_value::STRING) {
	          name = fn.env->top(0).to_string);
	      } 
	      if (fn.env->top(0).get_type() == as_value::NUMBER) {
	          value = fn.env->top(0).to_number);
	      } 
	  }
	

The internal data for this object can be accessed through the base class. Any data set using this object will stay resident in the player.

	     foo_as_object *foo_obj = (foo_as_object*)fn.this_ptr;
	     bool bar = foo_obj->obj.GetBar();
	  

Returning Data

Data is also returned in the data structure passed to the callback. This example calls a method of the object passed in on the stack, and then sets the return code to be the return code of calling the method.

	    // Set the argument to the function event handler based on
	    // whether the load was successful or failed.
	    ret = xml_obj->obj.load(filespec);
	    fn.result->set_bool(ret);
	  

The result field of the fn variable is a gnash::as_value object, so it's possible to set the value of several data types.

Here is a short list of the most often used data types returned from callbacks:

as_value::set_bool()

Set the result to a boolean value.

as_value::set_int()

Set the result to an integer value.

as_value::set_double()

Set the result to a floating point double value.

as_value::set_string()

Set the result to a const char* value.

as_value::set_as_object_interface()

Set the result to an object value.

Flash Opcodes

There are many opcodes in Flash, and Gnash implements the majority of them up to version 7 of the Flash format. Gnash will print an "unimplemented" message whenever it sees an opcode that isn't implemented. If you try to play a movie and it doesn't appear to be executing properly, run gnash or gprocessor with the -v option to see the debug messages. You can also use the -w option to gnash to write the debug messages to disk.

Unimplemented Opcodes

As of March, 2006, these are the few opcodes that haven't been implemented for full SWF version 7 compliance. SWF version 8 adds a few more that currently aren't listed here.

0x2A Throw

Throw an error that can be caught by a catch statement.

0x2C Implements

Specifies that a subclass must define all the derived methods.

0x69 Extends

Define a subclass of a class.

0x55 enum_object

Push the name of each member of an enum on the stack.

0x8F Try

Protect a block of code during which an error may occur.

0x53 new_method

Get the name of a method.

0x31 md length

Get the length of a multi-byte string.

0x35 md substring

Get a substring from a multi-byte string.

0x37 md chr

Get a single character from a multi-byte string.

0x3A delete

Delete an object.

0x45 get target

Return the path to a sprite.

The Interpreter Engine

FIXME:

The Main Loop

FIXME:

I/O Processing

FIXME:

Handling Values

All of the main values in Gnash as used by the interpreter, are usually an as_value class. This is a generic object to hold data. The supported data types for an object are BOOLEAN, STRING, NUMBER, OBJECT, C_FUNCTION, AS_FUNCTION. You can retrieve the value of an as_value using the conversion methods. For example, to_tu_string returns the value as string using the Gnash small STL library. Similarly, to_number would return this same value as a double.

as_value is often used as the initializer for a property or the data for a callback. This is done so the type of the object is specified along with the data.

	    // Set the callback for a new XML object
	    obj->set_member("XML", as_value(xml_new));

	    // Set the property to the value of text
	    obj->set_member("nodeName", as_value(text));
	    
	    // Set the property to null, but at least it exists
	    obj->set_member("nodeValue", as_value(""));
	  

	    // Get the name of an object
	    name = fn.env->top(0).to_string());

	    // Get the value of an object
	    value = fn.env->top(1).to_number);

	  

as_value set methods

While as_value allows you to use any of the supported data types when invoking the constructor (as in the prior example). This is a common way to set the data and type of a value. Often it's necessary to set the value of an object after it is created, or to change the existing value. The = operator is also supported, so it is also possible to set a value and its type this way as well. I sort of lean towards the explicit style of setting a type, so here's all the methods that explicitly set a value.

as_value::set_bool(bool)

Set the value to a boolean value.

as_value::set_int(int)

Set the value to an integer value.

as_value::set_double(double)

Set the value to a floating point double value.

as_value::set_string(const char*)

Set the value to a const char* value.

as_value::set_tu_string(int)

Set the value to an tu_string value. Once all the containers have been converted to using standard STL classes, this method will go away.

as_value::set_nan(int)

Set the value to an NaN (Not a Number) value.

as_value::set_null()

Set the value so this is a NULL object.

as_value::set_undefined()

Set the value so this is an undefined object.

as_value::set_as_object_interface(as_object *)

Set the value to an object value.

as_value::set_as_c_function_ptr(int)

Set the value.

as_value::set_function_as_object(int)

Set the value.

as_value get methods

as_value::to_bool(bool)

Return the value as a boolean.

as_value::to_number()

Return the value as a number object.

as_value::to_string()

Return the value as a const char*.

as_value::to_tu_string(int)

Return the value as a tu_string value. Once all the containers have been converted to using standard STL classes, this method will go away.

as_value::is_nan()

Return true if set to NaN (Not a Number).

as_value::is_inf()

Returns true if the number has an infinite value.

as_value::is_finite()

Returns true if the number has an finite value.

as_value::to_object()

Return the value as an as_object_interface. This is often used as the "handle" for an object within Gnash. You would use this when you need to do set_member() or get_member() operations.

as_value::to_c_function()

Return the value as a C function pointer.

as_value::to_as_function()

Return the value as an ActionScript function.

Handling Objects

FIXME:

The Environment Stack

FIXME:

Sound handling in Gnash

When a SWF-file contains audio Gnash uses its sound handlers to play it. At the moment there are two sound handlers, but it is likely that more will be made.

There are two different settings related to sound support: pluginsound and sound. This was done in order to allow the plugin to be independently configured, for instance to block sound from advertisements.

Sound types

Sounds can be divided into two groups: event-sounds and soundstreams. Event-sounds are contained in a single SWF frame, but the playtime can span multiple frames. Soundstreams can be (and normally are) divided between the SWF frames the soundstreams spans. This means that if a gotoframe-action jumps to a frame which contains data for a soundstream, playback of the stream can be picked up from there.

Sound parsing

When Gnash parses a SWF-file, it creates a sound handler if possible and hands over the sounds to it. Since the event-sounds are contained in one frame, the entire event-sound is retrieved at once, while a soundstream maybe not be completely retrieved before the entire SWF-file has been parsed. But since the entire soundstream doesn't need to be present when playback starts, it is not necessary to wait.

Sound playback

When a sound is about to be played Gnash calls the sound handler, which then starts to play the sound and return. All the playing is done by threads (in both SDL and Gstreamer), so once started the audio and graphics are not sync'ed with each other, which means that we have to trust both the graphic backend and the audio backend to play at correct speed.

The SDL sound backend

The current SDL sound backend has replaced the original sound handler, based on SDL_mixer, which by design had some limitations, making it difficult to implement needed features such as support for soundstreams. The SDL sound backend supports both event-sounds and soundstreams, using Gnash's internal ADPCM, and optionally MP3 support, using either FFMPEG or LIBMAD. When it receives sound data it is stored without being decoded, unless it is ADPCM, which is decoded in the parser. When playing, backend relies on a function callback for retrieving output sound, which is decoded and re-sampled if needed, and all sound output is mixed together. The current SDL sound backend was made since Gnash needed a working sound backend as soon as possible, and since the gstreamer backend at the time suffered from bugs and/or lack of features in gstreamer. The result was the most complete and best sound handler so far. The advantages of the SDL sound handler is speed, and ease of use, while its only real disadvantage is that it has to be compiled with MP3 support, which some Linux distributions will probably not like...

The Gstreamer backend

The Gstreamer backend, though not complete, supports both soundstreams and event-sounds. When receiving sound data it stores it compressed, unless if it's ADPCM event-sounds, which it decodes by the parser. When the playback starts, the backend setup a Gstreamer bin containing a decoder (and other things needed) and places it in a Gstreamer pipeline, which plays the audio. All the sound data is not passed at once, but in small chunks, and via callbacks the pipeline gets fed. The advantages of the Gstreamer backend is that it supports both kind of sounds, it avoids all the legal MP3-stuff, and it should be relatively easy to add VORBIS support. The drawbacks are that it has longer "reply delay" when starting the playback of a sound, and it suffers under some bugs in Gstreamer that are yet to be fixed.

Future audio backends

It would probably be desirable to make more backends in the future, either because other and better backend systems are brought to our attention, or perhaps because an internal sound handling is better suited for embedded platform with limited software installed.

Detailed description of the Gstreamer backend

Gstreamer uses pipelines, bins and elements. Pipelines are the main bin, where all other bins or elements are places. Visually the audio pipeline in Gnash looks like this:

	 ___
	|Bin|_
	|___| \
	 ___   \ _____       ____________
	|Bin|___|Adder|_____|Audio output|
	|___|   |_____|     |____________|
	 ___   /
	|Bin|_/
	|___|

      

There is one bin for each sound which is being played. If a sound is played more the once at the same time, multiple bins will be made. The bins contains:


	|source|---|capsfilter|---|decoder|---|aconverter|---|aresampler|---|volume|

      

In the source element we place parts of the undecoded sound data, and when playing the pipeline will pull the data from the element. Via callbacks it is refilled if needed. In the capsfilter the data is labeled with the format of the data. The decoder (surprise!) decodes the data. The audioconverter converts the now raw sound data into a format accepted by the adder, all input to the adder must in the same format. The audio re-sampler re-samples the raw sound data into a sample accepted by the adder, all input to the adder must in the same sample rate. The volume element makes it possible to control the volume of each sound.

When a sound is done being played it emits a End-Of-Stream-signal (EOS), which is caught by an event-handler-callback, which then makes sure that the bin in question is removed from the pipeline. When a sound is told by Gnash to stop playback before it has ended playback, we do something (not yet finally implemented), which makes the bin emit an EOS, and the event-handler-callback will remove the sound from the pipeline. Unfortunately Gstreamer currently has a bug which causes the entire pipeline to stop playing when unlinking an element from the pipeline; so far no fix is known.

Gstreamer also contains a bug concerning linking multiple elements to the adder in rapid succession, which causes to adder to "die" and stop the playback.

Testing

Instructions on running tests can be found in the section on building Gnash.

Testing Tools

Currently Gnash uses three other tools to help with testing. Two of these are free compilers for the Flash format. This lets us write simple test cases for Gnash to test specific features, and to see how the features operate.

The primary compiler used at this time is Ming. Since release 0.3, Ming includes a command-line compiler, makeswf. This allows test case development to be done entirely with free tools.

The other tools are optional. DejaGnu is used to run multiple test cases in an automated manner. DejaGnu is used by many other GNU projects like GCC and Samba.

Test Cases

ActionScript test cases are located under testsuite/actionscript.all/; these are organized in one file for the ActionScript class. Other Ming-generated tests are under testsuite/ming-misc.all/; these are typically used to test specific tag types. Full movies are located in testsuite/movies.all/ and sample movies are found in testsuite/samples/. Other directories in testsuite/ are (or shall be) used for other kind of tests.

Writing ActionScript Tests

Writing ActionScript tests is very simple. The makeswf compiler makes use of the C preprocessor, thus allowing the inclusion of definitions for macros and external files. We use these feature to provide common utilities for test units.

Each test unit sets an rcsid variable, includes the check.as file and performs some checks using the provided macros. Here is an example:


	  // This variable will be used by check.as
	  // to show testcase info as part of the test runs.
	  rcsid="Name and version of this testcase, usually the RCS id";
	  
	  #include "check.as"
	  
	  // Test object creation
	  check(new Object() instanceOf Object);
	  
	  // Test parseInt
	  check(isNaN(parseInt('none')));

	  // Test assignment
	  var a = 1;
	  check_equals(a, 1);
	  
	  // .. your tests here ...
	

The check(expr) macro will trace PASSED or FAILED together with the expression being evaluated and the line number of the check. This is the format expected by DejaGnu.

The check_equals(obtained, expected) macro uses equality operator == to check for equality. When possible, use of the check_equals() macro is preferred over check() because it shows what the actual result was in case of a failure.

Additionally, the check.as file provides a transparent way to send results to a TextField rather then using trace. This is very useful when you use a flash player without tracing support.

Test units are built by running make TestName-v#.swf. This will use TestName.as as source and the value of # as target version. Allowed target version are from 5 to 8 (inclusive).

Note that if you get a syntax error from the compiler, the line number will refer to the pre-processed file. This file is called TestName.as.pp or TestName-v#.swf.frame#.pp (depending on Ming version) and it's not thrown away by makeswf to make debugging easier.

Sometimes an expression is only supported by a specific SWF version, or it's evaluated differently by different SWF versions. For this purpose the framework provides an OUTPUT_VERSION macro that you can use to switch code based on output version. For example:


	  #if OUTPUT_VERSION >= 7
	  check(_root.getSWFVersion == OUTPUT_VERSION);
	  #endif
	  
	

Writing Ming-based self-contained SWF tests

Ming-based test cases are located in testsuite/misc-ming.all and contain a test generator and a test runner. The test generator (usually a C program) is used to produce the SWF file, while the test runner (a C++ program) will run it using a MovieTester class. Note that only the test generator needs Ming, not the test runner, so if Ming isn't installed on the user's host, the test cases can still be run as long as SWF has been distributed.

Producing tests using Ming has the advantage that you can easily see and modify the full source code for the SWF movie, and you can use some facilities provided by the Gnash testing framework to easily run tests.

For generic Ming API documentation, see http://www.libming.org.

Using Ming-based test generators facilities

Ming-based test generator facilities, which might be moved into a loadable SWF in the future, can be currently used by your test generator by including the ming_utils.h file and calling the appropriate functions.

The most useful facility provided for Ming-based SWF test generators is a Dejagnu-like TestState ActionScript class. In order to use this facility you must call 'add_dejagnu_functions()' right after Movie creation. The function takes an SWFMovie object and some parameters specifying depth and location of the "visual" trace textfield; it instantiates a global 'TestState' ActionScript object to keep track of test's state.

You will not need to directly invoke the TestState object created by the 'add_dejagnu_functions()' routine, rather you will be using C macros hiding its complexity:


	check(SWFMovie mo, const char* expr)

		Evaluate an ActionScript expression.

	xcheck(SWFMovie mo, const char* expr)

		Evaluate an ActionScript expression.
		A failure is expected
		(for cases where the call exposes a known bug).

	check_equals(SWFMovie mo, const char* obtained, const char* expected)

		Evaluate an ActionScript expression against an expected output.

	xcheck_equals(SWFMovie mo, const char* obtained, const char* expected)

		Evaluate an ActionScript expression against an expected output.
		A failure is expected (for cases where the call exposes a known bug).

	print_tests_summary(SWFMovie mo)

                This will print a summary of tests run, and should be
		called as the last step in your SWF generator.

	

Test cases generated using Ming and the provided facilities will be self-contained, which means they can be used as tests by simply running them with whatever Player you might have. Any 'check' or 'check_equals' result will be both traced and printed in a textfield. You can use 'gprocessor -v' to have Gnash use them as tests.

See section Writing Test Runners for information about writing SWF test runners.

Writing self-contained SWF tests with other compilers

If you want/need to use a different compiler for your test cases (there's plenty of open source tools for generating SWF out there), you can still make use of a loadable SWF utility provided as part of the Gnash testsuite to let your test consistent with the rest of the suite.

The loadable module is called Dejagnu.swf and is built during make check under testsuite/misc-ming.all. In order to use it you will need to load it into your SWF. We currently load it with an IMPORT tag for our ActionScript based test cases, but you can probably also use loadMovie or whatever works in the target SWF you're generating. Just make sure that the module is initialized before using it. You can check this by inspecting the dejagnu_module_initialized variable, which will be set to 'true' when all initialization actions contained in the Dejagnu.swf file are executed.

Once the module is loaded you will be able to invoke the following functions, all registered against the _root sprite (effects of _lockroot untested):


	check(expression, [message]);

		Evaluate the expression.
		Trace result (PASSED: expression / FAILED: expression).
		If fails, *visually* trace the failure.
		If second argument is given, it will be used instead of
		'expression' for printing results.

	check_equals(obtained, expected)

		Evaluate an expression against an expected output.
		Trace result (PASSED: obtained == expected / FAILED: expected X, obtained Y)
		If fails, *visually* trace the failure.

	xcheck(expression, [message]);

		Evaluate the expression.
		Trace result (XPASSED: expression / XFAILED: expression).
		If fails, *visually* trace the failure.
		If second argument is given, it will be used instead of
		'expression' for printing results.

	xcheck_equals(obtained, expected)

		Evaluate an expression against an expected output.
		Trace result (XPASSED: obtained == expected / XFAILED: expected X, obtained Y)
		If fails, *visually* trace the failure.

	note(string)

		Print string, both as debugging and *visual* trace.

	totals()

                Print a summary of tests run, both as debugging and *visual* traces.

	

Visual traces are lines of text pushed to a textarea defined by the Dejagnu.swf module. The textarea is initially placed at 0, 50 and is 600x800 in size. You can resize/move the clip after loading it. Also, you can completely make the clip invisible if that bothers you. The important thing is the *debuggin* trace (call to the trace function). The latter will be used by the testing framework.

See section Writing Test Runners for information about writing a test runners for your self-contained tests.

Writing Test Runners

Test runners are executables that run one or more tests, writing results in Dejagnu form to standard output.

The Dejagnu form uses a standard set of labels when printing test results. These are:

Label

Meaning

PASSED

The test succeeded.

FAILED

The test failed.

XPASSED

The test succeeded, but was expected to fail.

XFAILED

The test failed, and was expected to fail.

UNRESOLVED

The results of the test could not be automatically parsed.

UNTESTED

This test case is not complete.

UNSUPPORTED

The test case relies on a conditional feature which is not present in your environment.

The following labels may also appear:

Label

Meaning

ERROR

There was a serious error in running the test.

WARNING

There may have been a problem with running the test.

NOTE

There was some additional information given about the test.

Using the generic test runner for self-contained SWF tests

The simplest test runner is one that simply invokes Gnash in verbose mode against a self-contained SWF test movie. Self-contained SWF test movies are the ones that print the PASSED/FAILED etc. lines using ActionScript (traces). By invoking Gnash in verbose mode this movie will behave as a compliant "Test Runner".

A generator for simple test runners can be found in testsuite/generic-testrunner.sh. The script can be invoked by passing it $(top_builddir) as the first argument and the name of the SWF file (without the path) as the second argument. This will create a specific runner for your test in the current build directory. A simple Makefile.am rule for doing this follows:

MyTest-Runner: $(srcdir)/../generic-testrunner.sh MyTest.swf
        sh $(srcdir)/../generic-testrunner.sh $(top_builddir) MyTest.swf > $@
        chmod +x $@
	

By default, the generated test runner will play the movie up to the last frame. If you want the movie to be played more then once (maybe because you're exactly testing loop features) you can use the -r switch to the generic-testrunner.sh call. The following will create a runner playing the movie twice:

MyTest-Runner: $(srcdir)/../generic-testrunner.sh MyTest.swf
        sh $(srcdir)/../generic-testrunner.sh -r2 $(top_builddir) MyTest.swf > $@
        chmod +x $@
	

Writing Movie testers

There are some parts of Gnash that can NOT be tested by only using ActionScript tests. Examples include: frame advancements, actual actions execution, gui events and so on.

In this case you might want to use the MovieTester class to implement a C++ test runner. Be aware that you can *mix* tests in the MovieTester-based class with *self-contained* tests in the SWF file as long as you activate verbosity for the debug logfile. This is done, for example, for the DefineEditTextVariableNameTest.swf file. The corresponding test runner (DefineEditTextVariableNameTest-Runner) is a C++ runner based on MovieTester class. If you run the runner you see two kinds of test results: the ones coming from the ActionScript engine, and the ones coming from the test runner. You can distinguish between the two because the former contains an additional timestamp and the latter does not. Also, you'll see two final summaries for the two test sets. The 'make check' rule, which uses the testsuite/simple.exp output parser as its work-horse, will count test results from both test sets.

Movie testers are executables which load an SWF, generate events (both user or system) on it, and check its state using a standard interface.

To help this process a MovieTester class is defined in the testsuite/MovieTester.{h,cpp} files; see Doxygen documentation for more information.

Note that you do NOT need access to the SWF source code in order to implement a Movie tester for it. Some knowledge about the expected behavior suffices.

Gnash Extensions

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.

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.

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.

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.

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..

Creating A New Extension

Each new extension should live in it's own directory. The extensions included in Gnash are all in the gnash/extensions directory. Creating an extension requires a Makefile.am,

If you are adding this extension to the Gnash source tree itself, then you need to make two changes to add the new extension.

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.

The other change is to add it to the AC_OUTPUT list in configure.ac so the new directory will be configured along with the rest of Gnash.

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 check_PROGRAMS variable so that "make check" works.

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.

Crafting an Extension

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.

The first function is commonly called attachInterface, 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 set_member() to set a C function pointer to the string value used in the Flash movie.

	// setup so DummyClass.func1() and DummyClass.func2() work from Flash.
	static void
	attachInterface(as_object *obj)
	{
            obj->set_member("func1", &ext_func1);
            obj->set_member("func2", &ext_func2);
	}
      

The second function is commonly called getInterface(), and this returns a smart pointer to the new object. Gnash uses smart pointers for all ActionScript class definitions. (and many other things)

	static as_object*
	getInterface()
	{
	    static boost::intrusive_ptr<as_object> o;
	    if (o == NULL) {
	        o = new as_object();
	    }
	    return o.get();
	}
      

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 DummyExt, and has two methods, func1 and func2.

	static void
	dummyext_ctor(const fn_call& fn)
	{
	    DummyExt *obj = new DummyExt();

	    attachInterface(obj);
	    fn.result->set_as_object(obj); // will keep alive
	}
      

Allocate the new object and return a smart pointer.

	std::auto_ptr<as_object>
	init_dummyext_instance()
	{
	    return std::auto_ptr<as_object>(new DummyExt());
	}
      

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 dummyext, which also matches the file name of the extension. Gnash uses the name of the extension file itself when looking for the init function.

        extern "C" {
	    void
	    dummyext_class_init(as_object &obj)
	    {
	        static boost::intrusive_ptr<builtin_function> cl;
	        if (cl == NULL) {
	            cl = new builtin_function(&dummyext_ctor, getInterface());
	            attachInterface(cl.get());
	        }
	
	        VM& vm = VM::get();
		std::string name = "DummyExt";
		if ( vm.getSWFVersion() < 7 ) {
	            boost::to_lower(name, vm.getLocale());
		}
		obj.init_member(name, cl.get());
	    }
        } // end of extern C
      

The callbacks are all C functions. Like all the other code that implements ActionScript, parameters to the function are passed in using the fn_call data structure. The return code, if any, is also returned using this data structure. this_ptr is the object that the method is a member of.

	// Creates a new button with the label as the text.
	void func1(const fn_call& fn)
	{
	    DummyExt *ptr = dynamic_cast<DummyExt *>(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);
	    }
	}
      

Debugging An Extension

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 after the extension has been loaded into Gnash's VM. The easy solution is to use the Gnash debugger.

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 c (for continue) command to the Gnash console.

      // Get the debugger instance
      static Debugger& debugger = Debugger::getDefaultInstance();

      // Enable the debugger
      debugger.enabled(true);
      // Stop and drop into a console
      debugger.console();
    

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 ^C to drop into the GDB command console.

      bool stall = true;
      while (stall) {
          sleep 1;
      }
    

Once you have set the breakpoints you want, reset the value of the stall variable to break out of the loop, and the Flash movie will then continue playing.

      (gdb) set variable stall = false;
      continue
    

Included Extensions

Gnash has sme extensions included in the distribution. This is mostly because they were written by the Gnash team. Extensions can be external to gnash, Gnash needs no compiled in knowledge to load an extension file.

Gtk Extension

The GTK ActionScript class follows the same API as Gtk2, even down to the same arguments to the same function names. This means you're actually programming GTK,you're just using ActionScript instead of python, perl, or C. This extension makes it possible to write Flash movies that use the Gtk2 widgets for user interface components.

window_new

Create a new window.

signal_connect

Add an event handler to a widget.

container_set_border_width

Set the width of the window border.

button_new_with_label

Create a new button and give it the specified label.

signal_connect_swapped

Swap signals. Commonly used for delete event handling.

container_add

Add one widget to another as a child.

widget_show

Display the widget on the screen.

main

Start the main GTK event loop. This function does not return.

File I/O Extension

Flash movies are traditionally forbidden from accessing the filesystem, but this may be necessary for some embedded applications. Especially in the case of a user console, currently there is no way to get input into a Flash movie but through a TextField.

fopen

Open the file.

fread

Read a series of bytes from the opened file.

fgetc

Read a single byte from the opened file.

fgets

Read a single line until a Cariage Return from the opened file.

gets

Read a single line from the standard in.

getchar

Read a single character from the standard in.

fwrite

fputc

Write a single character to the opened file.

fputs

Write a single line to the opened file.

puts

Write a single line to standard out..

putchar

Write a single character to standard out..

fflush

Flush the current opened file to disk.

fseek

Seek to a location within the opened file.

ftell

Report the current position within the opened file.

fclose

Close the opened file.

MySQL Extension

The MySQL ActionScript class follows the same API as MySQL, even down to the same arguments to the same function names. This enables a Flash movie to have direct access to a MySQL database. Traditionally Flash movies have had no datatbase support, they either hsad to use arrays, or use XML to communicate to an application specific external database daemon.

connect

Connect to a MySQL database.

qetData

Get data from the database.

disconnect

Disconnect from a MySQL database.

query

Execute an SQL query to the database.

fetch_row

Fetch a row from the query results.

num_fields

free_result

Free the results of a query.

store_results

Store the results of a query.

Appendix

Code Style

I know any discussion of coding styles leads to strong opinions, so I'll state simply I follow the GNU Coding Standards. Where there is some flexibility as to the location of braces, I prefer mine on the end of a line when using an if, while, or do statement. I find this more compact style easier to read and parse by eye. I'm also a big fan of always using braces around if statements, even if they're one liners.

Here's my tweaked style settings for Emacs, the one true editor to rule them all.

      (defconst my-style
          '((c-tab-always-indent   . t)
           (c-auto-newline	   . t)
           (c-hanging-braces-alist . (
				   (brace-list-intro)
				   (namespace-open)
				   (inline-open)
				   (block-open)
				   (brace-list-open)
				   (brace-list-close)
				   (brace-entry-open)
				   (brace-else-brace)
				   (brace-elseif-brace)
				   (class-open after)
				   (class-close)
				   (defun-open after)
				   (defun-close)
				   (extern-lang-open)
				   (inexpr-class-open)
				   (statement-open)
				   (substatement-open)
				   (inexpr-class-close)))
            (c-hanging-colons-alist . ((member-init-intro before)
                                   (inher-intro)
                                   (case-label after)
                                   (label after)
                                   (access-label after)))
            (c-offsets-alist	. (
				   (innamespace . 0)
                                   (case-label  . 2)
				   ))
            (c-cleanup-list	. (
				   (scope-operator)
				   (empty-defun-braces)
				   (brace-else-brace)
				   (brace-elseif-brace)
				   (defun-close-semi)
				   (list-close-comma)
				   )
				)
    ;; no automatic newlines after ';' if following line non-blank or inside
    ;; one-line inline methods
    (add-to-list 'c-hanging-semi&comma-criteria
		 'c-semi&comma-no-newlines-before-nonblanks)
    (add-to-list 'c-hanging-semi&comma-criteria
		 'c-semi&comma-no-newlines-for-oneline-inliners)
;    (knr-argdecl-intro . -)
    (c-echo-syntactic-information-p . t)
    )
  "My GNU Programming Style")
    

Another coding consideration: comments are good! Over commenting isn't good. Here is an over commented example:

	counter++;		// increment counter
      

Gnash also uses Doxygen style comments. These are processed by Doxygen when building a cross reference of all the classes, and is a good way to help push internals documentation from the depths of the code into documentation where it can be seen by others.

Doxygen style comments for C++ code involves simply using three slashes /// instead of the standard two slashes // used for C++ comments. Here's a short comment block for the XML::cloneNode() method:

	/// \brief copy a node
	///
	/// Method; constructs and returns a new XML node of the same type,
	/// name, value, and attributes as the specified XML object. If deep
	/// is set to true, all child nodes are recursively cloned, resulting
	/// in an exact copy of the original object's document tree.
	XMLNode &
	XML::cloneNode(XMLNode &newnode, bool deep) {
	...
	}
      

The \brief keyword means that the text becomes associated when listing all the classes on the generated web pages. The text after the blank link becomes the detailed description which appears on the generated web page for that class and method.

RTMP Protocol

This document is based mostly on my own reverse engineering of the RTMP protocol and AMF format. tcpdump and ethereal are your friend. Some additional info that got me started was from the Red5 project. Red5 is the only other open source Flash server. So some details are still vague, but as the implementation appears to work, we'll figure out what they are later.

The Real Time Messaging Protocol was created by MacroMedia (now Adobe) for delivering Flash objects and video over a network connection. Currently the only servers which support this format are the MacroMedia Media sever, and the Open Source Red5 project.

This is a simple protocol, optimized for poor bandwidth connections. It can support up to 64 concurrent streams over the same network connection. Part of each AMF packet header contains the index number of the stream. A single RTMP message can contain multiple AMF packets.

An RTMP connection uses Tcp/ip port 1935. It is also possible to tunnel RTMP over an HTTP connection using port 80. Each AMF packet is 128 bytes long except for streaming audio, which has 64 byte packets.

The basics of the RTMP protocol are as follows. All communications are initiated by the client.

The client starts the RTMP connection by sending a single byte with a value of 0x3. This byte is followed by a data block of 1536 bytes. The format if this data block is unknown, but it appears to not be actually used by the protocol except as a handshake.

The server receives this packet, stores the 1536 byte data block, and then send a single byte with the value of 0x3, followed by two 1536 data blocks. The second data block is the full contents of the original data block as sent by the client.

The client receives the 1536 byte data block, and if they match, the connection is established. After the handshake process is done, there are three other messages that the client sends to the sever to start the data flowing.

The first AMF packet sent to the server contains the connect packet. This doesn't appear to do much but notify the server the client is happy with the handshake, and ready to start reading packets.

The second packet is the NetConnection object from the client. This ActionScript class is used by the Flash movie to create the network connection to the server.

The third packet is the NetStream object from the client. This is the ActionScript class used to specify the file to be streamed by the server.

The RTMP packet for our example looks like this:

      030000190000c91400000000020007connect00?f0000000000000030003app0200#
      software/gnash/tests/1153948634.flv0008flashVer02000cLNX 6,0,82,0 0006
      swfUrl02001dfile:///file|%2Ftmp%2Fout.swfc30005tcUrl\002\0004
      rtmp://localhost/software/gnash/tests/1153948634.flv\000\000\t
      \002\000\005userx
    

We'll take this apart in a bit, but you can see how all three AMF packets are in the same message. The message is received in several 128 byte blocks, with the last one being less than that. The total size of the RTMP message is in the header, so the reader can tell if the entire message was read or not.

The RTMP header is first, followed by the connect message as an ASCII string as the message body. The following AMF packet is the NetConnection one, which specifies that this is coming from a Flash application. This also contains the file path the server can use to find the file to stream. This is then followed by the version number, which I assume is the version of the Flash player, so the server knows what it is talking to.

The third packet is the one from NetStream, which specifies the URL used for the movie, followed by the user name for a semblance of security.

For the next level of detail, we'll explain the format of AMF. AMF is used by the RTMP protocol to transfer data. Each Flash object is encapsulated in an AMF packet, including streaming audio or video.

The first byte of the RTMP header determines two things about the rest of the message. The first 2 bits of this byte signify the total size of the RTMP header. The RTMP header is of a variable size, so this is important.

00

This specifies the header contains 12 bytes, including this one.

01

This specifies the header contains 8 bytes, including this one.

02

This specifies the header contains 4 bytes, including this one.

03

This specifies the header contains 1 byte, so this is the complete header.

The other 6 bits in this byte represent the AMF index. As a single RTMP connection can support multiple data streams, this signifies which stream this packet is for. Once an AMF object is fully received by the client, the AMF index may be reused.

For messages with headers of at least 4 bytes, the next 3 bytes are used by audio and video data packets, but at this time the meaning of this field is unknown.

For messages with a 8 byte or larger header, the next 3 bytes determine the size of the RTMP message being transmitted. Messages with a 1 byte or 4 byte header use a standard size, 128 bytes for video, and 64 bytes for audio.

For messages with an 8 byte or larger header, the next byte is the type of the AMF object.

0x3

This specifies the content type of the RTMP packet is the number of bytes read. This is used to start the RTMP connection.

0x4

This specifies the content type of the RTMP message is a ping packet.

0x5

This specifies the content type of the RTMP message is server response of some type.

0x6

This specifies the content type of the RTMP packet is client request of some type.

0x8

This specifies the content type of the RTMP packet is an audio message.

0x9

This specifies the content type of the RTMP message is a video packet.

0x12

This specifies the content type of the RTMP message is notify.

0x13

This specifies the content type of the RTMP message is shared object.

0x14

This specifies the content type of the RTMP message is remote procedure call. This invokes the method of a Flash class remotely.

There are two sets of data types to consider. One set is used by the to specify the content type of the AMF object, the other is an ActionScript data type tag used to denote which type of object is being transferred.

The values of the initial type byte are:

0x0

This specifies the data in the AMF packet is a numeric value. All numeric values in Flash are 64 bit, big-endian.

0x1

This specifies the data in the AMF packet is a boolean value.

0x2

This specifies the data in the AMF packet is an ASCII string.

0x3

This specifies the data in the AMF packet is a Flash object. The Flash object data type field further along in the message specifies which type of ActionScript object it is.

0x4

This specifies the data in the AMF packet is a Flash movie, ie. another Flash movie.

0x5

This specifies the data in the AMF packet is a NULL value. NULL is often used as the return code from calling Flash functions.

0x6

This specifies the data in the AMF packet is a undefined. This is also used as the return code from calling Flash functions.

0x7

This specifies the data in the AMF packet is a reference.

0x8

This specifies the data in the AMF packet is a ECMA array.

0x9

This specifies the data in the AMF packet is the end of an object definition. As an object is transmitted with multiple AMF packets, this lets the server know when the end of the object is reached.

0xa

This specifies the data in the AMF packet is a Strict array.

0xb

This specifies the data in the AMF packet is a date.

0xc

This specifies the data in the AMF packet is a multi-byte string. Multi-byte strings are used for international language support to represent non ASCII fonts.

0xd

This specifies the data in the AMF packet is a an unsupported feature.

0xe

This specifies the data in the AMF packet is a record set.

0xf

This specifies the data in the AMF packet is a AML object. XML objects are then parsed by the XML ActionScript class.

0x10

This specifies the data in the AMF packet is a typed object.

For messages with a 12 byte header, the last 4 bytes are the routing of the message. If the destination is the server, this value is the NetStream object source. If the destination is the client, this is the NetStream object for this RTMP message. A value of 0x00000000 appears to be reserved for the NetConnection object.

Multiple AMF streams can be contained in a single RTMP messages, so it's important to check the index of each AMF packet.

An example RTMP header might look like this. (spaces added between fields for clarity) All the numbers are in hex.

      03 000019 0000c9 14 000000000
    

03

The first two bits of this byte are the size of the header, which in this example is 00, for a 12 byte header. The next 6 bits is the AMF stream index number, which in this example is 0x3.

000019

These 3 bytes currently have an unknown purpose.

000c9

Since this example has a 12 byte header, this is the size of the RTMP message, in this case 201 bytes.

14

This is the content type of the RTMP message, which in this case is to invoke a remote function call. (which we later see is the connect function).

00000000

The source is the NetConnection object used to start this connection.

AMF Format

The AMF format is used in the LocalConnection, SharedObject, NetConnection, and NetStream ActionScript classes. This is a means of binary data interchange between Flash movies, or between a Flash player and a Flash server.

Like the RTMP messages, an AMF packet header can be of a variable size. The size is either the same as the initial header of the RTMP message, or a 1 byte header, which is commonly used for streaming audio or video data.

The body of an AMF packet may look something like this example. The spaces have been added for clarity.

      02  0007 636f6e6e656374
    

02

This is a single byte header. The value of the first 2 bits is 0x3, and the AMF index is also 0x3.

0007

This is the length in bytes of the string.

63 6f 6e 6e 65 63 74

This is the string. Note that there is no null terminator since the length is specified.

Authors

Gnash is maintained by Rob Savoye . Other active developers are: Sandro Santilli, Bastiaan Jacques, Vitaly Alexeev, and Tomas Groth. Please send all comments and suggestions to . Please use this link to submit a patch or this link to file a bug report. I am available for consulting on a variety of renewable energy and open source technologies. More details at http://www.senecass.com

The primary author of GameSWF (which provided the initial code for Gnash) is Thatcher Ulrich . Other individuals who contributed code are: Mike Shaver, Thierry Berger-Perrin, Ignacio CastaƱo, Willem Kokke, Vitaly Alexeev, Alexander Streit, and Rob Savoye.

A. GNU Free Documentation License

0. PREAMBLE

The purpose of this License is to make a manual, textbook, or other written document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or non-commercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.

This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.

We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.

1. APPLICABILITY AND DEFINITIONS

This License applies to any manual or other work that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you".

A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.

A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (For example, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.

The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License.

The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License.

A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, whose contents can be viewed and edited directly and straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup has been designed to thwart or discourage subsequent modification by readers is not Transparent. A copy that is not "Transparent" is called "Opaque".

Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML designed for human modification. Opaque formats include PostScript, PDF, proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML produced by some word processors for output purposes only.

The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text.

2. VERBATIM COPYING

You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.

You may also lend copies, under the same conditions stated above, and you may publicly display copies.

3. COPYING IN QUANTITY

If you publish printed copies of the Document numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.

If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.

If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a publicly-accessible computer-network location containing a complete Transparent copy of the Document, free of added material, which the general network-using public has access to download anonymously at no charge using public-standard network protocols. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.

It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.

4. MODIFICATIONS

You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:

  • A.  Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.

  • B.  List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has less than five).

  • C.  State on the Title Page the name of the publisher of the Modified Version, as the publisher.

  • D.  Preserve all the copyright notices of the Document.

  • E.  Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.

  • F.  Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.

  • G.  Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice.

  • H.  Include an unaltered copy of this License.

  • I.  Preserve the section entitled "History", and its title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.

  • J.  Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.

  • K.  In any section entitled "Acknowledgements" or "Dedications", preserve the section's title, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.

  • L.  Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.

  • M.  Delete any section entitled "Endorsements". Such a section may not be included in the Modified Version.

  • N.  Do not retitle any existing section as "Endorsements" or to conflict in title with any Invariant Section.

If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles.

You may add a section entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.

You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.

The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version .

5. COMBINING DOCUMENTS

You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice.

The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.

In the combination, you must combine any sections entitled "History" in the various original documents, forming one section entitled "History"; likewise combine any sections entitled "Acknowledgements", and any sections entitled "Dedications". You must delete all sections entitled "Endorsements."

6. COLLECTIONS OF DOCUMENTS

You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.

You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.

7. AGGREGATION WITH INDEPENDENT WORKS

A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, does not as a whole count as a Modified Version of the Document, provided no compilation copyright is claimed for the compilation. Such a compilation is called an "aggregate", and this License does not apply to the other self-contained works thus compiled with the Document , on account of their being thus compiled, if they are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one quarter of the entire aggregate, the Document's Cover Texts may be placed on covers that surround only the Document within the aggregate. Otherwise they must appear on covers around the whole aggregate.

8. TRANSLATION

Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License provided that you also include the original English version of this License. In case of a disagreement between the translation and the original English version of this License, the original English version will prevail.

9. TERMINATION

You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

10. FUTURE REVISIONS OF THIS LICENSE

The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.

Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation.

Addendum

To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:

Copyright YEAR YOUR NAME.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. A copy of the license is included in the section entitled "GNU Free Documentation License".

If you have no Invariant Sections, write "with no Invariant Sections" instead of saying which ones are invariant. If you have no Front-Cover Texts, write "no Front-Cover Texts" instead of "Front-Cover Texts being LIST"; likewise for Back-Cover Texts.

If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.