doc/src/examples/context2d.qdoc
branchRCL_3
changeset 7 3f74d0d4af4c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/src/examples/context2d.qdoc	Thu Apr 08 14:19:33 2010 +0300
@@ -0,0 +1,353 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+    \example script/context2d
+    \title Context2D Example
+
+    This Qt Script example is an implementation of the Context2D API.
+
+    \image context2d-example.png
+
+    Context2D is part of the specification for the HTML \c{<canvas>}
+    element. It can be used to draw graphics via scripting. A good
+    resource for learning more about the HTML \c{<canvas>} element is
+    the \l{http://developer.mozilla.org/en/docs/HTML:Canvas}{Mozilla Developer Center}.
+
+    \section1 Using The HTML Canvas Element in a Web Browser
+
+    First, let's look at how the \c{<canvas>} element is typically
+    used in a web browser. The following HTML snippet defines a
+    canvas of size 400x400 pixels with id \c{mycanvas}:
+
+    \code
+    <canvas width="400" height="400" id="mycanvas">Fallback content goes here.</canvas>
+    \endcode
+
+    To draw on the canvas, we must first obtain a reference to the
+    DOM element corresponding to the \c{<canvas>} tag and then call
+    the element's getContext() function. The resulting object
+    implements the Context2D API that we use to draw.
+
+    \code
+    <script>
+    var canvas = document.getElementById("mycanvas");
+    var ctx = canvas.getContext("2d");
+
+    // Draw a face
+    ctx.beginPath();
+    ctx.arc(75,75,50,0,Math.PI*2,true); // Outer circle
+    ctx.moveTo(110,75);
+    ctx.arc(75,75,35,0,Math.PI,false);   // Mouth
+    ctx.moveTo(65,65);
+    ctx.arc(60,65,5,0,Math.PI*2,true);  // Left eye
+    ctx.moveTo(95,65);
+    ctx.arc(90,65,5,0,Math.PI*2,true);  // Right eye
+    ctx.stroke();
+    </script>
+    \endcode
+
+    When the page is rendered by a browser that supports the
+    \c{<canvas>} tag, this would be the result:
+
+    \image context2d-example-smileysmile.png
+
+    \section1 Using Qt Script to script a Canvas
+
+    The goal of this example is to be able to evaluate scripts
+    that use the Context2D API, and render the results. Basic
+    interaction (mouse, keyboard) should also be supported.
+    In other words, we want to present scripts with an execution
+    environment that very much resembles that of a web browser. Of
+    course, our environment is only a small subset of what a browser
+    provides; i.e. we don't provide a full DOM API, only what is
+    needed to run "self-contained" Context2D scripts (i.e. scripts
+    that don't depend on other parts of the DOM document).
+
+    Our "Context2D-browser" is set up through the following steps:
+    \list
+    \o Create an Environment.
+    \o Create a Context2D, and a QContext2DCanvas widget to render it.
+    \o Add the canvas object to the environment; this will enable
+       scripts to obtain a reference to it.
+    \o Evaluate scripts in the environment.
+    \endlist
+
+    Once a script has been evaluated, the application handles any
+    timer events and input events that occur subsequently
+    (i.e. forwards events to their associated script targets).
+
+    \section1 The Context2D Class
+
+    The "heart" of this example is the Context2D C++ class that implements
+    the drawing API. Its interface is defined in terms of properties
+    and slots. Note that this class isn't tied to Qt Script in any
+    way.
+
+    \snippet examples/script/context2d/context2d.h 0
+
+    The properties define various aspects of the Context2D
+    configuration.
+    
+    \snippet examples/script/context2d/context2d.h 1
+
+    The slots define the operations that can be performed.
+    
+    \snippet examples/script/context2d/context2d.h 2
+
+    The changed() signal is emitted when the contents of the drawing
+    area has changed, so that clients associated with the Context2D
+    object (i.e. the canvas widget that renders it) are notified.
+
+    \section2 Implementation
+
+    Conveniently enough, the concepts, data structures and operations
+    of the Context2D API map more or less directly to Qt's painting
+    API. Conceptually, all we have to do is initialize a QPainter
+    according to the Context2D properties, and use functions like
+    QPainter::strokePath() to do the painting. Painting is done on a
+    QImage.
+
+    \snippet examples/script/context2d/context2d.cpp 0
+
+    The property accessors and most of the slots manipulate the
+    internal Context2D state in some way. For the \c{lineCap}
+    property, Context2D uses a string representation; we therefore
+    have to map it from/to a Qt::PenCapStyle. The \c{lineJoin}
+    property is handled in the same fashion. All the property setters
+    also set a \e{dirty flag} for the property; this is used to
+    decide which aspects of the QPainter that need to be updated
+    before doing the next painting operation.
+
+    \snippet examples/script/context2d/context2d.cpp 3
+
+    The implementation of the \c{fillStyle} property is interesting,
+    since the value can be either a string or a \c{CanvasGradient}.
+    We handle this by having the property be of type QVariant,
+    and check the actual type of the value to see how to handle the
+    write.
+
+    \snippet examples/script/context2d/context2d.cpp 1
+
+    Context2D does not have a concept of a paint event; painting
+    operations can happen at any time. We would like to be efficient,
+    and not have to call QPainter::begin() and QPainter::end() for
+    every painting operation, since typically many painting operations
+    will follow in quick succession. The implementations of the
+    painting operations use a helper function, beginPainting(), that
+    activates the QPainter if it isn't active already, and updates
+    the state of the QPainter (brush, pen, etc.) so that it reflects
+    the current Context2D state.
+
+    \snippet examples/script/context2d/context2d.cpp 2
+
+    The implementation of each painting operation ends by calling
+    scheduleChange(), which will post a zero-timer event if one is
+    not already pending. When the application returns to the event
+    loop later (presumably after all the drawing operations have
+    finished), the timer will trigger, QPainter::end() will be
+    called, and the changed() signal is emitted with the new
+    image as argument. The net effect is that there will typically
+    be only a single (QPainter::begin(), QPainter::end()) pair
+    executed for the full sequence of painting operations.
+
+    \section1 The Canvas Widget
+
+    \snippet examples/script/context2d/qcontext2dcanvas.h 0
+
+    The QContext2DCanvas class provides a widget that renders
+    the contents of a Context2D object. It also provides a
+    minimal scripting API, most notably the getContext() function.
+
+    \snippet examples/script/context2d/qcontext2dcanvas.cpp 3
+
+    The constructor connects to the changed() signal of the
+    Context2D object, so that the widget can update itself
+    when it needs to do so. Mouse tracking is enabled so that
+    mouse move events will be received even when no mouse
+    buttons are depressed.
+
+    \snippet examples/script/context2d/qcontext2dcanvas.cpp 0
+
+    The getContext() function asks the environment to wrap the
+    Context2D object; the resulting proxy object makes the
+    Context2D API available to scripts.
+
+    \snippet examples/script/context2d/qcontext2dcanvas.cpp 1
+
+    The paintEvent() function simply paints the contents that
+    was last received from the Context2D object.
+
+    \snippet examples/script/context2d/qcontext2dcanvas.cpp 2
+
+    The canvas widget reimplements mouse and key event handlers, and
+    forwards these events to the scripting environment. The
+    environment will take care of delivering the event to the proper
+    script target, if any.
+
+    \section1 The Environment
+
+    \snippet examples/script/context2d/environment.h 0
+
+    The Environment class provides a scripting environment where a
+    Canvas C++ object can be registered, looked up by ID (name),
+    and where scripts can be evaluated. The environment has a
+    \c{document} property, just like the scripting environment of a
+    web browser, so that scripts can call
+    \c{document.getElementById()} to obtain a reference to a canvas.
+
+    \snippet examples/script/context2d/environment.h 1
+
+    The Environment class provides the timer attributes of the DOM
+    Window Object interface. This enables us to support scripts that
+    do animation, for example.
+    
+    \snippet examples/script/context2d/environment.h 2
+
+    The scriptError() signal is emitted when evaluation of a script
+    causes a script exception. For example, if a mouse press handler
+    or timeout handler causes an exception, the environment's client(s)
+    will be notified of this and can report the error.
+
+    \snippet examples/script/context2d/environment.cpp 0
+
+    The constructor initializes the environment. First it creates
+    the QScriptEngine that will be used to evaluate scripts. It
+    creates the Document object that provides the getElementById()
+    function. Note that the QScriptEngine::ExcludeSuperClassContents
+    flag is specified to avoid the wrapper objects from exposing properties
+    and methods inherited from QObject. Next, the environment wraps
+    a pointer to \e{itself}; this is to prepare for setting this object
+    as the script engine's Global Object. The properties of the standard
+    Global Object are copied, so that these will also be available in
+    our custom Global Object. We also create two self-references to the
+    object; again, this is to provide a minimal level of compabilitity
+    with the scripting environment that web browsers provide.
+
+    \snippet examples/script/context2d/environment.cpp 5
+
+    The addCanvas() function adds the given canvas to the list of
+    registered canvas objects. The canvasByName() function looks up
+    a canvas by QObject::objectName(). This function is used to
+    implement the \c{document.getElementById()} script function.
+
+    \snippet examples/script/context2d/environment.cpp 1
+
+    The setInterval() and clearInterval() implementations use a QHash
+    to map from timer ID to the QScriptValue that holds the expression
+    to evaluate when the timer is triggered. A helper function,
+    maybeEmitScriptError(), is called after invoking the script handler;
+    it will emit the scriptError() signal if the script engine has an
+    uncaught exception.
+
+    \snippet examples/script/context2d/environment.cpp 2
+
+    The toWrapper() functions creates a QScriptValue that wraps the
+    given QObject. Note that the QScriptEngine::PreferExistingWrapperObject
+    flag is specified; this guarantees that a single, unique wrapper
+    object will be returned, even if toWrapper() is called several times
+    with the same argument. This is important, since it is possible that
+    a script can set new properties on the resulting wrapper object (e.g.
+    event handlers like \c{onmousedown}), and we want these to persist.
+
+    \snippet examples/script/context2d/environment.cpp 3
+
+    The handleEvent() function determines if there exists a handler
+    for the given event in the environment, and if so, invokes that
+    handler. Since the script expects a DOM event, the Qt C++ event
+    must be converted to a DOM event before it is passed to the
+    script. This mapping is relatively straightforward, but again,
+    we only implement a subset of the full DOM API; just enough to
+    get most scripts to work.
+
+    \snippet examples/script/context2d/environment.cpp 4
+
+    The newFakeDomEvent() function is a helper function that creates
+    a new script object and initializes it with default values for
+    the attributes defined in the DOM Event and DOM UIEvent
+    interfaces.
+
+    \snippet examples/script/context2d/environment.h 3
+
+    The Document class defines two slots that become available to
+    scripts: getElementById() and getElementsByTagName().
+    When the tag name is "canvas", getElementsByTagName() will
+    return a list of all canvas objects that are registered in
+    the environment.
+
+    \section1 The Application Window
+
+    \snippet examples/script/context2d/window.cpp 0
+
+    The Window constructor creates an Environment object and
+    connects to its scriptError() signal. It then creates a
+    Context2D object, and a QContext2DCanvas widget to hold it.
+    The canvas widget is given the name \c{tutorial}, and added to the
+    environment; scripts can access the canvas by e.g.
+    \c{document.getElementById('tutorial')}.
+
+    \snippet examples/script/context2d/window.cpp 1
+
+    The window contains a list widget that is populated with
+    available scripts (read from a \c{scripts/} folder).
+
+    \snippet examples/script/context2d/window.cpp 2
+
+    When an item is selected, the corresponding script is
+    evaluated in the environment.
+
+    \snippet examples/script/context2d/window.cpp 3
+
+    When the "Run in Debugger" button is clicked, the Qt Script debugger will
+    automatically be invoked when the first statement of the script is
+    reached. This enables the user to inspect the scripting environment and
+    control further execution of the script; e.g. he can single-step through
+    the script and/or set breakpoints. It is also possible to enter script
+    statements in the debugger's console widget, e.g. to perform custom
+    Context2D drawing operations, interactively.
+
+    \snippet examples/script/context2d/window.cpp 4
+
+    If the evaluation of a script causes an uncaught exception, the Qt Script
+    debugger will automatically be invoked; this enables the user to get an
+    idea of what went wrong.
+
+*/