graphicscomposition/openwfcompositionengine/composition/src/wfcelement.c
changeset 0 5d03bc08d59c
child 36 01a6848ebfd7
child 139 975c90a56547
child 163 bbf46f59e123
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicscomposition/openwfcompositionengine/composition/src/wfcelement.c	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,1207 @@
+/* Copyright (c) 2009 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ */
+/*! \ingroup wfc
+ *  \file wfcelement.c
+ *
+ *  \brief SI Element handling
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#include <WF/wfc.h>
+
+#include "wfcelement.h"
+#include "wfccontext.h"
+#include "wfcdevice.h"
+#include "wfcstructs.h"
+#include "wfcimageprovider.h"
+#include "owfnativestream.h"
+#include "owfattributes.h"
+#include "owfmemory.h"
+#include "owfobject.h"
+
+#include "owfdebug.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FIRST_ELEMENT_HANDLE    3000
+
+#define FAIL_IF(c,e)        if (c) { return e; }
+
+
+static const WFCbitfield    validTransparencyModes[] = {
+                                WFC_TRANSPARENCY_NONE,
+                                WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA,
+                                WFC_TRANSPARENCY_SOURCE,
+                                WFC_TRANSPARENCY_MASK,
+                                WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA |
+                                    WFC_TRANSPARENCY_SOURCE,
+                                WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA |
+                                    WFC_TRANSPARENCY_MASK
+                            };
+
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+void
+WFC_Element_Initialize(WFC_ELEMENT* element)
+{
+    element->dstRect[0]         = 0;
+    element->dstRect[1]         = 0;
+    element->dstRect[2]         = 0;
+    element->dstRect[3]         = 0;
+    element->srcRect[0]         = 0;
+    element->srcRect[1]         = 0;
+    element->srcRect[2]         = 0;
+    element->srcRect[3]         = 0;
+
+    element->source             = WFC_INVALID_HANDLE;
+    element->sourceFlip         = WFC_FALSE;
+    element->sourceRotation     = WFC_ROTATION_0;
+    element->sourceScaleFilter  = WFC_SCALE_FILTER_NONE;
+    element->transparencyTypes  = 0;
+    element->globalAlpha        = OWF_ALPHA_MAX_VALUE;
+    element->maskHandle         = WFC_INVALID_HANDLE;
+    element->sourceHandle       = WFC_INVALID_HANDLE;
+}
+
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL void
+WFC_Element_Destroy(WFC_ELEMENT* element)
+{
+    if (element)
+    {
+        DPRINT(("WFC_Element_Destroy"));
+
+        DPRINT(("  element = %p (%d)", element, element->handle));
+
+        DESTROY(element->cachedSource);
+        DESTROY(element->cachedMask);
+
+        DPRINT(("  cachedSource = %p (%d)", element->cachedSource,
+                                            element->cachedSource ?
+                                                element->cachedSource->handle :
+                                                0));
+        DPRINT(("  cachedMask = %p (%d)", element->cachedMask,
+                                          element->cachedMask ?
+                                              element->cachedMask->handle :
+                                              0));
+
+        DESTROY(element->source);
+        DESTROY(element->mask);
+
+        DPRINT(("  source = %p (%d)", element->source,
+                                      element->source ?
+                                          element->source->handle :
+                                          0));
+        DPRINT(("  mask = %p (%d)", element->mask,
+                                    element->mask ?
+                                        element->mask->handle :
+                                        0));
+        DESTROY(element->context);
+
+        OWF_Pool_PutObject(element);
+    }
+}
+
+/*---------------------------------------------------------------------------
+ *  Create new element into context
+ *
+ *  \param context Context into which to create the element
+ *
+ *  \return New element object or NULL
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL WFC_ELEMENT*
+WFC_Element_Create(WFC_CONTEXT* context)
+{
+    static WFCint           nextElementHandle = FIRST_ELEMENT_HANDLE;
+    WFC_ELEMENT*            element;
+
+    element = (WFC_ELEMENT*)OWF_Pool_GetObject(context->elementPool);
+
+    if (element)
+    {
+        WFC_Element_Initialize(element);
+
+        element->handle = nextElementHandle++;
+
+        ADDREF(element->context, context);
+        element->device = context->device;
+    }
+    return element;
+}
+
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL WFC_ELEMENT*
+WFC_Element_Clone(WFC_ELEMENT* element)
+{
+    WFC_ELEMENT*        clone;
+    WFC_CONTEXT*        context;
+
+    OWF_ASSERT(element);
+
+    DPRINT(("WFC_Element_Clone: element = %d, context = %d", element->handle,
+            element->context->handle));
+
+    context = CONTEXT(element->context);
+    clone = (WFC_ELEMENT*)OWF_Pool_GetObject(context->elementPool);
+
+    if (clone)
+    {
+        WFC_Element_Initialize(clone);
+
+        clone->handle           = element->handle;
+
+        clone->sourceFlip       = element->sourceFlip;
+        clone->sourceRotation   = element->sourceRotation;
+        clone->sourceScaleFilter= element->sourceScaleFilter;
+        clone->transparencyTypes= element->transparencyTypes;
+        clone->globalAlpha      = element->globalAlpha;
+        clone->maskHandle       = element->maskHandle;
+        clone->sourceHandle     = element->sourceHandle;
+
+        ADDREF(clone->cachedMask, element->cachedMask);
+        ADDREF(clone->cachedSource, element->cachedSource);
+
+        ADDREF(clone->mask,     element->mask);
+        ADDREF(clone->source,   element->source);
+        clone->device = element->device;
+
+        ADDREF(clone->context,  element->context);
+
+        memcpy(clone->srcRect,  element->srcRect, 4 * sizeof(WFCfloat));
+        memcpy(clone->dstRect,  element->dstRect, 4 * sizeof(WFCfloat));
+
+    }
+
+    return clone;
+}
+
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+static WFCboolean WFC_Element_ClampRectangle(const char* rtype,
+                                             WFCfloat* rect)
+{
+    /*
+     * int -> float conversion:
+     * ------------------------
+     *
+     * above 2^24 we start to lose precision when performing
+     * conversions between floats & ints, thus we must clamp
+     * values above in order to avoid nasty sign-change effects
+     * and other weird side-effects.
+     *
+     */
+
+    const WFCfloat          LIMIT = 1.6777216E7f;
+    WFCint                  i;
+    WFCboolean              clamped = WFC_FALSE;
+
+    /* Prevent compiler warning when DPRINT is disabled */
+    (void) rtype;
+
+    for (i = 0; i < 4; i++)
+    {
+        if (fabs(rect[i]) > LIMIT)
+        {
+#ifdef DEBUG
+            static const char* coord[4] = {"x", "y", "width", "height"};
+            (void)coord[0];
+#endif
+
+            DPRINT(("  Warning: Precision loss in element's %s rectangle's "
+                    "%s coordinate.",
+                    rtype, coord[i]));
+
+            rect[i] = rect[i] < 0 ? -LIMIT : LIMIT;
+
+            clamped = WFC_TRUE;
+        }
+    }
+    return clamped;
+}
+/*===========================================================================
+ *
+ * Attribute set-time checking functions. These are used for checking
+ * the attributes before saving them into elements. Attributes are validated
+ * for 2nd time during commit, where e.g. destination rectangle size vs.
+ * mask size dependency is checked.
+ *
+ *============================================================================*/
+
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+static WFCErrorCode
+WFC_Element_ValidateSourceRectangle(WFC_ELEMENT* element,
+                                    WFCfloat* rect)
+{
+    WFCErrorCode            result = WFC_ERROR_NONE;
+    
+#ifndef DEBUG
+    (void) element;
+#endif    
+
+    OWF_ASSERT(element);
+    OWF_ASSERT(rect);
+
+    if (rect[0] < 0.0f || rect[1] < 0.0f || rect[2] < 0.0f || rect[3] < 0.0f)
+    {
+        result = WFC_ERROR_ILLEGAL_ARGUMENT;
+    }
+    else if (WFC_Element_ClampRectangle("source", rect))
+    {
+        result = WFC_ERROR_NONE;
+    }
+    return result;
+}
+
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+static WFCErrorCode
+WFC_Element_ValidateDestinationRectangle(WFC_ELEMENT* element,
+                                         WFCfloat* rect)
+{
+    WFCErrorCode            result = WFC_ERROR_NONE;
+
+#ifndef DEBUG
+    (void) element;
+#endif    
+    
+    OWF_ASSERT(element);
+    OWF_ASSERT(rect);
+
+    DPRINT(("WFC_Element_ValidateDestinationRectangle(element = %d)",
+            element->handle));
+
+    if (rect[2] < 0.0f || rect[3] < 0.0f)
+    {
+        result = WFC_ERROR_ILLEGAL_ARGUMENT;
+    }
+    else if (WFC_Element_ClampRectangle("destination", rect))
+    {
+        /* ... return error or something here? */
+        result = WFC_ERROR_NONE;
+    }
+
+    /* Hmm.. let's clamp the rectangle even more! To 16k*16k at max;
+     * in OWF_Image_Create we calculate the byte size of the image buffer
+     * required, and if we have 4bpp, we get overflow for pixelcounts
+     * >= 65536*16384. */
+    rect[2] = CLAMP(rect[2], 0, 16384);
+    rect[3] = CLAMP(rect[3], 0, 16384);
+
+    return result;
+}
+
+#define BOOLEAN_TO_ERROR(x) ((x) ? WFC_ERROR_NONE : WFC_ERROR_ILLEGAL_ARGUMENT)
+
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+static WFCErrorCode
+WFC_Element_ValidateScalarAttributei(WFC_ELEMENT* element,
+                                     WFCElementAttrib attrib,
+                                     WFCint value)
+{
+    WFCErrorCode            result = WFC_ERROR_NONE;
+
+    OWF_ASSERT(element);
+
+    switch (attrib)
+    {
+        case WFC_ELEMENT_SOURCE:
+        {
+            WFC_IMAGE_PROVIDER* source;
+
+            source = WFC_Device_FindImageProvider(element->device,
+                                                  value,
+                                                  WFC_IMAGE_SOURCE);
+
+            result = BOOLEAN_TO_ERROR((WFC_INVALID_HANDLE == value) ||
+                                      ((WFC_INVALID_HANDLE != value) &&
+                                       (NULL != source)));
+            break;
+        }
+
+        case WFC_ELEMENT_MASK:
+        {
+            WFC_IMAGE_PROVIDER* mask;
+
+            mask = WFC_Device_FindImageProvider(element->device,
+                                                value,
+                                                WFC_IMAGE_MASK);
+
+            result = BOOLEAN_TO_ERROR((WFC_INVALID_HANDLE == value) ||
+                                      ((WFC_INVALID_HANDLE != value) &&
+                                       (NULL != mask)));
+            break;
+        }
+
+        case WFC_ELEMENT_SOURCE_ROTATION:
+        {
+            WFCRotation rotation = (WFCRotation) value;
+
+            result = BOOLEAN_TO_ERROR((WFC_ROTATION_0    == rotation ||
+                                       WFC_ROTATION_90   == rotation ||
+                                       WFC_ROTATION_180  == rotation ||
+                                       WFC_ROTATION_270  == rotation));
+            break;
+        }
+
+        case WFC_ELEMENT_SOURCE_SCALE_FILTER:
+        {
+            WFCScaleFilter  filter = (WFCScaleFilter) value;
+
+            result = BOOLEAN_TO_ERROR((WFC_SCALE_FILTER_NONE     == filter ||
+                                       WFC_SCALE_FILTER_FASTER   == filter ||
+                                       WFC_SCALE_FILTER_BETTER   == filter));
+            break;
+        }
+
+        case WFC_ELEMENT_SOURCE_FLIP:
+        {
+            WFCboolean  flip = (WFCboolean) value;
+
+            result = BOOLEAN_TO_ERROR((WFC_TRUE == flip ||
+                                       WFC_FALSE == flip));
+            break;
+        }
+
+        case WFC_ELEMENT_TRANSPARENCY_TYPES:
+        {
+            WFCint          ii;
+            WFCint          count = sizeof(validTransparencyModes) /
+                                    sizeof(WFCbitfield);
+            WFCbitfield     types = (WFCbitfield) value;
+
+            result = WFC_ERROR_ILLEGAL_ARGUMENT;
+            for (ii = 0; ii < count; ii++) {
+                if (types == validTransparencyModes[ii])
+                {
+                    result = WFC_ERROR_NONE;
+                    break;
+                }
+            }
+            break;
+        }
+
+        default:
+        {
+            result = WFC_ERROR_BAD_ATTRIBUTE;
+            break;
+        }
+    }
+    return result;
+}
+
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+static WFCErrorCode
+WFC_Element_ValidateScalarAttributef(WFC_ELEMENT* element,
+                                     WFCElementAttrib attrib,
+                                     WFCfloat value)
+{
+    WFCErrorCode          result = WFC_ERROR_NONE;
+
+#ifndef DEBUG
+    (void) element;
+#endif
+    
+    OWF_ASSERT(element);
+
+    switch (attrib)
+    {
+        case WFC_ELEMENT_GLOBAL_ALPHA:
+        {
+            result = BOOLEAN_TO_ERROR(value >= OWF_ALPHA_MIN_VALUE &&
+                                      value <= OWF_ALPHA_MAX_VALUE);
+            break;
+        }
+
+        /* SPECIAL CASES */
+        case WFC_ELEMENT_SOURCE_FLIP:
+        case WFC_ELEMENT_SOURCE_ROTATION:
+        case WFC_ELEMENT_SOURCE_SCALE_FILTER:
+        case WFC_ELEMENT_TRANSPARENCY_TYPES:
+        case WFC_ELEMENT_SOURCE:
+        case WFC_ELEMENT_MASK:
+        {
+            /* NOTE! special early out here. */
+            result = WFC_ERROR_BAD_ATTRIBUTE;
+            break;
+        }
+
+        default:
+        {
+            result = WFC_ERROR_ILLEGAL_ARGUMENT;
+            break;
+        }
+    }
+
+    return result;
+}
+
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+static void
+WFC_Element_SetElementImageProvider(WFC_ELEMENT* element,
+                                    WFC_IMAGE_PROVIDER_TYPE type,
+                                    WFCHandle handle)
+{
+    WFC_IMAGE_PROVIDER*     provider;
+
+    OWF_ASSERT(element);
+
+    provider = WFC_Device_FindImageProvider(element->device, handle, type);
+
+    switch (type)
+    {
+        case WFC_IMAGE_SOURCE:
+        {
+            DESTROY(element->cachedSource);
+            ADDREF(element->cachedSource, provider);
+            element->sourceHandle = handle;
+            break;
+        }
+        case WFC_IMAGE_MASK:
+        {
+            DESTROY(element->cachedMask);
+            ADDREF(element->cachedMask, provider);
+            element->maskHandle = handle;
+            break;
+        }
+    }
+}
+
+/*---------------------------------------------------------------------------
+ *  \brief Set vector integer attribute for an element
+ *
+ *  \param element          Element
+ *  \param attrib           Attribute name
+ *  \param count            Attribute size
+ *  \param values           Attribute vector value
+ *
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL WFCErrorCode
+WFC_Element_SetAttribiv(WFC_ELEMENT* element,
+                        WFCElementAttrib attrib,
+                        WFCint count,
+                        const WFCint* values)
+{
+    WFCErrorCode            result = WFC_ERROR_NONE;
+
+
+    FAIL_IF(NULL == values, WFC_ERROR_ILLEGAL_ARGUMENT);
+
+    switch (attrib)
+    {
+        /* Vector attributes */
+        case WFC_ELEMENT_SOURCE_RECTANGLE:
+        case WFC_ELEMENT_DESTINATION_RECTANGLE:
+        {
+            WFCfloat                rect[4];
+
+            rect[0] = values[0];
+            rect[1] = values[1];
+            rect[2] = values[2];
+            rect[3] = values[3];
+
+            result = WFC_Element_SetAttribfv(element, attrib, count, rect);
+            break;
+        }
+
+        case WFC_ELEMENT_GLOBAL_ALPHA:
+        {
+            WFCfloat    fvalue = values[0] /
+                                 (WFCfloat) OWF_BYTE_MAX_VALUE;
+
+            result = WFC_Element_SetAttribfv(element,
+                                             attrib,
+                                             1,
+                                             &fvalue);
+            break;
+        }
+
+        /* Scalar attributes */
+        default:
+        {
+            WFCint          value;
+
+            FAIL_IF(1 != count, WFC_ERROR_ILLEGAL_ARGUMENT);
+
+            value = values[0];
+
+            /* Validate the value thus ensuring it is safe to change it */
+            result = WFC_Element_ValidateScalarAttributei(element,
+                                                          attrib,
+                                                          value);
+            if (WFC_ERROR_NONE != result)
+            {
+                break;
+            }
+
+            switch (attrib)
+            {
+                case WFC_ELEMENT_SOURCE:
+                {
+                    WFC_Element_SetElementImageProvider(element,
+                                                        WFC_IMAGE_SOURCE,
+                                                        value);
+                    break;
+                }
+                case WFC_ELEMENT_MASK:
+                {
+                    WFC_Element_SetElementImageProvider(element,
+                                                        WFC_IMAGE_MASK,
+                                                        value);
+                    break;
+                }
+                case WFC_ELEMENT_SOURCE_FLIP:
+                {
+                    element->sourceFlip = (WFCboolean)value;
+                    break;
+                }
+                case WFC_ELEMENT_SOURCE_ROTATION:
+                {
+                    element->sourceRotation = (WFCRotation)value;
+                    break;
+                }
+                case WFC_ELEMENT_SOURCE_SCALE_FILTER:
+                {
+                    element->sourceScaleFilter = (WFCScaleFilter)value;
+                    break;
+                }
+                case WFC_ELEMENT_TRANSPARENCY_TYPES:
+                {
+                    element->transparencyTypes = value;
+                    break;
+                }
+                default:
+                {
+                    result = WFC_ERROR_BAD_ATTRIBUTE;
+                    break;
+                }
+            }
+            break;
+        }
+    }
+
+    return result;
+}
+
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL WFCErrorCode
+WFC_Element_SetAttribfv(WFC_ELEMENT* element,
+                        WFCElementAttrib attrib,
+                        WFCint count,
+                        const WFCfloat* values)
+{
+    WFCErrorCode            result = WFC_ERROR_NONE;
+
+    FAIL_IF(NULL == values, WFC_ERROR_ILLEGAL_ARGUMENT);
+
+    switch (attrib)
+    {
+        /* Vector attributes */
+        case WFC_ELEMENT_SOURCE_RECTANGLE:
+        case WFC_ELEMENT_DESTINATION_RECTANGLE:
+        {
+            WFCfloat        clamped[4];
+
+            FAIL_IF(4 != count, WFC_ERROR_ILLEGAL_ARGUMENT);
+
+            memcpy(clamped, values, 4 * sizeof(WFCfloat));
+
+            if (WFC_ELEMENT_SOURCE_RECTANGLE == attrib)
+            {
+                /* this clamps the rectangle, in case it has values that
+                 * cause precision loss or other fuzzy behaviour. */
+                result = WFC_Element_ValidateSourceRectangle(element, clamped);
+
+                if (WFC_ERROR_NONE == result)
+                {
+                    memcpy(element->srcRect, clamped, 4 * sizeof(WFCfloat));
+
+                    DPRINT(("  Source rectangle set to (%.2f,%.2f,%.2f,%.2f)",
+                            clamped[0], clamped[1], clamped[2], clamped[3]));
+                }
+                else
+                {
+                    DPRINT(("  Source rectangle (%.2f,%.2f,%.2f,%.2f) is " \
+                            "invalid",
+                            values[0], values[1], values[2], values[3]));
+                }
+            }
+            else
+            {
+                result = WFC_Element_ValidateDestinationRectangle(element,
+                                                                  clamped);
+                if (WFC_ERROR_NONE == result)
+                {
+                    memcpy(element->dstRect, clamped, 4 * sizeof(WFCfloat));
+
+                    DPRINT(("  Destination rectangle set to " \
+                            "(%.2f,%.2f,%.2f,%.2f)",
+                            clamped[0], clamped[1], clamped[2], clamped[3]));
+                }
+                else
+                {
+                    DPRINT(("  Destination rectangle (%.2f,%.2f,%.2f,%.2f) is "
+                            "invalid",
+                            values[0], values[1], values[2], values[3]));
+                }
+            }
+            break;
+        }
+
+        /* scalar attributes */
+        case WFC_ELEMENT_GLOBAL_ALPHA:
+        {
+            /* values[0] must be [0, 1] */
+            WFCfloat        value = values[0];
+
+            /* value is [0, 1] map to [0, OWF_ALPHA_MAX] */
+            value = value * OWF_ALPHA_MAX_VALUE;
+
+            /* validate the value */
+            result = WFC_Element_ValidateScalarAttributef(element,
+                                                          attrib,
+                                                          value);
+
+            if (WFC_ERROR_NONE != result)
+            {
+                /* invalid value for attribute, out we go */
+                break;
+            }
+
+            element->globalAlpha = value;
+            break;
+        }
+
+        default:
+        {
+            result = WFC_ERROR_BAD_ATTRIBUTE;
+            break;
+        }
+    }
+
+    return result;
+}
+
+/*---------------------------------------------------------------------------
+ * Attribute getters
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL WFCErrorCode
+WFC_Element_GetAttribiv(WFC_ELEMENT* element,
+                        WFCElementAttrib attrib,
+                        WFCint count,
+                        WFCint* values)
+{
+    WFCErrorCode            result = WFC_ERROR_NONE;
+
+
+    FAIL_IF(NULL == values, WFC_ERROR_ILLEGAL_ARGUMENT);
+
+    switch (attrib)
+    {
+        /* Vector attributes */
+        case WFC_ELEMENT_SOURCE_RECTANGLE:
+        case WFC_ELEMENT_DESTINATION_RECTANGLE:
+        {
+            WFCfloat        rect[4] = {0.0, 0.0, 0.0, 0.0};
+
+            result = WFC_Element_GetAttribfv(element, attrib, count, rect);
+
+            if (WFC_ERROR_NONE == result)
+            {
+                values[0] = floor(rect[0]);
+                values[1] = floor(rect[1]);
+                values[2] = floor(rect[2]);
+                values[3] = floor(rect[3]);
+            }
+            break;
+        }
+
+        /* Scalar attributes */
+        default:
+        {
+            FAIL_IF(1 != count, WFC_ERROR_ILLEGAL_ARGUMENT);
+
+            switch (attrib)
+            {
+                /* pure int attributes */
+                case WFC_ELEMENT_SOURCE:
+                {
+                    *values = element->sourceHandle;
+                    break;
+                }
+                case WFC_ELEMENT_MASK:
+                {
+                    *values = element->maskHandle;
+                    break;
+                }
+                case WFC_ELEMENT_SOURCE_FLIP:
+                {
+                    *values = element->sourceFlip;
+                    break;
+                }
+                case WFC_ELEMENT_SOURCE_ROTATION:
+                {
+                    *values = element->sourceRotation;
+                    break;
+                }
+                case WFC_ELEMENT_SOURCE_SCALE_FILTER:
+                {
+                    *values = element->sourceScaleFilter;
+                    break;
+                }
+                case WFC_ELEMENT_TRANSPARENCY_TYPES:
+                {
+                    *values = element->transparencyTypes;
+                    break;
+                }
+                case WFC_ELEMENT_GLOBAL_ALPHA:
+                {
+                    WFCfloat    fvalue;
+
+                    WFC_Element_GetAttribfv(element, attrib, 1, &fvalue);
+                    *values = floor(OWF_BYTE_MAX_VALUE * fvalue /
+                                    OWF_ALPHA_MAX_VALUE);
+                    break;
+                }
+                default:
+                {
+                    result = WFC_ERROR_BAD_ATTRIBUTE;
+                    break;
+                }
+            }
+            break;
+        }
+    }
+
+    return result;
+}
+
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL WFCErrorCode
+WFC_Element_GetAttribfv(WFC_ELEMENT* element,
+                        WFCElementAttrib attrib,
+                        WFCint count,
+                        WFCfloat* values)
+{
+    WFCErrorCode            result = WFC_ERROR_NONE;
+
+    FAIL_IF(NULL == values, WFC_ERROR_ILLEGAL_ARGUMENT);
+
+    switch (attrib)
+    {
+        /* Vector attributes */
+        case WFC_ELEMENT_SOURCE_RECTANGLE:
+        case WFC_ELEMENT_DESTINATION_RECTANGLE:
+        {
+            FAIL_IF(4 != count, WFC_ERROR_ILLEGAL_ARGUMENT);
+
+            if (WFC_ELEMENT_SOURCE_RECTANGLE == attrib)
+            {
+                values[0] = element->srcRect[0];
+                values[1] = element->srcRect[1];
+                values[2] = element->srcRect[2];
+                values[3] = element->srcRect[3];
+            }
+            else
+            {
+                values[0] = element->dstRect[0];
+                values[1] = element->dstRect[1];
+                values[2] = element->dstRect[2];
+                values[3] = element->dstRect[3];
+            }
+            break;
+        }
+
+        /* Scalar attributes */
+        default:
+        {
+            switch (attrib)
+            {
+                case WFC_ELEMENT_GLOBAL_ALPHA:
+                {
+                    *values = element->globalAlpha;
+                    break;
+                }
+                default:
+                {
+                    result = WFC_ERROR_BAD_ATTRIBUTE;
+                    break;
+                }
+            }
+            break;
+        }
+    }
+
+    return result;
+}
+
+/*---------------------------------------------------------------------------
+ *  Attribute checkers to use during commit to check element
+ *  for inconsistencies.
+ *----------------------------------------------------------------------------*/
+static WFCboolean
+WFC_Element_CheckAttribute(WFC_ELEMENT* element,
+                           WFCElementAttrib attrib)
+{
+#define VALIDATE_SCALAR_I(v)    \
+    (WFC_Element_ValidateScalarAttributei(element, attrib, v) == \
+            WFC_ERROR_NONE ? WFC_TRUE : WFC_FALSE)
+#define VALIDATE_SCALAR_F(v)    \
+    (WFC_Element_ValidateScalarAttributef(element, attrib, v) == \
+            WFC_ERROR_NONE ? WFC_TRUE : WFC_FALSE)
+
+    WFCboolean              result = WFC_TRUE;
+
+    DPRINT(("WFC_Element_CheckAttribute(%08x,%0x)",
+           element, attrib));
+
+    switch (attrib)
+    {
+        /*
+        INTEGER-ATTRIBUTES
+        */
+        case WFC_ELEMENT_SOURCE:
+        {
+            /* Validated when the attribute was modified */
+            break;
+        }
+
+        case WFC_ELEMENT_MASK:
+        {
+            /* Validated when the attribute was modified */
+            break;
+        }
+
+        case WFC_ELEMENT_SOURCE_FLIP:
+        {
+            result = VALIDATE_SCALAR_I(element->sourceFlip) ? WFC_TRUE: WFC_FALSE;
+            if (!result)
+            {
+                DPRINT(("  Element source flipping is invalid (%d)",
+                        element->sourceFlip));
+            }
+            break;
+        }
+
+        case WFC_ELEMENT_SOURCE_ROTATION:
+        {
+            result = VALIDATE_SCALAR_I(element->sourceRotation) ? WFC_TRUE: WFC_FALSE;
+
+            if (!result)
+            {
+                DPRINT(("  Element source rotation is invalid (%d)",
+                        element->sourceRotation));
+            }
+            break;
+        }
+
+        case WFC_ELEMENT_SOURCE_SCALE_FILTER:
+        {
+            result = VALIDATE_SCALAR_I(element->sourceScaleFilter) ? WFC_TRUE: WFC_FALSE;
+
+            if (!result)
+            {
+                DPRINT(("  Element source scale filter is invalid (%d)",
+                        element->sourceScaleFilter));
+            }
+            break;
+        }
+
+        case WFC_ELEMENT_TRANSPARENCY_TYPES:
+        {
+            result = VALIDATE_SCALAR_I(element->transparencyTypes) ? WFC_TRUE: WFC_FALSE;
+
+            if (!result)
+            {
+                DPRINT(("  Element transparency type is invalid (%x)",
+                        element->transparencyTypes));
+            }
+            break;
+        }
+
+        case WFC_ELEMENT_GLOBAL_ALPHA:
+        {
+            result = VALIDATE_SCALAR_F(element->globalAlpha) ? WFC_TRUE: WFC_FALSE;
+            if (!result)
+            {
+                DPRINT(("  Element global alpha is invalid (%d)",
+                        element->globalAlpha));
+            }
+            break;
+        }
+
+        case WFC_ELEMENT_DESTINATION_RECTANGLE:
+        {
+            WFC_IMAGE_PROVIDER* mask;
+
+            /* The <0 test is repeated in SetAttribfv ValidateDestinationRectangle */
+           if (element->dstRect[2] < 0 || element->dstRect[3] < 0)
+            {
+                DPRINT(("  Element destination rectangle has negative "
+                        "width/height"));
+                result = WFC_FALSE;
+                break;
+            }
+            if (element->maskHandle!=WFC_INVALID_HANDLE)
+            {
+                result = WFC_Element_CheckAttribute(element, WFC_ELEMENT_MASK);
+
+                if (result)
+                {
+                    mask = WFC_Device_FindMask(element->device,
+                                               element->maskHandle);
+                    if (!mask)
+                    {
+                        DPRINT(("  Mask handle is valid, but mask object now destroyed"));
+                        mask=element->cachedMask;
+                        if (!mask)
+                        {
+                            mask=element->mask;
+                        }
+                    }
+                    if (mask)
+                    {
+                        WFCint  maskWidth, maskHeight;
+    
+                        DPRINT(("  Element has a mask"));
+                        /* if the element has a mask, then width & height must match
+                           the dimensions of that mask */
+                        owfNativeStreamGetHeader(mask->streamHandle,&maskWidth, &maskHeight,NULL,NULL,NULL);
+    
+                        if (element->dstRect[2] != maskWidth ||
+                            element->dstRect[3] != maskHeight)
+                        {
+                            DPRINT(("  Mask size (%dx%d) != element size (%d,%d)",
+                                   maskWidth, maskHeight,
+                                   (int)element->dstRect[2],
+                                   (int)element->dstRect[3]));
+                            result = WFC_FALSE;
+                            break;
+                        }
+                    }
+                    else 
+                    {
+                        DPRINT(("  No mask pointers could be opened! Scene not safe!"));
+                        result = WFC_FALSE;
+                    }
+                }
+            }
+            break;
+        }
+
+        case WFC_ELEMENT_SOURCE_RECTANGLE:
+        {
+            WFC_IMAGE_PROVIDER* source;
+
+            result = WFC_Element_CheckAttribute(element, WFC_ELEMENT_SOURCE);
+            
+            if (result && element->sourceHandle!=WFC_INVALID_HANDLE)
+            {   /* no source is valid - the element "will not affect composition results" */
+                source = WFC_Device_FindImageProvider(element->device,
+                                                      element->sourceHandle,
+                                                      WFC_IMAGE_SOURCE);
+    
+                result = WFC_TRUE;
+                if (!source)
+                {
+                    DPRINT(("  Source handle is valid, but source object now destroyed"));
+                    source=element->cachedSource;
+                    if (!source)
+                    {
+                        source=element->source;
+                    }
+                }
+                
+                if (source)
+                {
+                    WFCint  sourceWidth, sourceHeight;
+    
+                    owfNativeStreamGetHeader(source->streamHandle,&sourceWidth, &sourceHeight,NULL,NULL,NULL);
+                    /* The <0 test is repeated in SetAttribfv ValidateSourceRectangle */ 
+                    if ((element->srcRect[0] < 0) ||
+                        (element->srcRect[1] < 0) ||
+                        (element->srcRect[2] < 0) ||
+                        (element->srcRect[3] < 0) ||
+                        (element->srcRect[0] + element->srcRect[2]) > sourceWidth ||
+                        (element->srcRect[1] + element->srcRect[3]) > sourceHeight)
+                    {
+                        DPRINT(("  Source rectangle out of bounds"));
+                        DPRINT(("  (%f,%f,%f,%f), source size %dx%d",
+                               element->srcRect[0], element->srcRect[1],
+                               element->srcRect[2], element->srcRect[3],
+                               sourceWidth, sourceHeight));
+                        result = WFC_FALSE;
+                        break;
+                    }
+                }
+                else
+                {
+                    DPRINT(("  No source pointers could be opened! Scene not safe!"));
+                    result = WFC_FALSE;
+                }
+            }
+            break;
+        }
+
+        case WFC_ELEMENT_FORCE_32BIT:
+        {
+            /* to keep compiler happy */
+            OWF_ASSERT(0);
+            break;
+        }
+    }
+
+    return result;
+
+#undef VALIDATE_SCALAR_F
+#undef VALIDATE_SCALAR_I
+}
+
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL WFCboolean
+WFC_Element_HasConflicts(WFC_ELEMENT* element)
+{
+#define CHECK(x) \
+    if (!WFC_Element_CheckAttribute(element, x)) \
+    {\
+        DPRINT(("Element %d: Conflict in attribute %08x", element->handle, x));\
+        return WFC_TRUE; \
+    }
+
+    CHECK(WFC_ELEMENT_SOURCE);
+    CHECK(WFC_ELEMENT_MASK);
+    CHECK(WFC_ELEMENT_SOURCE_RECTANGLE);
+    CHECK(WFC_ELEMENT_DESTINATION_RECTANGLE);
+    CHECK(WFC_ELEMENT_SOURCE_FLIP);
+    CHECK(WFC_ELEMENT_SOURCE_ROTATION);
+    CHECK(WFC_ELEMENT_SOURCE_SCALE_FILTER);
+    CHECK(WFC_ELEMENT_TRANSPARENCY_TYPES);
+    CHECK(WFC_ELEMENT_GLOBAL_ALPHA);
+
+#undef CHECK
+
+    /* all ok, no conflicts */
+    return WFC_FALSE;
+}
+
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL WFCboolean
+WFC_Element_AffectsCompositionResults(WFC_ELEMENT* element)
+{
+    if (    (element->transparencyTypes&WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA)
+       &&   element->globalAlpha==OWF_FULLY_TRANSPARENT )
+    {
+        return WFC_FALSE;
+    }
+    if (element->sourceHandle==WFC_INVALID_HANDLE)
+    {
+        return WFC_FALSE;
+    }
+    if (element->dstRect[2]==0.0f || element->dstRect[3]==0.0f)
+    {
+        return WFC_FALSE;
+    }
+    if (element->srcRect[2]==0.0f || element->srcRect[3]==0.0f)
+    {
+        return WFC_FALSE;
+    }
+    return WFC_TRUE;
+    
+}
+/*---------------------------------------------------------------------------
+ *
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL void
+WFC_Element_Commit(WFC_ELEMENT* element)
+{
+    OWF_ASSERT(element);
+
+    DPRINT(("WFC_Element_Commit(element = %d)\n", element->handle));
+
+    /* replace source/mask ONLY if it has changed. without these checks,
+     * both source and mask would be overwritten whenever one of them
+     * is changed.
+     */
+
+    if (element->cachedSource != element->source)
+    {
+        element->source = element->cachedSource;
+    }
+
+    if (element->cachedMask != element->mask)
+    {
+        element->mask = element->cachedMask;
+    }
+
+    /* these must be reset now that the element is committed -- the only purpose
+     * of these cached ones is to have source/mask object pointers in the
+     * element so that source/mask can be safely deleted from the device even
+     * if that particular image provider is set as source/mask for some element
+     * that is not yet committed.
+     */
+
+    DPRINT(("  Prior to destroying cached objects:"));
+    DPRINT(("    R(cachedMask) = %d", REFCOUNT(element->cachedMask)));
+    DPRINT(("    R(cachedSource) = %d", REFCOUNT(element->cachedSource)));
+
+    element->cachedSource = NULL;
+    element->cachedMask = NULL;
+
+    DPRINT(("  new source   = %d\n", element->source ?
+                                     element->source->handle : 0));
+    DPRINT(("  new mask     = %d\n", element->mask ?
+                                     element->mask->handle : 0));
+}
+
+
+
+#ifdef __cplusplus
+}
+#endif
+