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: sl@0: /*! \ingroup wfc sl@0: * \file wfcscene.c sl@0: * sl@0: * \brief SI Scene graph management functions. sl@0: */ sl@0: sl@0: #include "WF/wfc.h" sl@0: #include "wfcstructs.h" sl@0: #include "wfcscene.h" sl@0: #include "wfcelement.h" sl@0: #include "wfcimageprovider.h" sl@0: sl@0: #include "owfmemory.h" sl@0: #include "owfarray.h" sl@0: #include "owflinkedlist.h" sl@0: #include "owfobject.h" sl@0: sl@0: #include "owfdebug.h" sl@0: sl@0: /*! sl@0: * \brief Destroy an element. In case the element is marked as shared, sl@0: * this function does nothing. An element is marked as shared, when it is sl@0: * inserted into working copy scene. The marked flag is reset when the element sl@0: * is removed from the context (i.e. it only resides in the device's sl@0: * list of created elements) sl@0: * sl@0: * \param element Element to destroy sl@0: */ sl@0: static void WFC_Scene_DestroyElement(WFC_ELEMENT* element) sl@0: { sl@0: /* elements in the working copy are "read only" because sl@0: * they're shared between the device & the working copy sl@0: */ sl@0: if (!element->shared) sl@0: { sl@0: WFC_Element_Destroy(element); sl@0: } sl@0: } sl@0: sl@0: OWF_API_CALL void sl@0: WFC_Scene_Destroy(WFC_SCENE* scene) sl@0: { sl@0: OWF_NODE* node; sl@0: sl@0: DPRINT(("WFC_Scene_Destroy(%p)", scene)); sl@0: if (scene) sl@0: { sl@0: for (node = scene->elements; NULL != node; node = node->next) sl@0: { sl@0: WFC_Scene_DestroyElement((WFC_ELEMENT*)node->data); sl@0: } sl@0: sl@0: scene->elements = OWF_List_Clear(scene->elements); sl@0: sl@0: DESTROY(scene->context); sl@0: sl@0: OWF_Pool_PutObject(scene); sl@0: } sl@0: } sl@0: sl@0: /*! sl@0: * \brief Append element into scene sl@0: * sl@0: * \param scene Scene sl@0: * \param element Element to add sl@0: */ sl@0: static void sl@0: WFC_Scene_AppendElement(WFC_SCENE* scene, sl@0: WFC_ELEMENT* element) sl@0: { sl@0: OWF_NODE* node; sl@0: sl@0: /* OBS! No duplicate check here! Use with caution*/ sl@0: sl@0: node = OWF_Node_Create(CONTEXT(scene->context)->nodePool, element); sl@0: scene->elements = OWF_List_Append(scene->elements, node); sl@0: return ; sl@0: } sl@0: sl@0: /*----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL WFC_SCENE* sl@0: WFC_Scene_Clone(WFC_SCENE* scene) sl@0: { sl@0: WFC_SCENE* cloneScene; sl@0: OWF_NODE* node; sl@0: sl@0: cloneScene = WFC_Scene_Create(CONTEXT(scene->context)); sl@0: sl@0: for (node = scene->elements; NULL != node; node = node->next) sl@0: { sl@0: WFC_ELEMENT* original; sl@0: WFC_ELEMENT* cloneElem; sl@0: sl@0: original = ELEMENT(node->data); sl@0: if (WFC_Element_AffectsCompositionResults(original)) sl@0: { sl@0: cloneElem = WFC_Element_Clone(original); sl@0: WFC_Scene_AppendElement(cloneScene, cloneElem); sl@0: } sl@0: } sl@0: sl@0: return cloneScene; sl@0: } sl@0: sl@0: /*----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL WFC_SCENE* sl@0: WFC_Scene_Create(WFC_CONTEXT* context) sl@0: { sl@0: WFC_SCENE* scene; sl@0: sl@0: DPRINT(("WFC_Scene_Create")); sl@0: sl@0: OWF_ASSERT(context); sl@0: sl@0: scene = SCENE(OWF_Pool_GetObject(context->scenePool)); sl@0: sl@0: OWF_ASSERT(scene); sl@0: sl@0: ADDREF(scene->context, context); sl@0: sl@0: return scene; sl@0: } sl@0: sl@0: /*----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL WFCErrorCode sl@0: WFC_Scene_InsertElement(WFC_SCENE* scene, sl@0: WFC_ELEMENT* element, sl@0: WFCElement elementBelow) sl@0: { sl@0: WFCErrorCode result = WFC_ERROR_NONE; sl@0: OWF_NODE* iter = NULL; sl@0: OWF_NODE* newPos = NULL; sl@0: OWF_NODE* oldPos = NULL; sl@0: sl@0: if (!scene || !element) sl@0: { sl@0: return WFC_ERROR_ILLEGAL_ARGUMENT; sl@0: } sl@0: sl@0: if (element->handle == (WFCHandle)element) sl@0: { sl@0: /* nothing to do */ sl@0: return WFC_ERROR_NONE; sl@0: } sl@0: sl@0: newPos = NULL; /*scene->elements;*/ sl@0: for (iter = scene->elements; NULL != iter; iter = iter->next) sl@0: { sl@0: WFC_ELEMENT* temp = NULL; sl@0: sl@0: temp = ELEMENT(iter->data); sl@0: sl@0: if (temp->handle == elementBelow) sl@0: { sl@0: /* insertion point found */ sl@0: newPos = iter; sl@0: } sl@0: if (temp->handle == element->handle) sl@0: { sl@0: /* already in the scene; relocate */ sl@0: oldPos = iter; sl@0: } sl@0: } sl@0: sl@0: if (newPos && newPos == oldPos) { sl@0: /* inserting element above self is a no-op */ sl@0: return WFC_ERROR_NONE; sl@0: } sl@0: sl@0: if (!newPos && WFC_INVALID_HANDLE != elementBelow) sl@0: { sl@0: /* could not find elementBelow from the scene */ sl@0: result = WFC_ERROR_ILLEGAL_ARGUMENT; sl@0: } sl@0: else sl@0: { sl@0: OWF_NODE* newNode = NULL; sl@0: sl@0: /* first remove element from its old slot, if already sl@0: * on the list sl@0: */ sl@0: if (NULL != oldPos) sl@0: { sl@0: scene->elements = OWF_List_Remove(scene->elements, oldPos); sl@0: OWF_Node_Destroy(oldPos); sl@0: } sl@0: sl@0: /* allocate new node to insert */ sl@0: newNode = OWF_Node_Create(CONTEXT(scene->context)->nodePool, element); sl@0: if (NULL != newPos) sl@0: { sl@0: /* insert into new position, above elementBelow */ sl@0: OWF_List_InsertAfter(newPos, newNode); sl@0: } sl@0: else sl@0: { sl@0: /* insert on bottom */ sl@0: scene->elements = OWF_List_Insert(scene->elements, newNode); sl@0: } sl@0: } sl@0: sl@0: DPRINT((" Order of the elements (bottom to top): ")); sl@0: for (iter = scene->elements; NULL != iter; iter = iter->next) sl@0: { sl@0: DPRINT((" %d", ELEMENT(iter->data)->handle)); sl@0: } sl@0: return result; sl@0: sl@0: } sl@0: sl@0: /*----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL void sl@0: WFC_Scene_RemoveElement(WFC_SCENE* scene, sl@0: WFCElement element) sl@0: { sl@0: OWF_NODE* node = NULL; sl@0: sl@0: for (node = scene->elements; NULL != node; node = node->next) sl@0: { sl@0: WFC_ELEMENT* etemp; sl@0: sl@0: etemp = ELEMENT(node->data); sl@0: if (etemp->handle == element) sl@0: { sl@0: scene->elements = OWF_List_Remove(scene->elements, node); sl@0: OWF_Node_Destroy(node); sl@0: WFC_Scene_DestroyElement(etemp); sl@0: break; sl@0: sl@0: } sl@0: } sl@0: DPRINT((" Order of the elements (bottom to top): ")); sl@0: for (node = scene->elements; NULL != node; node = node->next) sl@0: { sl@0: DPRINT((" %d", ELEMENT(node->data)->handle)); sl@0: } sl@0: } sl@0: sl@0: /*----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL WFC_ELEMENT* sl@0: WFC_Scene_FindElement(WFC_SCENE* scene, sl@0: WFCElement element) sl@0: { sl@0: OWF_NODE* node = NULL; sl@0: WFC_ELEMENT* result = NULL; sl@0: sl@0: for (node = scene->elements; NULL != node; node = node->next) sl@0: { sl@0: WFC_ELEMENT* etemp; sl@0: sl@0: etemp = ELEMENT(node->data); sl@0: if (etemp->handle == element) sl@0: { sl@0: result = etemp; sl@0: break; sl@0: } sl@0: } sl@0: return result; sl@0: } sl@0: sl@0: /*----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL void sl@0: WFC_Scene_LockSourcesAndMasks(WFC_SCENE* scene) sl@0: { sl@0: OWF_NODE* node = NULL; sl@0: sl@0: DPRINT(("WFC_Scene_LockSourcesAndMasks(scene = %p)", scene)); sl@0: sl@0: for (node = scene->elements; NULL != node; node = node->next) sl@0: { sl@0: WFC_ELEMENT* element; sl@0: sl@0: element = ELEMENT(node->data); sl@0: sl@0: DPRINT((" Element source handle = %d", element->sourceHandle)); sl@0: DPRINT((" Element source = %p", element->source)); sl@0: DPRINT((" Element dest size = %.2fx%.2f", sl@0: element->dstRect[2], element->dstRect[3])); sl@0: DPRINT((" Element src size = %.2fx%.2f", sl@0: element->srcRect[2], element->srcRect[3])); sl@0: sl@0: if (WFC_Element_AffectsCompositionResults(element)) sl@0: { sl@0: DPRINT((" Locking element %p", element)); sl@0: WFC_ImageProvider_LockForReading(element->source); sl@0: /* set the flag so that composition knows to include the sl@0: element into composition */ sl@0: element->skipCompose = sl@0: (element->source->lockedStream.image->data == NULL) ? sl@0: WFC_TRUE : WFC_FALSE; sl@0: } sl@0: else sl@0: { sl@0: element->skipCompose = WFC_TRUE; sl@0: } sl@0: sl@0: if (!element->skipCompose && sl@0: WFC_INVALID_HANDLE != element->maskHandle && sl@0: NULL != element->mask) sl@0: { sl@0: WFC_ImageProvider_LockForReading(element->mask); sl@0: element->maskComposed = WFC_TRUE; sl@0: sl@0: OWF_ASSERT(element->mask); sl@0: OWF_ASSERT(element->mask->streamHandle); sl@0: OWF_ASSERT(element->mask->lockedStream.image); sl@0: sl@0: if(element->mask->lockedStream.image->data == NULL) sl@0: { sl@0: WFC_ImageProvider_Unlock(element->source); sl@0: element->skipCompose = WFC_TRUE; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: element->maskComposed = WFC_FALSE; sl@0: } sl@0: } sl@0: } sl@0: sl@0: /*----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL void sl@0: WFC_Scene_UnlockSourcesAndMasks(WFC_SCENE* scene) sl@0: { sl@0: OWF_NODE* node = NULL; sl@0: sl@0: DPRINT(("WFC_Scene_UnlockSourcesAndMasks(scene = %p)", scene)); sl@0: sl@0: for (node = scene->elements; NULL != node; node = node->next) sl@0: { sl@0: WFC_ELEMENT* element; sl@0: sl@0: element = ELEMENT(node->data); sl@0: sl@0: DPRINT((" Unlocking element %p", element)); sl@0: if (element->source && !element->skipCompose) sl@0: { sl@0: WFC_ImageProvider_Unlock(element->source); sl@0: } sl@0: sl@0: if (element->mask && !element->skipCompose) sl@0: { sl@0: WFC_ImageProvider_Unlock(element->mask); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /*----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL WFCElement sl@0: WFC_Scene_GetNeighbourElement(WFC_SCENE* scene, WFCElement element, WFCint n) sl@0: { sl@0: WFCElement result = WFC_INVALID_HANDLE; sl@0: OWF_NODE* node = NULL; sl@0: OWF_NODE* prev = NULL; sl@0: sl@0: for (node = scene->elements; NULL != node; node = node->next) sl@0: { sl@0: WFC_ELEMENT* etemp; sl@0: sl@0: etemp = ELEMENT(node->data); sl@0: if (etemp->handle == element) sl@0: { sl@0: if (n < 0) sl@0: { sl@0: result = prev ? ELEMENT(prev->data)->handle sl@0: : WFC_INVALID_HANDLE; sl@0: } sl@0: else sl@0: { sl@0: result = node->next ? ELEMENT(node->next->data)->handle sl@0: : WFC_INVALID_HANDLE; sl@0: sl@0: } sl@0: break; sl@0: } sl@0: prev = node; sl@0: } sl@0: return result; sl@0: } sl@0: sl@0: /*----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL WFCboolean sl@0: WFC_Scene_HasConflicts(WFC_SCENE* scene) sl@0: { sl@0: WFCboolean result = WFC_FALSE; sl@0: OWF_NODE* node = NULL; sl@0: sl@0: for (node = scene->elements; NULL != node; node = node->next) sl@0: { sl@0: WFC_ELEMENT* element; sl@0: sl@0: element = ELEMENT(node->data); sl@0: sl@0: result = result || WFC_Element_HasConflicts(element) ? WFC_TRUE : WFC_FALSE; sl@0: if (result) sl@0: { sl@0: /* conflict found */ sl@0: break; sl@0: } sl@0: } sl@0: return result; sl@0: } sl@0: sl@0: /*----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL void sl@0: WFC_Scene_Commit(WFC_SCENE* scene) sl@0: { sl@0: OWF_NODE* node; sl@0: sl@0: for (node = scene->elements; NULL != node; node = node->next) sl@0: { sl@0: WFC_ELEMENT* element; sl@0: sl@0: element = ELEMENT(node->data); sl@0: WFC_Element_Commit(element); sl@0: } sl@0: } sl@0: sl@0: /*----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL WFCElement sl@0: WFC_Scene_LowestElement(WFC_SCENE* scene) sl@0: { sl@0: WFCElement element = WFC_INVALID_HANDLE; sl@0: sl@0: if (scene && scene->elements) sl@0: { sl@0: element = ELEMENT(scene->elements->data)->handle; sl@0: } sl@0: return element; sl@0: } sl@0: sl@0: /*----------------------------------------------------------------------------*/ sl@0: OWF_API_CALL WFC_ELEMENT* sl@0: WFC_Scene_TopMostElement(WFC_SCENE* scene) sl@0: { sl@0: OWF_NODE* node = NULL; sl@0: sl@0: for (node = scene->elements; node && node->next; node = node->next) sl@0: { sl@0: /* All work done in the for statement, so no body */ sl@0: } sl@0: sl@0: return node ? ELEMENT(node->data) : NULL; sl@0: }