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