/* Copyright (c) 2009-2010 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;
OWF_ASSERT(context);
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