gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r11777: Test and implement dynamic g


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r11777: Test and implement dynamic gradients correctly; the main changes are
Date: Wed, 20 Jan 2010 12:12:29 +0100
User-agent: Bazaar (2.0.2)

------------------------------------------------------------
revno: 11777 [merge]
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Wed 2010-01-20 12:12:29 +0100
message:
  Test and implement dynamic gradients correctly; the main changes are
  1) correcting the transformation matrix to convert AS matrix to the
  appropriate Gnash gradient matrix, and 2) using the right member names
  (a, b, c, d, tx, ty). And 3) lots of automated tests in the prettiest
  DrawingApiTest page yet.
  
  The new SWF8 functionality (focal gradients, interpolation mode selection) is
  still not implemented.
  
  Correct fill_style to actually create dynamic radial gradients (was probably
  a recent bug).
  
  Half-finished refactoring of TextFormat to create its many methods more
  generically, fixing some of the many new tests added in actionscript.all.
modified:
  backend/Renderer.h
  backend/Renderer_agg.cpp
  libcore/TextField.cpp
  libcore/asobj/flash/display/MovieClip_as.cpp
  libcore/asobj/flash/text/TextFormat_as.cpp
  libcore/asobj/flash/text/TextFormat_as.h
  libcore/fill_style.cpp
  libcore/fill_style.h
  testsuite/actionscript.all/TextFormat.as
  testsuite/misc-ming.all/DrawingApiTest.as
  testsuite/misc-ming.all/DrawingApiTestRunner.cpp
=== modified file 'backend/Renderer.h'
--- a/backend/Renderer.h        2010-01-14 12:03:17 +0000
+++ b/backend/Renderer.h        2010-01-19 09:59:10 +0000
@@ -462,8 +462,7 @@
     /// the nearest pixel is returned.
     /// The function returns false when the coordinates are outside the 
     /// main frame buffer.
-    virtual bool getPixel(rgba& /*color_return*/, int /*x*/, int /*y*/) const
-    {
+    virtual bool getPixel(rgba& /*color_return*/, int /*x*/, int /*y*/) const {
 
         log_debug("getPixel() not implemented for this renderer");
         abort();        
@@ -542,8 +541,7 @@
     /// @param width stage width in pixels
     ///
     /// @param height stage height in pixels
-    virtual bool initTestBuffer(unsigned /*width*/, unsigned /*height*/)
-    {
+    virtual bool initTestBuffer(unsigned /*width*/, unsigned /*height*/) {
         return false;
     }
 
@@ -554,9 +552,7 @@
     /// TODO: this should be a pure abstract function, just don't want
     ///     to scan ogl and cairo backend for an implementation *now*
     ///     but would be needed for automated testing... Quinn, can you help ?
-    ///
-    virtual unsigned int getBitsPerPixel() const
-    {
+    virtual unsigned int getBitsPerPixel() const {
         return 0;
     }
     
@@ -564,20 +560,14 @@
 
 protected:
 
-
-    /// Dummy, neutral color transformation (do not change!!)
-    const cxform m_neutral_cxform;
-
     /// Kept in parallel with movie_root's setting.
     Quality _quality;
 
-}; // class Renderer
-
-
+}; 
 
 } // namespace gnash
 
-#endif // RENDER_HANDLER_H
+#endif 
 
 
 // Local Variables:

=== modified file 'backend/Renderer_agg.cpp'
--- a/backend/Renderer_agg.cpp  2010-01-14 12:03:17 +0000
+++ b/backend/Renderer_agg.cpp  2010-01-19 09:59:10 +0000
@@ -898,7 +898,7 @@
 
     // prepare style handler
     agg_style_handler sh;
-    build_agg_styles(sh, m_single_fill_styles, mat, m_neutral_cxform);
+    build_agg_styles(sh, m_single_fill_styles, mat, cxform());
     
     draw_shape(-1, paths, agg_paths, sh, false);
     

=== modified file 'libcore/TextField.cpp'
--- a/libcore/TextField.cpp     2010-01-18 08:15:33 +0000
+++ b/libcore/TextField.cpp     2010-01-19 15:02:37 +0000
@@ -994,22 +994,22 @@
     //TODO: this is lazy. we should set all the TextFormat variables HERE, i 
think
     //This is just so we can set individual variables without having to call 
format_text()
     //This calls format_text() at the end of setting TextFormat
-    if ( tf.alignDefined() ) setAlignment(tf.align());
-    if ( tf.sizeDefined() ) setFontHeight(tf.size()); // keep twips
-    if ( tf.indentDefined() ) setIndent(tf.indent());
-    if ( tf.blockIndentDefined() ) setBlockIndent(tf.blockIndent());
-    if ( tf.leadingDefined() ) setLeading(tf.leading());
-    if ( tf.leftMarginDefined() ) setLeftMargin(tf.leftMargin());
-    if ( tf.rightMarginDefined() ) setRightMargin(tf.rightMargin());
-    if ( tf.colorDefined() ) setTextColor(tf.color());
-    if ( tf.underlinedDefined() ) setUnderlined(tf.underlined());
-    if ( tf.bulletDefined() ) setBullet(tf.bullet());
-    if ( tf.displayDefined() ) setDisplay(tf.display());
-       if ( tf.tabStopsDefined() ) setTabStops(tf.tabStops());
+    if (tf.align()) setAlignment(*tf.align());
+    if (tf.size()) setFontHeight(*tf.size()); // keep twips
+    if (tf.indent()) setIndent(*tf.indent());
+    if (tf.blockIndent()) setBlockIndent(*tf.blockIndent());
+    if (tf.leading()) setLeading(*tf.leading());
+    if (tf.leftMargin()) setLeftMargin(*tf.leftMargin());
+    if (tf.rightMargin()) setRightMargin(*tf.rightMargin());
+    if (tf.color()) setTextColor(*tf.color());
+    if (tf.underlined()) setUnderlined(*tf.underlined());
+    if (tf.bullet()) setBullet(*tf.bullet());
+    setDisplay(tf.display());
+       if (tf.tabStops()) setTabStops(*tf.tabStops());
        
        // NEED TO IMPLEMENT THESE TWO
-       if ( tf.urlDefined() ) setURL(tf.url());
-       if ( tf.targetDefined() ) setTarget(tf.target());
+       if (tf.url()) setURL(*tf.url());
+       if (tf.target()) setTarget(*tf.target());
     
     format_text();
 }
@@ -3300,7 +3300,7 @@
     if (font)
     {
         tf->fontSet(font->name());
-        tf->italicedSet(font->isItalic());
+        tf->italicSet(font->isItalic());
         tf->boldSet(font->isBold());
     }
 
@@ -3355,13 +3355,13 @@
         return as_value();
     }
 
-    if ( tf->fontDefined() )
+    if (tf->font())
     {
-        const std::string& fontName = tf->font();
+        const std::string& fontName = *tf->font();
         if ( ! fontName.empty() )
         {
-            bool bold = tf->bold();
-            bool italic = tf->italiced();
+            bool bold = tf->bold() ? *tf->bold() : false;
+            bool italic = tf->italic() ? *tf->italic() : false;
 
             // NOTE: should query movie-private font lib, not global-shared one
             Movie* mi = text->get_root();

=== modified file 'libcore/asobj/flash/display/MovieClip_as.cpp'
--- a/libcore/asobj/flash/display/MovieClip_as.cpp      2010-01-14 11:45:08 
+0000
+++ b/libcore/asobj/flash/display/MovieClip_as.cpp      2010-01-20 10:36:10 
+0000
@@ -1954,9 +1954,9 @@
     ObjPtr colors = fn.arg(1).to_object(getGlobal(fn));
     ObjPtr alphas = fn.arg(2).to_object(getGlobal(fn));
     ObjPtr ratios = fn.arg(3).to_object(getGlobal(fn));
-    ObjPtr matrixArg = fn.arg(4).to_object(getGlobal(fn));
+    ObjPtr matrix = fn.arg(4).to_object(getGlobal(fn));
 
-    if (!colors || !alphas || !ratios || !matrixArg ) {
+    if (!colors || !alphas || !ratios || !matrix) {
         IF_VERBOSE_ASCODING_ERRORS(
         std::stringstream ss; fn.dump_args(ss);
         log_aserror(_("%s.beginGradientFill(%s): one or more of the "
@@ -1991,122 +1991,74 @@
         stops = 15;
     }
 
-
-    // ----------------------------
-    // Parse SWFMatrix
-    // ----------------------------
-    
-    //
-    // TODO: fix the SWFMatrix build-up, it is NOT correct for
-    //             rotation.
-    //             For the "boxed" SWFMatrixType and radial fills this
-    //             is not a problem as this code just discards the
-    //             rotation (which doesn't make sense), but for
-    //             the explicit SWFMatrix type (a..i) it is a problem.
-    //             The whole code can likely be simplified by 
-    //             always transforming the gnash gradients to the
-    //             expected gradients and subsequently applying
-    //             user-specified SWFMatrix; for 'boxed' SWFMatrixType
-    //             this simplification would increase cost, but
-    //             it's too early to apply optimizations to the
-    //             code (correctness first!!).
     SWFMatrix mat;
+
+    if (radial) {
+        // A gradient box extends from (-16384, -16384) to (16384, 16384),
+        // so we have set scale and translation to convert our radial
+        // (0, 0)-(64, 64) range to a -16384 - 16384 square.
+        mat.concatenate_translation(32, 32);
+        mat.set_scale(1 / 512., 1 / 512.);
+    }
+    else {
+        // A gradient box extends from (-16384, -16384) to (16384, 16384),
+        // so we have set scale and translation to convert our linear 0-256
+        // range to -16384 - 16384.
+        mat.concatenate_translation(128, 0);
+        mat.set_scale(1 / 128., 1 / 128.);
+    }
+
     SWFMatrix input_matrix;
 
-    if (matrixArg->getMember(NSV::PROP_MATRIX_TYPE).to_string() == "box") {
-        
-        boost::int32_t valX = pixelsToTwips(
-                matrixArg->getMember(NSV::PROP_X).to_number()); 
-        boost::int32_t valY = pixelsToTwips(
-                matrixArg->getMember(NSV::PROP_Y).to_number()); 
-        boost::int32_t valW = pixelsToTwips(
-                matrixArg->getMember(NSV::PROP_W).to_number()); 
-        boost::int32_t valH = pixelsToTwips(
-                matrixArg->getMember(NSV::PROP_H).to_number()); 
-        float valR = matrixArg->getMember(NSV::PROP_R).to_number(); 
-
-        if (radial) {
-            // Radial gradient is 64x64 twips.
-            input_matrix.set_scale(64.0/valW, 64.0/valH);
-
-            // For radial gradients, dunno why translation must be negative...
-            input_matrix.concatenate_translation( -valX, -valY );
-
-            // NOTE: rotation is intentionally discarded as it would
-            //             have no effect (theoretically origin of the radial
-            //             fill is at 0,0 making any rotation meaningless).
-
-        }
-        else {
-            // Linear gradient is 256x1 twips.
-            //
-            // No idea why we should use the 256 value for Y scale, but 
-            // empirically seems to give closer results. Note that it only
-            // influences rotation, which is still not correct...
-            // TODO: fix it !
-            input_matrix.set_scale_rotation(256.0/valW, 256.0/valH, -valR);
-
-            // For linear gradients, dunno why translation must be negative...
-            input_matrix.concatenate_translation( -valX, -valY );
-        }
-
-        mat.concatenate(input_matrix);
+    // This is case sensitive.
+    if (matrix->getMember(NSV::PROP_MATRIX_TYPE).to_string() == "box") {
+        
+        const double valX = pixelsToTwips(
+                matrix->getMember(NSV::PROP_X).to_number()); 
+        const double valY = pixelsToTwips(
+                matrix->getMember(NSV::PROP_Y).to_number()); 
+        const double valW = pixelsToTwips(
+                matrix->getMember(NSV::PROP_W).to_number()); 
+        const double valH = pixelsToTwips(
+                matrix->getMember(NSV::PROP_H).to_number()); 
+        const double rot = matrix->getMember(NSV::PROP_R).to_number(); 
+
+        const double a = std::cos(rot) * valW * 2;
+        const double b = std::sin(rot) * valH * 2;
+        const double c = -std::sin(rot) * valW * 2;
+        const double d = std::cos(rot) * valH * 2;
+
+        input_matrix.sx = a; 
+        input_matrix.shx = b;
+        input_matrix.shy = c;
+        input_matrix.sy = d; 
+        input_matrix.tx = valX + valW / 2.0;
+        input_matrix.ty = valY + valH / 2.0;
+        
     }
     else {
-        float valA = matrixArg->getMember(NSV::PROP_A).to_number() ; // xx
-        float valB = matrixArg->getMember(NSV::PROP_B).to_number() ; // yx
-        float valD = matrixArg->getMember(NSV::PROP_D).to_number() ; // xy
-        float valE = matrixArg->getMember(NSV::PROP_E).to_number() ; // yy
-        boost::int32_t valG = pixelsToTwips(
-                matrixArg->getMember(NSV::PROP_G).to_number()); // x0
-        boost::int32_t valH = pixelsToTwips(
-                matrixArg->getMember(NSV::PROP_H).to_number()); // y0
-
-        input_matrix.sx    = valA * 65536; // sx
-        input_matrix.shx = valB * 65536; // shy
-        input_matrix.shy = valD * 65536; // shx
-        input_matrix.sy    = valE * 65536; // sy
-        input_matrix.tx = valG; // x0
-        input_matrix.ty = valH; // y0
-
-        // This is the SWFMatrix that would transform the gnash
-        // gradient to the expected flash gradient.
-        // Transformation is different for linear and radial
-        // gradient for Gnash (in flash they should be the same)
-        SWFMatrix gnashToFlash;
-
-        if (radial) {
-
-            // Gnash radial gradients are 64x64 with center at 32,32
-            // Should be 20x20 with center at 0,0
-            const double g2fs = 20.0/64.0; // gnash to flash scale
-            gnashToFlash.set_scale(g2fs, g2fs);
-            gnashToFlash.concatenate_translation(-32, -32);
-
-        }
-        else {
-            // First define a SWFMatrix that would transform
-            // the gnash gradient to the expected flash gradient:
-            // this means translating our gradient to put the
-            // center of gradient at 0,0 and then scale it to
-            // have a size of 20x20 instead of 256x1 as it is
-            //
-            // Gnash linear gradients are 256x1 with center at 128,0
-            // Should be 20x20 with center at 0,0
-            gnashToFlash.set_scale(20.0/256.0, 20.0/1);
-            gnashToFlash.concatenate_translation(-128, 0);
-
-        }
-
-        // Apply gnash to flash SWFMatrix before user-defined one
-        input_matrix.concatenate(gnashToFlash);
-
-        // Finally, and don't know why, take
-        // the inverse of the resulting SWFMatrix as
-        // the one which would be used.
-        mat = input_matrix;
-        mat.invert();
+
+        // Convert input matrix to SWFMatrix.
+        const double factor = 65536.0;
+        const double valA = matrix->getMember(NSV::PROP_A).to_number() * 
factor;
+        const double valB = matrix->getMember(NSV::PROP_B).to_number() * 
factor;
+        const double valC = matrix->getMember(NSV::PROP_C).to_number() * 
factor;
+        const double valD = matrix->getMember(NSV::PROP_D).to_number() * 
factor;
+
+        const boost::int32_t valTX = pixelsToTwips(
+                matrix->getMember(NSV::PROP_TX).to_number());
+        const boost::int32_t valTY = pixelsToTwips(
+                matrix->getMember(NSV::PROP_TY).to_number());
+
+        input_matrix.sx = valA; 
+        input_matrix.shx = valB;
+        input_matrix.shy = valC;
+        input_matrix.sy = valD; 
+        input_matrix.tx = valTX; 
+        input_matrix.ty = valTY;
     }
+    
+    mat.concatenate(input_matrix.invert());
 
     // ----------------------------
     // Create the gradients vector
@@ -2147,7 +2099,6 @@
         movieclip->beginLinearGradientFill(gradients, mat);
     }
 
-    LOG_ONCE( log_debug("MovieClip.beginGradientFill() TESTING") );
     return as_value();
 }
 

=== modified file 'libcore/asobj/flash/text/TextFormat_as.cpp'
--- a/libcore/asobj/flash/text/TextFormat_as.cpp        2010-01-13 07:54:28 
+0000
+++ b/libcore/asobj/flash/text/TextFormat_as.cpp        2010-01-19 15:44:18 
+0000
@@ -22,23 +22,127 @@
 #include "TextFormat_as.h"
 #include "fn_call.h"
 #include "Global_as.h"
-#include "builtin_function.h" // for getter/setter properties
-#include "NativeFunction.h" // for getter/setter properties
+#include "builtin_function.h" 
+#include "NativeFunction.h" 
 #include "namedStrings.h"
 #include "VM.h"
-#include "RGBA.h" // for rgba type
-#include "StringPredicates.h" // for parseAlignString
-#include "smart_ptr.h" // intrusive_ptr
+#include "RGBA.h" 
+#include "StringPredicates.h"
+#include "smart_ptr.h" 
 #include "GnashNumeric.h"
 #include "Array_as.h"
 
 
 namespace gnash {
 
-// Forward declarations
-
-namespace {
-    
+// Functions and templates for reducing code duplication.
+namespace {
+
+struct
+PositiveTwips
+{
+    int operator()(const as_value& val) const {
+        return pixelsToTwips(std::max<int>(toInt(val), 0));
+    }
+};
+
+struct
+TwipsToPixels
+{
+    template<typename T> double operator()(const T& t) const {
+        return twipsToPixels(t);
+    }
+};
+
+
+struct
+ToBool
+{
+    bool operator()(const as_value& val) const {
+        return val.to_bool();
+    }
+};
+
+struct
+Nothing
+{
+    template<typename T> const T& operator()(const T& val) const {
+        return val;
+    }
+};
+
+/// Produce a function to set a TextFormat property
+//
+/// @tparam T       The type of the Relay (should be TextFormat_as)
+/// @tparam U       The return type of the function to be called (as C++ can't
+///                 yet work out what it is)
+/// @tparam F       The function to call to store the value.
+/// @tparam P       A function object to be applied to the argument before
+///                 storing the value.
+template<typename T, typename U, void(T::*F)(const Optional<U>&), typename P>
+struct Set
+{
+    static as_value set(const fn_call& fn) {
+
+        T* relay = ensure<ThisIsNative<T> >(fn);
+
+        if (!fn.nargs) return as_value();
+
+        const as_value& arg = fn.arg(0);
+        // Undefined doesn't do anything.
+
+        if (arg.is_undefined() || arg.is_null()) {
+            (relay->*F)(Optional<U>());
+            return as_value();
+        }
+
+        (relay->*F)(P()(arg));
+        return as_value();
+    }
+
+};
+
+/// Produce a function to get a TextFormat property
+//
+/// @tparam T       The type of the Relay (should be TextFormat_as)
+/// @tparam U       The return type of the function to be called (as C++ can't
+///                 yet work out what it is)
+/// @tparam F       The function to call to retrieve the value.
+/// @tparam P       A function object to be applied to the argument before
+///                 returning the value.
+template<typename T, typename U, const Optional<U>&(T::*F)(),
+    typename P = Nothing>
+struct Get
+{
+    static as_value get(const fn_call& fn) {
+        T* relay = ensure<ThisIsNative<T> >(fn);
+        const Optional<U>& opt = (relay->*F)();
+               if (opt) return as_value(P()(*opt));
+               
+        as_value null;
+        null.set_null();
+        return null;
+    }
+};
+
+/// Function object for Array handling.
+class
+PushToVector
+{
+public:
+    PushToVector(std::vector<int>& v) : _v(v) {}
+    void operator()(const as_value& val) {
+        _v.push_back(val.to_number());
+    }
+private:
+    std::vector<int>& _v;
+};
+
+
+}
+
+namespace {
+
     as_value textformat_new(const fn_call& fn);
     void attachTextFormatInterface(as_object& o);
     const char* getAlignString(TextField::TextAlignment a);
@@ -47,17 +151,11 @@
        TextField::TextFormatDisplay parseDisplayString(const std::string& 
display);
 
        as_value textformat_display(const fn_call& fn);
-       as_value textformat_bullet(const fn_call& fn);
        as_value textformat_tabStops(const fn_call& fn);
        as_value textformat_blockIndent(const fn_call& fn);
        as_value textformat_leading(const fn_call& fn);
        as_value textformat_indent(const fn_call& fn);
-       as_value textformat_rightMargin(const fn_call& fn);
-       as_value textformat_leftMargin(const fn_call& fn);
        as_value textformat_align(const fn_call& fn);
-       as_value textformat_underline(const fn_call& fn);
-       as_value textformat_italic(const fn_call& fn);
-       as_value textformat_bold(const fn_call& fn);
        as_value textformat_target(const fn_call& fn);
        as_value textformat_url(const fn_call& fn);
        as_value textformat_color(const fn_call& fn);
@@ -67,10 +165,22 @@
 
 }
 
+TextFormat_as::TextFormat_as()
+    :
+    _display(TextField::TEXTFORMAT_BLOCK)
+{
+}
+
+
+
 void
 TextFormat_as::alignSet(const std::string& align) 
 {
-    alignSet(parseAlignString(align));
+    StringNoCaseEqual cmp;
+    if (cmp(align, "left")) alignSet(TextField::ALIGN_LEFT);
+    if (cmp(align, "center")) alignSet(TextField::ALIGN_CENTER);
+    if (cmp(align, "right")) alignSet(TextField::ALIGN_RIGHT);
+    if (cmp(align, "justify")) alignSet(TextField::ALIGN_JUSTIFY);
 }
 
 void
@@ -88,65 +198,102 @@
     // TODO: these functions are probably split into getters and setters
     // instead of one function for both. Needs testing.
     vm.registerNative(textformat_new, 110, 0);
+    
     vm.registerNative(textformat_font, 110, 1);
     vm.registerNative(textformat_font, 110, 2);
+    
     vm.registerNative(textformat_size, 110, 3);
     vm.registerNative(textformat_size, 110, 4);
+    
     vm.registerNative(textformat_color, 110, 5);
     vm.registerNative(textformat_color, 110, 6);
+    
     vm.registerNative(textformat_url, 110, 7);
     vm.registerNative(textformat_url, 110, 8);
+    
     vm.registerNative(textformat_target, 110, 9);
     vm.registerNative(textformat_target, 110, 10);
-    vm.registerNative(textformat_bold, 110, 11);
-    vm.registerNative(textformat_bold, 110, 12);
-    vm.registerNative(textformat_italic, 110, 13);
-    vm.registerNative(textformat_italic, 110, 14);
-    vm.registerNative(textformat_underline, 110, 15);
-    vm.registerNative(textformat_underline, 110, 16);
+    
+    vm.registerNative(
+            Get<const TextFormat_as, bool, &TextFormat_as::bold>::get,
+            110, 11);
+    vm.registerNative(
+            Set<TextFormat_as, bool, &TextFormat_as::boldSet,
+            ToBool>::set, 
+            110, 12);
+    
+    vm.registerNative(
+            Get<const TextFormat_as, bool, &TextFormat_as::italic>::get,
+            110, 13);
+    vm.registerNative(
+            Set<TextFormat_as, bool, &TextFormat_as::italicSet,
+            ToBool>::set, 
+            110, 14);
+    
+    vm.registerNative(
+            Get<const TextFormat_as, bool, &TextFormat_as::underlined>::get,
+            110, 15);
+    vm.registerNative(
+            Set<TextFormat_as, bool, &TextFormat_as::underlinedSet,
+            ToBool>::set, 
+            110, 16);
+    
     vm.registerNative(textformat_align, 110, 17);
     vm.registerNative(textformat_align, 110, 18);
-    vm.registerNative(textformat_leftMargin, 110, 19);
-    vm.registerNative(textformat_leftMargin, 110, 20);
-    vm.registerNative(textformat_rightMargin, 110, 21);
-    vm.registerNative(textformat_rightMargin, 110, 22);
+
+    vm.registerNative(
+            Get<const TextFormat_as, boost::uint16_t,
+            &TextFormat_as::leftMargin, TwipsToPixels>::get,
+            110, 19);
+    vm.registerNative(
+            Set<TextFormat_as, boost::uint16_t, &TextFormat_as::leftMarginSet,
+            PositiveTwips>::set, 
+            110, 20);
+
+    vm.registerNative(
+            Get<const TextFormat_as, boost::uint16_t,
+            &TextFormat_as::rightMargin, TwipsToPixels>::get,
+            110, 21);
+    vm.registerNative(
+            Set<TextFormat_as, boost::uint16_t, &TextFormat_as::rightMarginSet,
+            PositiveTwips>::set, 
+            110, 22);
+
     vm.registerNative(textformat_indent, 110, 23);
-    vm.registerNative(textformat_indent, 110, 24);
+    vm.registerNative(
+            Set<TextFormat_as, boost::uint16_t, &TextFormat_as::indentSet,
+            PositiveTwips>::set, 
+            110, 24);
+    
     vm.registerNative(textformat_leading, 110, 25);
-    vm.registerNative(textformat_leading, 110, 26);
+    vm.registerNative(
+            Set<TextFormat_as, boost::uint16_t, &TextFormat_as::leadingSet,
+            PositiveTwips>::set, 
+            110, 26);
+
     vm.registerNative(textformat_blockIndent, 110, 27);
-    vm.registerNative(textformat_blockIndent, 110, 28);
+
+    // Note: this behaves differently in SWF8, so perhaps best not to use
+    // the template.
+    vm.registerNative(
+            Set<TextFormat_as, boost::uint32_t, &TextFormat_as::blockIndentSet,
+            PositiveTwips>::set,
+            110, 28);
+
     vm.registerNative(textformat_tabStops, 110, 29);
     vm.registerNative(textformat_tabStops, 110, 30);
-    vm.registerNative(textformat_bullet, 110, 31);
-    vm.registerNative(textformat_bullet, 110, 32);
+
+    vm.registerNative(
+            Get<const TextFormat_as, bool, &TextFormat_as::bullet,
+            ToBool>::get, 110, 31);
+    vm.registerNative(
+            Set<TextFormat_as, bool, &TextFormat_as::bulletSet,
+            ToBool>::set, 
+            110, 32);
+
     vm.registerNative(textformat_getTextExtent, 110, 33);
 }
 
-TextFormat_as::TextFormat_as()
-       :
-       _flags(0),
-       _underline(false),
-       _bold(false),
-       _italic(false),
-       _bullet(false),
-    _display(),
-       _align(TextField::ALIGN_LEFT),
-       _blockIndent(-1),
-       _color(),
-       _indent(-1),
-       _leading(-1),
-       _leftMargin(-1),
-       _rightMargin(-1),
-       _pointSize(-1),
-       _tabStops(),
-       _target(),
-       _url()
-{
-}
-
-
-
 // extern (used by Global.cpp)
 void
 textformat_class_init(as_object& global, const ObjectURI& uri)
@@ -201,7 +348,7 @@
            case 6:
                tf->underlinedSet(fn.arg(5).to_bool());
            case 5:
-               tf->italicedSet(fn.arg(4).to_bool());
+               tf->italicSet(fn.arg(4).to_bool());
            case 4:
                tf->boldSet(fn.arg(3).to_bool());
            case 3:
@@ -244,10 +391,7 @@
 
        if ( fn.nargs == 0 ) // getter
        {
-               if ( relay->displayDefined() ) {
-            ret.set_string(getDisplayString(relay->display()));
-        }
-        else ret.set_null();
+        ret.set_string(getDisplayString(relay->display()));
        }
        else // setter
        {
@@ -258,38 +402,6 @@
 }
 
 as_value
-textformat_bullet(const fn_call& fn)
-{
-    TextFormat_as* relay = ensure<ThisIsNative<TextFormat_as> >(fn);
-
-       as_value ret;
-
-       if ( fn.nargs == 0 ) // getter
-       {
-               if ( relay->bulletDefined() ) ret.set_bool(relay->bullet());
-               else ret.set_null();
-       }
-       else // setter
-       {
-           // Boolean
-               relay->bulletSet(fn.arg(0).to_bool());
-       }
-
-       return ret;
-}
-
-class PushToVector
-{
-public:
-    PushToVector(std::vector<int>& v) : _v(v) {}
-    void operator()(const as_value& val) {
-        _v.push_back(val.to_number());
-    }
-private:
-    std::vector<int>& _v;
-};
-
-as_value
 textformat_tabStops(const fn_call& fn)
 {
     TextFormat_as* relay = ensure<ThisIsNative<TextFormat_as> >(fn);
@@ -321,17 +433,13 @@
 
        as_value ret;
 
-       if ( fn.nargs == 0 ) // getter
+       if (fn.nargs == 0) 
        {
-               if (relay->blockIndentDefined()) {
-            ret.set_double(twipsToPixels(relay->blockIndent()));
+               if (relay->blockIndent()) {
+            ret.set_double(twipsToPixels(*relay->blockIndent()));
         }
                else ret.set_null();
        }
-       else // setter
-       {
-               relay->blockIndentSet(pixelsToTwips(toInt(fn.arg(0))));
-       }
 
        return ret;
 }
@@ -345,7 +453,7 @@
 
        if ( fn.nargs == 0 ) // getter
        {
-               if ( relay->leadingDefined() ) 
ret.set_double(twipsToPixels(relay->leading()));
+               if (relay->leading()) 
ret.set_double(twipsToPixels(*relay->leading()));
                else ret.set_null();
        }
        else // setter
@@ -365,54 +473,8 @@
 
        if ( fn.nargs == 0 ) // getter
        {
-               if ( relay->indentDefined() ) 
ret.set_double(twipsToPixels(relay->indent()));
-               else ret.set_null();
-       }
-       else // setter
-       {
-               relay->indentSet(pixelsToTwips(toInt(fn.arg(0))));
-       }
-
-       return ret;
-}
-
-as_value
-textformat_rightMargin(const fn_call& fn)
-{
-    TextFormat_as* relay = ensure<ThisIsNative<TextFormat_as> >(fn);
-
-       as_value ret;
-
-       if ( fn.nargs == 0 ) // getter
-       {
-               if ( relay->rightMarginDefined() ) 
ret.set_double(twipsToPixels(relay->rightMargin()));
-               else ret.set_null();
-       }
-       else // setter
-       {
-               relay->rightMarginSet(pixelsToTwips(toInt(fn.arg(0))));
-       }
-
-       return ret;
-}
-
-as_value
-textformat_leftMargin(const fn_call& fn)
-{
-    TextFormat_as* relay = ensure<ThisIsNative<TextFormat_as> >(fn);
-
-       as_value ret;
-
-       if ( fn.nargs == 0 ) // getter
-       {
-               if (relay->leftMarginDefined()) {
-            ret.set_double(twipsToPixels(relay->leftMargin()));
-        }
-               else ret.set_null();
-       }
-       else // setter
-       {
-               relay->leftMarginSet(pixelsToTwips(toInt(fn.arg(0))));
+               if (relay->indent()) 
ret.set_double(twipsToPixels(*relay->indent()));
+               else ret.set_null();
        }
 
        return ret;
@@ -427,8 +489,8 @@
 
        if ( fn.nargs == 0 ) // getter
        {
-               if ( relay->alignDefined() ) {
-            ret.set_string(getAlignString(relay->align()));
+               if (relay->align()) {
+            ret.set_string(getAlignString(*relay->align()));
         }
         else ret.set_null();
        }
@@ -441,66 +503,6 @@
 }
 
 as_value
-textformat_underline(const fn_call& fn)
-{
-    TextFormat_as* relay = ensure<ThisIsNative<TextFormat_as> >(fn);
-
-       as_value ret;
-
-       if ( fn.nargs == 0 ) // getter
-       {
-               if ( relay->underlinedDefined() ) 
ret.set_bool(relay->underlined());
-               else ret.set_null();
-       }
-       else // setter
-       {
-               relay->underlinedSet(fn.arg(0).to_bool());
-       }
-
-       return ret;
-}
-
-as_value
-textformat_italic(const fn_call& fn)
-{
-    TextFormat_as* relay = ensure<ThisIsNative<TextFormat_as> >(fn);
-
-       as_value ret;
-
-       if ( fn.nargs == 0 ) // getter
-       {
-               if ( relay->italicedDefined() ) ret.set_bool(relay->italiced());
-               else ret.set_null();
-       }
-       else // setter
-       {
-               relay->italicedSet(fn.arg(0).to_bool());
-       }
-
-       return ret;
-}
-
-as_value
-textformat_bold(const fn_call& fn)
-{
-    TextFormat_as* relay = ensure<ThisIsNative<TextFormat_as> >(fn);
-
-       as_value ret;
-
-       if ( fn.nargs == 0 ) // getter
-       {
-               if ( relay->boldDefined() ) ret.set_bool(relay->bold());
-               else ret.set_null();
-       }
-       else // setter
-       {
-               relay->boldSet(fn.arg(0).to_bool());
-       }
-
-       return ret;
-}
-
-as_value
 textformat_target(const fn_call& fn)
 {
     TextFormat_as* relay = ensure<ThisIsNative<TextFormat_as> >(fn);
@@ -509,7 +511,7 @@
 
        if ( fn.nargs == 0 ) // getter
        {
-               if ( relay->targetDefined() ) ret.set_string(relay->target());
+               if (relay->target()) ret.set_string(*relay->target());
                else ret.set_null();
        }
        else // setter
@@ -529,7 +531,7 @@
 
        if ( fn.nargs == 0 ) // getter
        {
-               if ( relay->urlDefined() ) ret.set_string(relay->url());
+               if (relay->url()) ret.set_string(*relay->url());
                else ret.set_null();
        }
        else // setter
@@ -549,7 +551,7 @@
 
        if ( fn.nargs == 0 ) // getter
        {
-               if ( relay->colorDefined() )  
ret.set_double(relay->color().toRGB());
+               if (relay->color()) ret.set_double(relay->color()->toRGB());
                else ret.set_null();
        }
        else // setter
@@ -571,7 +573,7 @@
 
        if ( fn.nargs == 0 ) // getter
        {
-               if ( relay->sizeDefined() ) 
ret.set_double(twipsToPixels(relay->size()));
+               if (relay->size()) 
ret.set_double(twipsToPixels(*relay->size()));
                else ret.set_null();
        }
        else // setter
@@ -591,7 +593,7 @@
 
        if ( fn.nargs == 0 ) // getter
        {
-               if (relay->fontDefined()) ret.set_string(relay->font());
+               if (relay->font()) ret.set_string(*relay->font());
                else ret.set_null();
        }
        else // setter
@@ -676,19 +678,6 @@
 }
 
 
-TextField::TextAlignment
-parseAlignString(const std::string& align)
-{
-       StringNoCaseEqual cmp;
-       if ( cmp(align, "left") ) return TextField::ALIGN_LEFT;
-    if ( cmp(align, "center") ) return TextField::ALIGN_CENTER;
-       if ( cmp(align, "right") ) return TextField::ALIGN_RIGHT;
-       if ( cmp(align, "justify") ) return TextField::ALIGN_JUSTIFY;
-       
-       log_debug("Invalid align string %s, taking as left", align);
-       return TextField::ALIGN_LEFT;
-}
-
 TextField::TextFormatDisplay
 parseDisplayString(const std::string& display)
 {

=== modified file 'libcore/asobj/flash/text/TextFormat_as.h'
--- a/libcore/asobj/flash/text/TextFormat_as.h  2010-01-11 06:41:38 +0000
+++ b/libcore/asobj/flash/text/TextFormat_as.h  2010-01-19 15:44:18 +0000
@@ -31,231 +31,249 @@
 
 namespace gnash {  
 
+/// A type to hold a simple value but with an additional 'unset' state.
+//
+/// Most TextFormat values can be 'uninitialized', meaning they are not
+/// taken into account when applying formatting. These values return null
+/// in ActionScript.
+template<typename T>
+class
+Optional
+{
+public:
+
+    /// Construct an Optional<T> with no value set.
+    Optional()
+        :
+        _t(),
+        _set(false)
+    {}
+
+    /// Construct an Optional<T> with an initial value.
+    //
+    /// Implicit construction is allowed.
+    Optional(const T& t)
+        :
+        _t(t),
+        _set(true)
+    {}
+
+    /// Unset this value.
+    void unset() {
+        _set = false;
+    }
+
+    /// Relatively safe conversion to bool via void*.
+    operator const void*() const {
+        return _set ? this : 0;
+    }
+
+    /// Access to value using operator->().
+    const T* operator->() const {
+        assert(_set);
+        return &_t;
+    }
+
+    /// Assign a T to this Optional<T>.
+    Optional<T>& operator=(const T& t) {
+        _t = t;
+        _set = true;
+        return *this;
+    }
+
+    /// Retrieve type only if set (converts to true).
+    const T& operator*() const {
+        assert(_set);
+        return _t;
+    }
+
+private:
+    T _t;
+    bool _set;
+};
+
+
+/// The TextFormat_as Relay type stores text properties.
+//
+/// Most properties can either have a value or be null.
+//
 /// TODO: SWF8 has two additional members: kerning and letterSpacing.
 class TextFormat_as : public Relay
 {
 public:
   
-       TextFormat_as();
-       ~TextFormat_as() {}
-
-       /// Return a Boolean value that indicates whether the text is 
underlined.
-       bool underlined() const { return _underline; }
-       bool underlinedDefined() const { return _flags&DEFunderline; }
-
-       /// Return a Boolean value that indicates whether the text is 
italicized.
-       bool italiced() const { return _italic; }
-       bool italicedDefined() const { return _flags&DEFitalic; }
-
-       /// Return a Boolean value that indicates whether the text is boldface.
-       bool bold() const { return _bold; }
-       bool boldDefined() const { return _flags&DEFbold; }
-
-       bool bullet() const { return _bullet; }
-       bool bulletDefined() const { return _flags&DEFbullet; }
-
-       /// Return the color of text using this text format.
-       const rgba& color() const { return _color; }
-       bool colorDefined() const { return _flags&DEFcolor; }
-
-       TextField::TextFormatDisplay display() const {return _display; }
-       bool displayDefined() const { return _flags&DEFdisplay; }
-       
-       std::vector<int> tabStops() const { return _tabStops; }
-       bool tabStopsDefined() const { return _flags&DEFtabStops; }
-       
-    void tabStopsSet(const std::vector<int>& tabStops) { 
-        _tabStops = tabStops;
-               _flags |= DEFtabStops; 
-       }
-
-       /// \brief
-       /// Return an integer that indicates the indentation from the left
-    /// margin to the first DisplayObject in the paragraph
-       boost::uint16_t indent() const { return _indent; }
-       bool indentDefined() const { return _flags&DEFindent; }
-
-       /// Return the alignment of the paragraph.
-       TextField::TextAlignment align() const { return _align; }
-       bool alignDefined() const { return _flags&DEFalign; }
-
-       /// Return the name of a font for text as a string.
-       const std::string& font() const { return _font; }
-       bool fontDefined() const { return _flags&DEFfont; }
-
-       // See doc for _target member
-       const std::string& target() const { return _target; }
-       bool targetDefined() const { return _flags&DEFtarget; }
-
-       // See doc for _target member
-       void targetSet(const std::string& s) { _target=s; _flags |= DEFtarget; }
-
-       // See doc for _url member
-       const std::string& url() const { return _url; }
-       bool urlDefined() const { return _flags&DEFurl; }
-
-       // See doc for _url member
-       void urlSet(const std::string& s) { _url=s; _flags |= DEFurl; }
-
-       ///
-       boost::uint16_t blockIndent() { return _blockIndent; }
-       bool blockIndentDefined() const { return _flags&DEFblockIndent; }
-
-       /// Return a number that indicates the amount of leading vertical
-       /// space between lines.
-       boost::uint16_t leading()     { return _leading; }
-       bool leadingDefined() const { return _flags&DEFleading; }
-
-       /// Indicates the left margin of the paragraph, in points.
-       boost::uint16_t leftMargin()  { return _leftMargin; }
-       bool leftMarginDefined() const { return _flags&DEFleftMargin; }
-
-       /// Indicates the right margin of the paragraph, in points.
-       boost::uint16_t rightMargin() { return _rightMargin; }
-       bool rightMarginDefined() const { return _flags&DEFrightMargin; }
-
-       /// Return a float that indicates the point size in twips.
-       boost::uint16_t size()        { return _pointSize; }
-       bool sizeDefined() const { return _flags&DEFsize; }
-
-       void underlinedSet(bool x)   { _underline = x; _flags |= DEFunderline; }
-       void italicedSet(bool x)     { _italic = x; _flags |= DEFitalic; }
-       void boldSet(bool x)         { _bold = x; _flags |= DEFbold; }
-       void bulletSet(bool x)       { _bullet = x; _flags |= DEFbullet; }
-       void colorSet(const rgba& x)      { _color = x; _flags |= DEFcolor; }
-       void indentSet(boost::uint16_t x)      { _indent = x; _flags |= 
DEFindent; }
-       void fontSet(const std::string& font) { _font=font; _flags |= DEFfont; }
-       void displaySet(TextField::TextFormatDisplay x) {
-               _display = x;
-               _flags |= DEFdisplay;
-       }
-       
-       void displaySet(const std::string& display);
-       
-    void alignSet(TextField::TextAlignment x) {
-        _align = x;
-        _flags |= DEFalign;
-    }
-
-       void alignSet(const std::string& align);
-
-       void blockIndentSet(boost::uint16_t x)   { 
+    TextFormat_as();
+
+    ~TextFormat_as() {}
+
+    /// Return a Boolean value that indicates whether the text is underlined.
+    const Optional<bool>& underlined() const { return _underline; }
+    
+    /// Return a Boolean value that indicates whether the text is boldface.
+    const Optional<bool>& bold() const { return _bold; }
+
+    /// Return a Boolean value that indicates whether the text is italicized.
+    const Optional<bool>& italic() const { return _italic; }
+
+    /// Return the color of text using this text format.
+    const Optional<rgba>& color() const { return _color; }
+
+    /// Whether the text should have a bullet.
+    const Optional<bool>& bullet() const { return _bullet; }
+
+    /// The display type (block or inline).
+    //
+    /// Note this is not an optional parameter.
+    TextField::TextFormatDisplay display() const {
+        return _display;
+    }
+
+    const Optional<std::vector<int> >& tabStops() const {
+        return _tabStops;
+    }
+
+    /// Indentation from left margin to the first character in the paragraph
+    const Optional<boost::uint16_t>& indent() const { return _indent; }
+    
+    /// Paragraph alignment
+    const Optional<TextField::TextAlignment>& align() const { return _align; }
+
+    /// Font name.
+    const Optional<std::string>& font() const { return _font; }
+
+    // See doc for _target member
+    const Optional<std::string>& target() const { return _target; }
+
+    // See doc for _url member
+    const Optional<std::string>& url() const { return _url; }
+
+    /// The block indent.
+    const Optional<boost::uint32_t>& blockIndent() { return _blockIndent; }
+
+    /// Return a number that indicates the amount of leading vertical
+    /// space between lines.
+    const Optional<boost::uint16_t>& leading() const { return _leading; }
+
+    /// Indicates the left margin of the paragraph, in points.
+    const Optional<boost::uint16_t>& leftMargin() const { return _leftMargin; }
+
+    /// Indicates the right margin of the paragraph in twips
+    const Optional<boost::uint16_t>& rightMargin() const {
+        return _rightMargin;
+    }
+
+    /// Return a float that indicates the point size in twips.
+    const Optional<boost::uint16_t>& size() const { return _pointSize; }
+
+    /// Setters
+
+    void targetSet(const Optional<std::string>& s) { _target=s; }
+
+    void urlSet(const Optional<std::string>& s) { _url=s; }
+
+    void underlinedSet(const Optional<bool>& x) { _underline = x; }
+
+    void italicSet(const Optional<bool>& x) { _italic = x; }
+
+    void boldSet(const Optional<bool>& x) { _bold = x; }
+
+    void bulletSet(const Optional<bool>& x) { _bullet = x; }
+
+    void colorSet(const Optional<rgba>& x) { _color = x; }
+
+    void indentSet(const Optional<boost::uint16_t>& x) { _indent = x; }
+
+    void fontSet(const Optional<std::string>& font) { _font=font; }
+    
+    void alignSet(const Optional<TextField::TextAlignment>& x) { _align = x; }
+    
+    void alignSet(const std::string& align);
+    
+    void blockIndentSet(const Optional<boost::uint32_t>& x) {
         _blockIndent = x;
-        _flags |= DEFblockIndent;
-    }
-
-       void leadingSet(boost::uint16_t x) {
-        _leading = x;
-        _flags |= DEFleading;
-    }
-
-       void leftMarginSet(boost::uint16_t x) {
-        _leftMargin = x;
-        _flags |= DEFleftMargin;
-    }
-       
-    void rightMarginSet(boost::uint16_t x) {
+    }
+    
+    void leadingSet(const Optional<boost::uint16_t>& x) { _leading = x; }
+
+    void leftMarginSet(const Optional<boost::uint16_t>& x) { _leftMargin = x; }
+
+    void rightMarginSet(const Optional<boost::uint16_t>& x) {
         _rightMargin = x;
-        _flags |= DEFrightMargin;
-    }
-
-       /// Set font point size in twips
-       void sizeSet(boost::uint16_t x) {
-        _pointSize = x;
-        _flags |= DEFsize;
-    }
-
+    }
+
+    void sizeSet(const Optional<boost::uint16_t>& x) { _pointSize = x; }
+
+    void tabStopsSet(const std::vector<int>& tabStops) { _tabStops = tabStops; 
}
+
+    /// These are not optional!
+    void displaySet(TextField::TextFormatDisplay x) { _display = x; }
+    void displaySet(const std::string& display);
 private:
 
-    enum {
-               DEFunderline    =1<<0,
-               DEFbold         =1<<1,
-               DEFitalic       =1<<2,
-               DEFbullet       =1<<3,
-               DEFalign        =1<<4,
-               DEFblockIndent  =1<<5,
-               DEFcolor        =1<<6,
-               DEFfont         =1<<7,
-               DEFindent       =1<<8,
-               DEFleading      =1<<9,
-               DEFleftMargin   =1<<10,
-               DEFrightMargin  =1<<11,
-               DEFpointSize    =1<<12,
-               DEFtabStops     =1<<13,
-               DEFtarget       =1<<14,
-               DEFurl          =1<<15,
-               DEFsize         =1<<16,
-               DEFdisplay  =1<<17
-       };
-
-    // need at least 17 bit here... (1<<16)
-       boost::uint64_t _flags;
-    //boost::uint32_t _flags; 
-
-       /// A Boolean value that indicates whether the text is underlined.
-       bool _underline;
-
-       /// A Boolean value that indicates whether the text is boldface.
-       bool _bold;
-
-       /// A Boolean value that indicates whether the text is italicized.
-       bool _italic;
-
-       // 
-       bool _bullet;
-       
-       TextField::TextFormatDisplay _display;
+    /// A Boolean value that indicates whether the text is underlined.
+    Optional<bool> _underline;
+
+    /// A Boolean value that indicates whether the text is boldface.
+    Optional<bool> _bold;
+
+    /// A Boolean value that indicates whether the text is italicized.
+    Optional<bool> _italic;
+
+    // 
+    Optional<bool> _bullet;
+    
+    TextField::TextFormatDisplay _display;
   
-       /// The alignment of the paragraph, represented as a string.
-       //
-       /// If "left", the paragraph is left-aligned. If "center", the
-       /// paragraph is centered. If "right", the paragraph is
-       /// right-aligned. If "justify", the paragraph is justified.
-       ///
-       TextField::TextAlignment _align;
-
-       // 
-       boost::uint16_t _blockIndent;
-
-       /// The color of text using this text format.
-       //
-       /// A number containing three 8-bit RGB components; for example,
+    /// The alignment of the paragraph, represented as a string.
+    //
+    /// If "left", the paragraph is left-aligned. If "center", the
+    /// paragraph is centered. If "right", the paragraph is
+    /// right-aligned. If "justify", the paragraph is justified.
+    ///
+    Optional<TextField::TextAlignment> _align;
+
+    // 
+    Optional<boost::uint32_t> _blockIndent;
+
+    /// The color of text using this text format.
+    //
+    /// A number containing three 8-bit RGB components; for example,
         /// 0xFF0000 is red, 0x00FF00 is green.
-       rgba _color;    
-
-       // The name of a font for text as a string.
-       std::string _font;      
-
-       /// An integer that indicates the indentation from the left
+    Optional<rgba> _color;    
+
+    // The name of a font for text as a string.
+    Optional<std::string> _font;    
+
+    /// An integer that indicates the indentation from the left
     /// margin to the first DisplayObject in the paragraph (twips)
-       boost::uint16_t _indent;
-
-       /// A number that indicates the amount of leading vertical
-       /// space between lines (twips)
-       boost::uint16_t _leading;
-
-       /// Indicates the left margin of the paragraph, in points (twips)
-       boost::uint16_t _leftMargin;
-
-       /// Indicates the right margin of the paragraph, in points (twips).
-       boost::uint16_t _rightMargin;
-
-       /// Point size in twips.
-       boost::uint16_t _pointSize;
-
-       ///
-       std::vector<int> _tabStops;
-
-       /// The target window where the hyperlink is displayed. 
+    Optional<boost::uint16_t> _indent;
+
+    /// A number that indicates the amount of leading vertical
+    /// space between lines (twips)
+    Optional<boost::uint16_t> _leading;
+
+    /// Indicates the left margin of the paragraph, in points (twips)
+    Optional<boost::uint16_t> _leftMargin;
+
+    /// Indicates the right margin of the paragraph, in points (twips).
+    Optional<boost::uint16_t> _rightMargin;
+
+    /// Point size in twips.
+    Optional<boost::uint16_t> _pointSize;
+
+    ///
+    Optional<std::vector<int> > _tabStops;
+
+    /// The target window where the hyperlink is displayed. 
         /// If the target window is an empty string, the text is displayed in
         /// the default target window _self. If the url parameter is
         /// set to an empty string or to the value null, you can get
         /// or set this property, but the property will have no effect.
-       std::string     _target;
+    Optional<std::string> _target;
 
-       /// The URL to which the text in this text format hyperlinks.
-       /// If url is an empty string, the text does not have a hyperlink
-       std::string      _url;  
+    /// The URL to which the text in this text format hyperlinks.
+    /// If url is an empty string, the text does not have a hyperlink
+    Optional<std::string> _url;    
 };
 
 void textformat_class_init(as_object& global, const ObjectURI& uri);

=== modified file 'libcore/fill_style.cpp'
--- a/libcore/fill_style.cpp    2010-01-14 11:15:29 +0000
+++ b/libcore/fill_style.cpp    2010-01-20 10:36:15 +0000
@@ -34,10 +34,6 @@
 
 namespace gnash {
 
-//
-// gradient_record
-//
-
 void
 gradient_record::read(SWFStream& in, SWF::TagType tag)
 {
@@ -46,13 +42,10 @@
     m_color.read(in, tag);
 }
 
-//
-// fill_style
-//
 fill_style::fill_style()
     :
     _bitmapInfo(0),
-    m_color(), // FF.FF.FF.FF
+    m_color(), 
     m_spread_mode(SWF::GRADIENT_SPREAD_PAD),
     m_interpolation(SWF::GRADIENT_INTERPOL_NORMAL),
     m_type(SWF::FILL_SOLID),
@@ -60,7 +53,6 @@
 {
 }
 
-
 void
 fill_style::read(SWFStream& in, SWF::TagType t, movie_definition& md,
         const RunResources& r, fill_style *pOther)
@@ -110,13 +102,12 @@
 
         // shouldn't this be in initializer's list ?
         _matrix.set_identity();
-        if (m_type == SWF::FILL_LINEAR_GRADIENT)
-        {
+        if (m_type == SWF::FILL_LINEAR_GRADIENT) {
             _matrix.set_translation(128, 0);
             _matrix.set_scale(1.0/128, 1.0/128);
         }
-        else // FILL_RADIAL_GRADIENT or FILL_FOCAL_GRADIENT
-        {
+        else {
+            // FILL_RADIAL_GRADIENT or FILL_FOCAL_GRADIENT
             _matrix.set_translation(32, 32);
             _matrix.set_scale(1.0/512, 1.0/512);
         }
@@ -124,14 +115,10 @@
         SWFMatrix m = input_matrix;
         m.invert();
 
-        if (is_morph)
-        {
-            pOther->_matrix = _matrix;
-        }
+        if (is_morph) pOther->_matrix = _matrix;
         _matrix.concatenate(m);
         
-        if (is_morph)
-        {
+        if (is_morph) {
             input_matrix.read(in);
             m = input_matrix;
             m.invert();
@@ -160,7 +147,7 @@
                 IF_VERBOSE_MALFORMED_SWF(
                     log_swferror("Illegal spread mode in gradient 
definition.");
                 );
-                }
+            }
     
             uint8_t interpolation = (grad_props >> 4) & 3;
             switch(interpolation) {
@@ -187,8 +174,7 @@
         }
     
         if (num_gradients > 8 + ((t == SWF::DEFINESHAPE4 ||
-            t == SWF::DEFINESHAPE4_) ? 7 : 0))
-        {
+            t == SWF::DEFINESHAPE4_) ? 7 : 0)) {
            // see: http://sswf.sourceforge.net/SWFalexref.html#swf_gradient
             IF_VERBOSE_MALFORMED_SWF(
                 log_swferror(_("Unexpected num gradients (%d), "
@@ -201,7 +187,7 @@
         }
                 
         m_gradients.resize(num_gradients);
-        for (unsigned int i = 0; i < num_gradients; i++) {
+        for (size_t i = 0; i < num_gradients; ++i) {
             m_gradients[i].read(in, t);
             if (is_morph) {
                 pOther->m_gradients[i].read(in, t);
@@ -209,8 +195,7 @@
         }
     
         // A focal gradient also has a focal point.
-        if (m_type == SWF::FILL_FOCAL_GRADIENT)
-        {
+        if (m_type == SWF::FILL_FOCAL_GRADIENT) {
            in.ensureBytes(2);
            m_focal_point = in.read_short_sfixed();
            if (m_focal_point < -1.0f) m_focal_point = -1.0f;
@@ -221,7 +206,7 @@
                 pOther->m_focal_point = m_focal_point;
         }
     
-        IF_VERBOSE_PARSE (
+        IF_VERBOSE_PARSE(
            log_parse("  gradients: num_gradients = %d",
                static_cast<int>(num_gradients));
         );
@@ -252,24 +237,20 @@
         // 0x42: tiled bitmap fill with hard edges
         // 0x43: clipped bitmap fill with hard edges
 
-        if ( m_type == SWF::FILL_TILED_BITMAP_HARD ||
-             m_type == SWF::FILL_CLIPPED_BITMAP_HARD )
-        {
+        if (m_type == SWF::FILL_TILED_BITMAP_HARD ||
+             m_type == SWF::FILL_CLIPPED_BITMAP_HARD) {
             _bitmapSmoothingPolicy = BITMAP_SMOOTHING_OFF;
         }
-        else if ( md.get_version() >= 8 )
-        {
+        else if (md.get_version() >= 8) {
             _bitmapSmoothingPolicy = BITMAP_SMOOTHING_ON;
         }
-        else
-        {
+        else {
             _bitmapSmoothingPolicy = BITMAP_SMOOTHING_UNSPECIFIED;
         }
 
         in.ensureBytes(2);
         int bitmap_char_id = in.read_u16();
-        IF_VERBOSE_PARSE
-        (
+        IF_VERBOSE_PARSE(
             log_parse("  bitmap_char = %d, smoothing_policy = %s",
                 bitmap_char_id, _bitmapSmoothingPolicy);
         );
@@ -277,8 +258,7 @@
         // Look up the bitmap DisplayObject.
         _bitmapInfo = md.getBitmap(bitmap_char_id);
         IF_VERBOSE_MALFORMED_SWF(
-            if (!_bitmapInfo)
-            {
+            if (!_bitmapInfo) {
                 LOG_ONCE(
                     log_swferror(_("Bitmap fill specifies '%d' as associated"
                         " bitmap DisplayObject id,"
@@ -291,25 +271,24 @@
             }
         );
 
-        SWFMatrix  m;
+        SWFMatrix m;
         m.read(in);
 
         // For some reason, it looks like they store the inverse of the
         // TWIPS-to-texcoords SWFMatrix.
         _matrix = m.invert();
 
-        if (is_morph)
-        {
+        if (is_morph) {
             pOther->_bitmapInfo = _bitmapInfo;
             m.read(in);
             pOther->_matrix = m.invert();
         }
+
         IF_VERBOSE_PARSE(
            log_parse("SWFMatrix: %s", _matrix);
         );
     }
-    else
-    {
+    else {
         std::stringstream ss;
         ss << "Unknown fill style type " << m_type;    
         // This is a fatal error, we'll be leaving the stream
@@ -445,22 +424,22 @@
             // Linear gradient.
             im.reset(new ImageRGBA(256, 1));
 
-            for (size_t i = 0; i < im->width(); i++)
-            {
+            for (size_t i = 0; i < im->width(); i++) {
                 rgba sample = sample_gradient(i);
                 im->setPixel(i, 0, sample.m_r, sample.m_g,
                         sample.m_b, sample.m_a);
             }
             break;
+
         case SWF::FILL_RADIAL_GRADIENT:
             // Radial gradient.
             im.reset(new ImageRGBA(64, 64));
 
             for (size_t j = 0; j < im->height(); j++) {
                 for (size_t i = 0; i < im->width(); i++) {
-                    float   radius = (im->height() - 1) / 2.0f;
-                    float   y = (j - radius) / radius;
-                    float   x = (i - radius) / radius;
+                    float radius = (im->height() - 1) / 2.0f;
+                    float y = (j - radius) / radius;
+                    float x = (i - radius) / radius;
                     int ratio = static_cast<int>(
                             std::floor(255.5f * std::sqrt(x * x + y * y)));
                     if (ratio > 255) {
@@ -472,6 +451,7 @@
                 }
             }
             break;
+
         case SWF::FILL_FOCAL_GRADIENT:
             // Focal gradient.
             im.reset(new ImageRGBA(64, 64));
@@ -617,8 +597,8 @@
     assert(!gradients.empty());
     
     // We must ensure that all gradients have more than one colour stop
-    // because asking the renderer to render a gradient with one colour
-    // leads to problems.
+    // because asking renderers to render a gradient with one colour
+    // can cause them to invoke UB.
     if (gradients.size() < 2) {
         setSolid(gradients[0].m_color);
         return;
@@ -638,13 +618,16 @@
     assert(!gradients.empty());
     
     // We must ensure that all gradients have more than one colour stop
-    // because asking the renderer to render a gradient with one colour
-    // leads to problems.
+    // because asking renderers to render a gradient with one colour
+    // can cause them to invoke UB.
     if (gradients.size() < 2) {
         setSolid(gradients[0].m_color);
         return;
     }
     
+    m_type = SWF::FILL_RADIAL_GRADIENT;
+    m_gradients = gradients;
+
     _matrix = mat;
     _bitmapInfo = 0;
 }

=== modified file 'libcore/fill_style.h'
--- a/libcore/fill_style.h      2010-01-13 08:19:25 +0000
+++ b/libcore/fill_style.h      2010-01-20 06:19:48 +0000
@@ -55,13 +55,12 @@
     void read(SWFStream& in, SWF::TagType tag);
     
     //data:
-    boost::uint8_t    m_ratio;
-    rgba    m_color;
+    boost::uint8_t m_ratio;
+    rgba m_color;
 };
 
 
 /// For the interior of outline shapes.
-//
 class DSOEXPORT fill_style 
 {
 public:

=== modified file 'testsuite/actionscript.all/TextFormat.as'
--- a/testsuite/actionscript.all/TextFormat.as  2010-01-13 08:21:36 +0000
+++ b/testsuite/actionscript.all/TextFormat.as  2010-01-19 17:38:27 +0000
@@ -58,8 +58,8 @@
 // When you construct a TextFormat w/out args all members
 // are of the 'null' type. In general, uninitialized members
 // are all of the 'null' type.
-xcheck_equals(typeof(tfObj.display), 'string');
-xcheck_equals(tfObj.display, 'block');
+check_equals(typeof(tfObj.display), 'string');
+check_equals(tfObj.display, 'block');
 check_equals(typeof(tfObj.bullet), 'null');
 check_equals(typeof(tfObj.tabStops), 'null');
 check_equals(typeof(tfObj.blockIndent), 'null');
@@ -80,8 +80,8 @@
 
 // new TextFormat([font, [size, [color, [bold, [italic, [underline, [url, 
[target, [align,[leftMargin, [rightMargin, [indent, [leading]]]]]]]]]]]]])
 tfObj = new TextFormat("fname", 2, 30, true, false, true, 'http', 'tgt', 
'cEnter', '23', '32', 12, 4);
-xcheck_equals(typeof(tfObj.display), 'string');
-xcheck_equals(tfObj.display, 'block');
+check_equals(typeof(tfObj.display), 'string');
+check_equals(tfObj.display, 'block');
 check_equals(typeof(tfObj.bullet), 'null');
 check_equals(typeof(tfObj.tabStops), 'null');
 check_equals(typeof(tfObj.blockIndent), 'null');
@@ -103,6 +103,156 @@
 check_equals(tfObj.font, 'fname');
 
 
+/// Bold
+
+// The boolean conversion of a string is version dependent.
+stringbool = "string" ? true : false;
+
+tf = new TextFormat();
+check_equals(tf.bold, null);
+tf.bold = true;
+check_equals(tf.bold, true);
+tf.bold = false;
+check_equals(tf.bold, false);
+tf.bold = "string";
+check_equals(tf.bold, stringbool);
+tf.bold = null;
+check_equals(tf.bold, null);
+tf.bold = "string";
+check_equals(tf.bold, stringbool);
+tf.bold = undefined;
+check_equals(tf.bold, null);
+
+
+// rightMargin
+tf = new TextFormat();
+check_equals(tf.rightMargin, null);
+tf.rightMargin = 10;
+check_equals(tf.rightMargin, 10);
+tf.rightMargin = -10;
+check_equals(tf.rightMargin, 0);
+tf.rightMargin = "string";
+check_equals(tf.rightMargin, 0);
+tf.rightMargin = null;
+check_equals(tf.rightMargin, null);
+tf.rightMargin = "string";
+check_equals(tf.rightMargin, 0);
+tf.rightMargin = undefined;
+check_equals(tf.rightMargin, null);
+
+// leftMargin
+tf = new TextFormat();
+check_equals(tf.leftMargin, null);
+tf.leftMargin = 10;
+check_equals(tf.leftMargin, 10);
+tf.leftMargin = -10;
+check_equals(tf.leftMargin, 0);
+tf.leftMargin = "string";
+check_equals(tf.leftMargin, 0);
+tf.leftMargin = null;
+check_equals(tf.leftMargin, null);
+tf.leftMargin = "string";
+check_equals(tf.leftMargin, 0);
+tf.leftMargin = undefined;
+check_equals(tf.leftMargin, null);
+
+// blockIndent
+tf = new TextFormat();
+check_equals(tf.blockIndent, null);
+tf.blockIndent = 10;
+check_equals(tf.blockIndent, 10);
+tf.blockIndent = -10;
+
+#if OUTPUT_VERSION < 8
+check_equals(tf.blockIndent, 0);
+#else
+xcheck_equals(tf.blockIndent, -10);
+#endif
+
+tf.blockIndent = "string";
+#if OUTPUT_VERSION < 8
+check_equals(tf.blockIndent, 0);
+#else
+xcheck_equals(tf.blockIndent, -2147483648);
+#endif
+
+tf.blockIndent = null;
+check_equals(tf.blockIndent, null);
+
+tf.blockIndent = "string";
+#if OUTPUT_VERSION < 8
+check_equals(tf.blockIndent, 0);
+#else
+xcheck_equals(tf.blockIndent, -2147483648);
+#endif
+tf.blockIndent = undefined;
+check_equals(tf.blockIndent, null);
+
+// leading
+tf = new TextFormat();
+check_equals(tf.leading, null);
+tf.leading = 10;
+check_equals(tf.leading, 10);
+tf.leading = -10;
+
+#if OUTPUT_VERSION < 8
+check_equals(tf.leading, 0);
+#else
+xcheck_equals(tf.leading, -10);
+#endif
+
+tf.leading = "string";
+#if OUTPUT_VERSION < 8
+check_equals(tf.leading, 0);
+#else
+xcheck_equals(tf.leading, -2147483648);
+#endif
+
+tf.leading = null;
+check_equals(tf.leading, null);
+
+tf.leading = "string";
+#if OUTPUT_VERSION < 8
+check_equals(tf.leading, 0);
+#else
+xcheck_equals(tf.leading, -2147483648);
+#endif
+tf.leading = undefined;
+check_equals(tf.leading, null);
+
+// indent
+tf = new TextFormat();
+check_equals(tf.indent, null);
+tf.indent = 10;
+check_equals(tf.indent, 10);
+tf.indent = -10;
+
+#if OUTPUT_VERSION < 8
+check_equals(tf.indent, 0);
+#else
+xcheck_equals(tf.indent, -10);
+#endif
+
+tf.indent = "string";
+#if OUTPUT_VERSION < 8
+check_equals(tf.indent, 0);
+#else
+xcheck_equals(tf.indent, -2147483648);
+#endif
+
+tf.indent = null;
+check_equals(tf.indent, null);
+
+tf.indent = "string";
+#if OUTPUT_VERSION < 8
+check_equals(tf.indent, 0);
+#else
+xcheck_equals(tf.indent, -2147483648);
+#endif
+tf.indent = undefined;
+check_equals(tf.indent, null);
+
+
 // Check tabStops property.
 // The passed array is processed before assignment, not simply stored.
 tf = new TextFormat();
@@ -118,6 +268,10 @@
 xcheck_equals(tf.tabStops.toString(), "6");
 
 tf2 = new TextFormat("Arial", 12);
+
+// Different behaviour.
+#if OUTPUT_VERSION > 6
+
 te = tf2.getTextExtent("Hello");
 
 // The object is a bare object
@@ -134,18 +288,47 @@
 xcheck_equals(Math.round(te.textFieldWidth), 33);
 
 te = tf2.getTextExtent("Hello", 10);
+#if OUTPUT_VERSION > 7
 xcheck_equals(Math.round(te.textFieldHeight), 60);
+#else
+xcheck_equals(Math.round(te.textFieldHeight), 18);
+#endif
+
 xcheck_equals(te.textFieldWidth, 10);
+
+#if OUTPUT_VERSION > 7
 xcheck_equals(Math.round(te.width), 9);
+#else
+xcheck_equals(Math.round(te.width), 29);
+#endif
+
 
 te = tf2.getTextExtent("Hello", 5);
+#if OUTPUT_VERSION > 7
 xcheck_equals(Math.round(te.textFieldHeight), 74);
+#else
+xcheck_equals(Math.round(te.textFieldHeight), 18);
+#endif
 xcheck_equals(te.textFieldWidth, 5);
-// Width of largest character?
+
+
+#if OUTPUT_VERSION > 7
+// Width of largest character in version 8?
 xcheck_equals(Math.round(te.width), 9);
+#else
+xcheck_equals(Math.round(te.width), 29);
+#endif
 
 te = tf2.getTextExtent("Longer sentence with more words.", 30);
 xcheck_equals(te.textFieldWidth, 30);
 xcheck_equals(Math.round(te.width), 25);
 
-check_totals(81);
+#endif
+
+#if OUTPUT_VERSION < 7
+    check_totals(107);
+#elif OUTPUT_VERSION == 7
+    check_totals(123);
+#else 
+    check_totals(123);
+#endif

=== modified file 'testsuite/misc-ming.all/DrawingApiTest.as'
--- a/testsuite/misc-ming.all/DrawingApiTest.as 2009-07-08 10:57:35 +0000
+++ b/testsuite/misc-ming.all/DrawingApiTest.as 2010-01-20 09:52:21 +0000
@@ -10,8 +10,8 @@
 //
 // Click the mouse button to turn the cursor shape into a mask and back.
 // Press a number on the keyboard to switch between "pages" of the drawing.
-// We currently have two pages: 1 and 2.
-// Only page 1 have automatic testing so far.
+// We currently have pages 1, 2, 3, 4.
+// All pages are tested automatically.
 //
 // '-' and '+' decrement and increment _alpha
 // 'h' toggles _visible
@@ -20,6 +20,9 @@
 
 #include "../actionscript.all/check.as"
 
+// Make Matrix visible for easier gradient tests.
+ASSetPropFlags(_global, "flash", 0, 5248);
+
 printBounds = function(b)
 {
        return ''+Math.round(b.xMin*100)/100+','+Math.round(b.yMin*100)/100+' 
'+Math.round(b.xMax*100)/100+','+Math.round(b.yMax*100)/100;
@@ -741,6 +744,155 @@
 check(line.hitTest(230, 80, true));
 
 
+// Page 4 ( page[3] )
+
+draw100x100Box = function(x, y, mc) {
+    s = 90;
+    with (mc) {
+        moveTo(x, y);
+        lineTo(x + s, y);
+        lineTo(x + s, y + s);
+        lineTo(x, y + s);
+        lineTo(x, y);
+        endFill();
+    };
+};
+    
+
+createEmptyMovieClip("grad", 150);
+
+// Test gradients.
+// The beginGradientFill function works with fake Matrices, but there is no
+// point making more work for ourselves as that testing is already done for
+// the Matrix class.
+// Only the "box" matrixType gets special handling.
+
+with(grad) {
+
+    // Linear gradients
+    fillType = "linear";
+
+    x = 0;
+    y = 0;
+
+    // shape 1
+    colors = [0x0000ff, 0xffffff];
+    alphas = [100, 100];
+    ratios = [0, 0xff];
+    matrix = new flash.geom.Matrix();
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+    
+    // shape 2
+    x += 100;
+    colors = [0x0000ff, 0xffffff];
+    alphas = [100, 100];
+    ratios = [0, 0xff];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+    
+    // shape 3
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0xff00ff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xff / 2, 0xff];
+    matrix.createGradientBox(90, 90, Math.PI / 4, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // shape 4
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0xff00ff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xff / 2, 0xff];
+    matrix.createGradientBox(180, 180, Math.PI / 4, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // shape 5
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0x00ff00];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xff / 2, 0xff];
+    matrix.createGradientBox(180, 180, Math.PI / 4 * 3, x - 90, y - 90);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // shape 6
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0x00ff00, 0xff00ff, 0x00ffff, 0xffff00 ];
+    alphas = [100, 100, 100, 50, 25, 100];
+    ratios = [0, 0xff / 5, 0xff / 5 * 2, 0xff / 5 * 3, 0xff / 5 * 4, 0xff];
+    matrix.createGradientBox(90, 90, Math.PI / 2, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+ 
+    // Radial gradients
+    fillType = "radial";
+
+    x = 0;
+    y += 100;
+
+    // shape 7
+    colors = [0x0000ff, 0xffffff];
+    alphas = [100, 100];
+    ratios = [0, 0xff];
+    matrix = new flash.geom.Matrix();
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+    
+    // shape 8
+    x += 100;
+    colors = [0x0000ff, 0xffffff];
+    alphas = [100, 100];
+    ratios = [0, 0xff];
+    matrix.createGradientBox(90, 90, 0, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+    
+    // shape 9
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0xff00ff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xff / 2, 0xff];
+    matrix.createGradientBox(90, 90, Math.PI / 4, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // shape 10
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0xff00ff];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xff / 2, 0xff];
+    matrix.createGradientBox(180, 180, Math.PI / 4, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // shape 11
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0x00ff00];
+    alphas = [100, 100, 100];
+    ratios = [0, 0xff / 2, 0xff];
+    matrix.createGradientBox(180, 180, Math.PI / 4 * 3, x - 90, y - 90);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+    // shape 12
+    x += 100;
+    colors = [0x0000ff, 0xffffff, 0x00ff00, 0xff00ff, 0x00ffff, 0xffff00 ];
+    alphas = [100, 100, 100, 50, 25, 100];
+    ratios = [0, 0xff / 5, 0xff / 5 * 2, 0xff / 5 * 3, 0xff / 5 * 4, 0xff];
+    matrix.createGradientBox(90, 90, Math.PI / 2, x, y);
+    beginGradientFill(fillType, colors, alphas, ratios, matrix);
+    draw100x100Box(x, y, grad);
+
+   
+    _visible = false;
+
+};
+grad.onRollOver = function() {};
+
 //---------------------------------------------------------------------------
 //
 //---------------------------------------------------------------------------
@@ -874,6 +1026,8 @@
 page[0] = a;
 page[1] = inv;
 page[2] = line;
+page[3] = grad;
+
 onKeyDown = function()
 {
        var ascii = Key.getAscii();

=== modified file 'testsuite/misc-ming.all/DrawingApiTestRunner.cpp'
--- a/testsuite/misc-ming.all/DrawingApiTestRunner.cpp  2010-01-01 17:48:26 
+0000
+++ b/testsuite/misc-ming.all/DrawingApiTestRunner.cpp  2010-01-20 10:35:43 
+0000
@@ -866,6 +866,138 @@
     // Top right corner (yellow line)
     check_pixel(x + w, y, 2, yellow, 2);
 
+    // Test picture 4
+       tester.pressKey(gnash::key::_4); tester.advance();
+
+    // The shapes are 90x90, spaced in a 100x100 pixel grid with 6 shapes in
+    // each row.
+
+    x = 0;
+    y = 0;
+
+    // Shape 1
+    // Check each corner. The gradient is much too spread out, so should be
+    // practically the same blue-white everywhere.
+    rgba lightblue(120, 129, 248, 255);
+    check_pixel(x + 2, y + 2, 2, lightblue, 2);
+    check_pixel(x + 2, y + 90 - 2, 2, lightblue, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, lightblue, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, lightblue, 2);
+
+    // Shape 2
+    // Check each corner
+    x += 100;
+    check_pixel(x + 2, y + 2, 2, blue, 2);
+    check_pixel(x + 2, y + 90 - 2, 2, blue, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, white, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, white, 2);
+    
+    // Shape 3
+    // Check each corner
+    x += 100;
+    check_pixel(x + 2, y + 2, 2, blue, 2);
+    check_pixel(x + 2, y + 90 - 2, 2, white, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, white, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, violet, 2);
+    
+    // Shape 4
+    // Check each corner
+    x += 100;
+    rgba whiteblue(70,70,248,255);
+    check_pixel(x + 2, y + 2, 2, blue, 2);
+    check_pixel(x + 2, y + 90 - 2, 2, whiteblue, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, whiteblue, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, white, 2);
+
+    // Shape 5
+    // Check each corner
+    x += 100;
+    rgba whitegreen(80,248,80,255);
+    check_pixel(x + 2, y + 2, 2, white, 2);
+    check_pixel(x + 2, y + 90 - 2, 2, whitegreen, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, whiteblue, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, white, 2);
+
+    // Shape 6
+    // Check each row
+    x += 100;
+    int row = 90 / 5;
+    check_pixel(x + 45, y + 1, 2, blue, 2);
+    check_pixel(x + 45, y + row, 2, white, 2);
+    check_pixel(x + 45, y + row * 2, 2, green, 2);
+
+    // Note that these two have a lower alpha value and the rgba value we
+    // expect is that combined with the white background and surrounding
+    // fill colours..
+    check_pixel(x + 45, y + row * 3, 2, rgba(240,120,244,255), 2);
+    check_pixel(x + 45, y + row * 4 , 2, rgba(184,240,240,255), 2);
+    
+    // I'm fairly sure this should be plain yellow, but we render it with
+    // alpha.
+    xcheck_pixel(x + 45, y + 89, 2, yellow, 2);
+
+    y += 100;
+    x = 0;
+
+    // Shape 7
+    // Check each corner and centre. The gradient is much too spread out,
+    // so should be almost the same blue-white everywhere.
+    rgba otherblue(24,24,248,255);
+    rgba otherblue2(56,56,248,255);
+    check_pixel(x + 2, y + 2, 2, otherblue, 2);
+    check_pixel(x + 2, y + 90 - 2, 2, otherblue2, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, otherblue, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, otherblue2, 2);
+    check_pixel(x + 45, y + 45, 2, otherblue, 2);
+
+    // Shape 8
+    x += 100;
+    check_pixel(x + 2, y + 2, 2, white, 2);
+    check_pixel(x + 2, y + 90 - 2, 2, white, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, white, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, white, 2);
+    check_pixel(x + 45, y + 45, 2, blue, 2);
+    
+    // Shape 9
+    x += 100;
+    check_pixel(x + 2, y + 2, 2, violet, 2);
+    check_pixel(x + 2, y + 90 - 2, 2, violet, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, violet, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, violet, 2);
+    check_pixel(x + 45, y + 45, 2, blue, 2);
+    // Inner white circle
+    check_pixel(x + 45, y + 45 / 2, 2, white, 2)
+
+    // Shape 10
+    x += 100;
+    check_pixel(x + 2, y + 2, 2, violet, 2);
+    check_pixel(x + 2, y + 90 - 2, 2, violet, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, violet, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, blue, 2);
+    
+    check_pixel(x + 90, y + 45, 2, white, 2);
+    check_pixel(x + 45, y + 90, 2, white, 2);
+
+    
+    // Shape 11
+    x += 100;
+    check_pixel(x + 2, y + 2, 2, blue, 2);
+    check_pixel(x + 2, y + 90 - 2, 2, green, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, green, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, green, 2);
+    
+    check_pixel(x + 45, y + 1, 2, white, 2);
+    check_pixel(x + 1, y + 45, 2, white, 2);
+    
+    // Shape 12
+    x += 100;
+    check_pixel(x + 2, y + 2, 2, yellow, 2);
+    check_pixel(x + 2, y + 90 - 2, 2, yellow, 2);
+    check_pixel(x + 90 - 2, y + 2, 2, yellow, 2);
+    check_pixel(x + 90 - 2, y + 90 - 2, 2, yellow, 2);
+    check_pixel(x + 45, y + 45, 2, blue, 2);
+
+
     //----------------------------------------------------------
        // TODO: check startDrag/stopDrag on the hit detector
        // (hit 'd' key to toggle)


reply via email to

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