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