graphicscomposition/openwfcompositionengine/composition/src/wfcelement.c
author Faisal Memon <faisal.memon@nokia.com>
Fri, 25 Jun 2010 17:49:58 +0100
branchEGL_MERGE
changeset 105 158b2308cc08
parent 0 5d03bc08d59c
child 36 01a6848ebfd7
child 139 975c90a56547
child 163 bbf46f59e123
permissions -rw-r--r--
Fix def files so that the implementation agnostic interface definition has no non-standards defined entry points, and change the eglrefimpl specific implementation to place its private entry points high up in the ordinal order space in the implementation region, not the standards based entrypoints region.

/* 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