graphicscomposition/openwfcompositionengine/composition/src/wfcpipeline.c
changeset 0 5d03bc08d59c
child 36 01a6848ebfd7
child 39 a4b63488e0b0
child 163 bbf46f59e123
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicscomposition/openwfcompositionengine/composition/src/wfcpipeline.c	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,836 @@
+/* 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 wfcpipeline.c
+ *
+ *  \brief SI Composition pipeline stages
+ *
+ *  Each pipeline stage is implemented in their respective functions
+ *  that take context and element as parameter. Composition status is
+ *  stored in elements state variable (struct WFC_ELEMENT_STATE.)
+ *  State has no strict input/output variables, each stage reads/writes
+ *  those variables it needs
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "WF/wfc.h"
+#include "wfccontext.h"
+#include "wfcelement.h"
+#include "wfcimageprovider.h"
+#include "wfcstructs.h"
+#include "wfcscene.h"
+
+#include "owfobject.h"
+
+#include "owfnativestream.h"
+#include "owfmemory.h"
+#include "owfimage.h"
+#include "owfdebug.h"
+
+#define EXTRA_PIXEL_BOUNDARY 2
+
+/*!
+ *  \brief Check element destination visibility
+ *
+ *  Check if element's destination rectangle is
+ *  inside context's visible limits.
+ *
+ *  \param context          Context
+ *  \param element          Element
+ *
+ *  \return Boolean value indicating whether element is visible or not
+ */
+
+static WFCboolean
+WFC_Pipeline_ElementIsVisible(WFC_CONTEXT* context, WFC_ELEMENT* element)
+{
+    OWF_RECTANGLE bounds, rect, drect;
+
+    if ((context->rotation == WFC_ROTATION_90) || (context->rotation == WFC_ROTATION_270))
+        {
+        OWF_Rect_Set(&bounds, 0, 0, context->targetHeight, context->targetWidth);
+        }
+    else
+        {
+        OWF_Rect_Set(&bounds, 0, 0, context->targetWidth, context->targetHeight);
+        }
+    
+    OWF_Rect_Set(&rect, element->dstRect[0], element->dstRect[1],
+            element->dstRect[2], element->dstRect[3]);
+
+    /* check destination rectangle against bounds - exit if not visible */
+    if (!OWF_Rect_Clip(&drect, &rect, &bounds))
+    {
+        return WFC_FALSE;
+    }
+
+    return WFC_TRUE;
+}
+
+static void 
+WFC_Pipeline_BlendInfo(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state)
+{
+
+    OWF_ASSERT(state);    
+    
+    /* setup blending parameters */
+    state->blendInfo.destination.image     = context->state.internalTargetImage;
+    state->blendInfo.destination.rectangle = &state->dstRect;
+    state->blendInfo.source.image          = state->scaledSourceImage;
+    state->blendInfo.source.rectangle      = &state->scaledSrcRect;
+    state->blendInfo.mask                  = state->originalMaskImage ? state->maskImage : NULL;
+    state->blendInfo.globalAlpha           = state->globalAlpha;
+    
+    /* composition does not use these values ever */
+    state->blendInfo.tsColor                = NULL;
+    state->blendInfo.destinationFullyOpaque = OWF_FALSE;    
+    
+    DPRINT(("  globalAplha = %f", state->globalAlpha));
+    /* no need to check with OWF_ALPHA_MIN_VALUE as it is zero */
+    OWF_ASSERT(state->blendInfo.globalAlpha <= OWF_ALPHA_MAX_VALUE);    
+}
+
+/*! Transform the source rectangle to represent the floating point viewport
+    as an offset in the final rotation stage image */
+static void
+WFC_Pipeline_TransformSource(WFC_ELEMENT_STATE* state)
+{
+    OWFfloat                width, height, totalWidth, totalHeight,
+                            leftMargin, rightMargin, 
+                            topMargin, bottomMargin,
+                            temp;
+    OWF_FLIP_DIRECTION      flipping;
+    WFCRotation             rotation;
+    
+    
+    OWF_ASSERT(state);
+    
+    width = state->sourceRect[2];
+    totalWidth = state->sourceRect[0] + state->sourceRect[2];
+    
+    height = state->sourceRect[3];
+    totalHeight = state->sourceRect[1] + state->sourceRect[3];
+    
+    /* X margins - includes 1 pixel border */
+    leftMargin = (state->sourceRect[0] - ((float) floor(state->sourceRect[0]))) + 1.0f;
+    rightMargin = (((float) ceil(totalWidth)) - totalWidth) + 1.0f;
+    
+    /* Y margins - includes 1 pixel border */
+    topMargin = (state->sourceRect[1] - ((float) floor(state->sourceRect[1]))) + 1.0f;    
+    bottomMargin = (((float) ceil(totalHeight)) - totalHeight) + 1.0f;
+    
+    /* flip stages */
+    flipping = state->sourceFlip > 0.0f ? OWF_FLIP_VERTICALLY
+                                      : OWF_FLIP_NONE;
+    
+    /* top margin needs to be the bottom margin */
+    if (flipping & OWF_FLIP_VERTICALLY)
+    {
+        temp = topMargin;
+        topMargin = bottomMargin;
+        bottomMargin = temp; 
+    }
+    
+    /* rotation stages */
+    rotation = state->rotation;
+    
+    switch (rotation)
+    {
+        case WFC_ROTATION_0:
+        {
+            break;
+        }
+
+        case WFC_ROTATION_90:
+        {
+            /* switch width and height */
+            temp = width;
+            width = height;
+            height = temp;
+            
+            topMargin = leftMargin;
+            leftMargin = bottomMargin;
+            
+            break;
+        }
+
+        case WFC_ROTATION_180:
+        {
+            leftMargin = rightMargin;
+            topMargin = bottomMargin;
+        
+            break;
+        }
+
+        case WFC_ROTATION_270:
+        {
+            /* switch width and height */
+            temp = width;
+            width = height;
+            height = temp; 
+            
+            leftMargin = topMargin;
+            topMargin = rightMargin;
+            
+            break;
+        }
+
+        default:
+        {
+            OWF_ASSERT(0);
+        }
+    }    
+    
+    /* X offset */
+    state->transformedSourceRect[0] = leftMargin;
+    /* Y offset */
+    state->transformedSourceRect[1] = topMargin;
+    /* width */
+    state->transformedSourceRect[2] = width;
+    /* height */
+    state->transformedSourceRect[3] = height;    
+}
+
+/*! Calculate the oversized integer crop region */
+static void
+WFC_Pipeline_OversizedViewport(WFC_ELEMENT_STATE* state)
+{
+    OWFint width, height;
+
+    state->oversizedCropRect.x = (int) floor(state->sourceRect[0]);
+    state->oversizedCropRect.y = (int) floor(state->sourceRect[1]);
+    
+    width = (int) ceil(state->sourceRect[0] + state->sourceRect[2]);
+    state->oversizedCropRect.width = (width - state->oversizedCropRect.x) + EXTRA_PIXEL_BOUNDARY;
+    
+    height = (int) ceil(state->sourceRect[1] + state->sourceRect[3]);    
+    state->oversizedCropRect.height = (height - state->oversizedCropRect.y) + EXTRA_PIXEL_BOUNDARY;
+}
+
+/*-----------------------------------------------------------*
+ * Initial creation of element state object created just once per context
+ *-----------------------------------------------------------*/
+OWF_API_CALL void WFC_Pipeline_DestroyState(WFC_CONTEXT* context)
+{
+    WFC_ELEMENT_STATE*      state;
+    state= &context->prototypeElementState;
+    OWF_Image_Destroy(state->scaledSourceImage);
+    OWF_Image_Destroy(state->croppedSourceImage);
+    OWF_Image_Destroy(state->convertedSourceImage);
+    OWF_Image_Destroy(state->rotatedSourceIntermediateImage);
+    OWF_Image_Destroy(state->flippedSourceImage);
+    OWF_Image_Destroy(state->rotatedSourceImage);    
+    OWF_Image_Destroy(state->maskImage);
+    state->scaledSourceImage=NULL;
+    state->croppedSourceImage=NULL;
+    state->convertedSourceImage=NULL;
+    state->rotatedSourceIntermediateImage=NULL;
+    state->flippedSourceImage=NULL;
+    state->rotatedSourceImage=NULL;    
+    state->maskImage=NULL;
+}
+
+OWF_API_CALL OWFboolean WFC_Pipeline_CreateState(WFC_CONTEXT* context)
+{
+    WFC_ELEMENT_STATE*      state;
+    OWF_IMAGE_FORMAT        fmt;
+    
+    fmt.pixelFormat    = OWF_IMAGE_ARGB_INTERNAL;
+    fmt.linear         = OWF_FALSE;
+    fmt.premultiplied  = OWF_FALSE;
+    fmt.rowPadding     = 1;
+    state= &context->prototypeElementState;
+    /* All buffers are initially created the full size of the scratch buffers, whicgh records the buffer size in bytes */
+    state->convertedSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[1], 0);
+    state->croppedSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[2], 0);
+    state->flippedSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[2], 0);    
+
+    state->rotatedSourceIntermediateImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[1], 0);      
+    state->rotatedSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[2], 0);  
+    state->scaledSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[3], 0);
+    fmt.pixelFormat    = OWF_IMAGE_L32;
+    state->maskImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[4], 0);
+    if (!state->convertedSourceImage||!state->croppedSourceImage||!state->flippedSourceImage
+        ||!state->rotatedSourceIntermediateImage||!state->rotatedSourceImage
+        ||!state->scaledSourceImage||!state->maskImage
+        )
+        {
+        WFC_Pipeline_DestroyState(context);
+        return OWF_FALSE;
+        }
+    return OWF_TRUE;
+}
+
+
+/*---------------------------------------------------------------------------
+ *  Composition pipeline preparation
+ *
+ *  \param context          Context
+ *  \param element          Element
+ *
+ *  \return Boolean value indicating whether preparation succeeded
+ *----------------------------------------------------------------------------*/
+#ifdef DEBUG
+/* reset size to original extent then try to set it to the target size */
+#define CREATE_WITH_LIMITS(img, imgW, imgH, fmt, maxW, maxH) \
+    { \
+        OWFboolean resized; \
+        OWF_Image_SetSize(img, maxW, maxH); \
+        OWF_Image_SetFlags(img,(fmt)->premultiplied,(fmt)->linear); \
+        resized = OWF_Image_SetSize(img, imgW, imgH); \
+        OWF_ASSERT(resized); \
+    }
+#else
+#define CREATE_WITH_LIMITS(img, imgW, imgH, fmt, maxW, maxH) \
+    { \
+        OWF_Image_SetSize(img, maxW, maxH); \
+        OWF_Image_SetFlags(img,(fmt)->premultiplied,(fmt)->linear); \
+        OWF_Image_SetSize(img, imgW, imgH); \
+    }
+#endif
+OWF_API_CALL WFC_ELEMENT_STATE*
+WFC_Pipeline_BeginComposition(WFC_CONTEXT* context, WFC_ELEMENT* element)
+{
+    WFC_ELEMENT_STATE*      state = &context->prototypeElementState;
+    OWF_IMAGE_FORMAT        imgf;
+    OWFint                  sourceWidth;
+    OWFint                  sourceHeight;
+    OWFint                  x;
+    OWFint                  tempWidth, tempHeight;
+
+
+    DPRINT(("WFC_Element_BeginComposition(%x,%x)",
+            context ? context->handle : 0, element ? element->handle : 0));
+
+    if (!context || !element)
+    {
+        DPRINT(("  context == NULL || element == NULL"));
+        return NULL;
+    }
+
+    if (!WFC_Pipeline_ElementIsVisible(context, element))
+    {
+        DPRINT(("  element [%x] totally outside of target - skipped",
+                        element ? element->handle : 0));
+        return NULL;
+    }
+
+    
+    /* setup temporary images used in composition. since the original
+       source data must not be altered, we must copy it to scratch buffer
+       and work it there. another scratch buffer is needed for scaling
+       the image to its final size. same applies for masks; thus a grand total
+       of 4 scratch buffers are needed. */
+    OWF_ASSERT(element->source);
+    OWF_ASSERT(element->source->streamHandle);     
+    
+    state->originalSourceImage = element->source->lockedStream.image;
+    state->rotation = element->sourceRotation;
+    state->sourceFlip = element->sourceFlip;
+    state->globalAlpha = element->globalAlpha;
+    state->sourceScaleFilter = element->sourceScaleFilter;
+    state->transparencyTypes = element->transparencyTypes;
+    /* replicate the source viewport rectangle and target extent rectangle */
+    for (x = 0; x < 4; x++)
+    {
+        state->sourceRect[x] = element->srcRect[x];
+        state->destinationRect[x] = element->dstRect[x];
+    }
+    OWF_Rect_Set(&state->dstRect, element->dstRect[0], element->dstRect[1],
+                 element->dstRect[2], element->dstRect[3]);    
+    
+    /* transform the source rectangle to represent the floating point viewport
+       as an offset in the final rotation stage image */
+    WFC_Pipeline_TransformSource(state);
+    
+    imgf.pixelFormat    = OWF_IMAGE_ARGB_INTERNAL;
+    imgf.linear         = element->source->lockedStream.image->format.linear;
+    imgf.premultiplied  = element->source->lockedStream.image->format.premultiplied;
+    imgf.rowPadding     = 1;
+
+    /* add a 1 pixel boundary so we can replicate the edges */
+    sourceWidth = element->source->lockedStream.image->width + EXTRA_PIXEL_BOUNDARY;
+    sourceHeight = element->source->lockedStream.image->height + EXTRA_PIXEL_BOUNDARY;
+    
+    CREATE_WITH_LIMITS(state->convertedSourceImage,
+                       sourceWidth,
+                       sourceHeight,
+                       &imgf,
+                       MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);
+    
+    /* calculate the oversized integer crop region (inc. 1 pixel boundary)
+       so edge replication can be performed */
+    WFC_Pipeline_OversizedViewport(state);    
+    
+    /* subsequent temporary renderstage pipeline images need to use the oversized
+       integer crop region */
+    CREATE_WITH_LIMITS(state->croppedSourceImage,
+                       state->oversizedCropRect.width, state->oversizedCropRect.height,
+                       &imgf,
+                       MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);
+    
+    CREATE_WITH_LIMITS(state->flippedSourceImage,
+                       state->oversizedCropRect.width, state->oversizedCropRect.height,
+                       &imgf,
+                       MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);    
+    
+
+    if (state->rotation == WFC_ROTATION_90 || state->rotation == WFC_ROTATION_270)
+    {
+        tempHeight = state->oversizedCropRect.width;
+        tempWidth = state->oversizedCropRect.height;
+    }
+    else
+    {
+        tempWidth = state->oversizedCropRect.width;
+        tempHeight = state->oversizedCropRect.height;
+    }
+
+    CREATE_WITH_LIMITS(state->rotatedSourceIntermediateImage,
+                       tempWidth, tempHeight,
+                       &imgf,
+                       MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);      
+    
+
+     /* no rotation required - just use the previous stages (flip) buffer */
+    CREATE_WITH_LIMITS(state->rotatedSourceImage,
+                       tempWidth, tempHeight,
+                       &imgf,
+                       MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);  
+
+    /* finally, scaled image uses destination width and height */
+    OWF_Rect_Set(&state->scaledSrcRect, 0, 0, element->dstRect[2], element->dstRect[3]);
+    CREATE_WITH_LIMITS(state->scaledSourceImage,
+                       state->scaledSrcRect.width,
+                       state->scaledSrcRect.height,
+                       &imgf,
+                        MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);
+
+    if (!(state->convertedSourceImage && state->croppedSourceImage &&
+          state->scaledSourceImage && state->rotatedSourceIntermediateImage &&
+          state->flippedSourceImage && state->rotatedSourceImage))
+    {
+        DPRINT(("  Preparation of intermediate pipeline image buffers failed"
+                "  (May be caused by overflow or out-of-memory situation)"));
+        DPRINT(("    convertedSourceImage = %p", state->convertedSourceImage));
+        DPRINT(("    croppedSourceImage = %p", state->croppedSourceImage));
+        DPRINT(("    scaledSourceImage = %p", state->scaledSourceImage));
+        DPRINT(("    rotatedSourceIntermediateImage = %p", state->rotatedSourceIntermediateImage));
+        DPRINT(("    flippedSourceImage = %p", state->flippedSourceImage));
+        DPRINT(("    rotatedSourceImage = %p", state->rotatedSourceImage));
+
+
+        return (WFC_ELEMENT_STATE*)WFC_FALSE;
+    }
+
+#ifdef DEBUG
+        OWF_Image_Clear(state->convertedSourceImage, 0, 0, 0, 0);
+        OWF_Image_Clear(state->croppedSourceImage, 0, 0, 0, 0);
+        OWF_Image_Clear(state->scaledSourceImage, 0, 0, 0, 0);
+        OWF_Image_Clear(state->rotatedSourceIntermediateImage, 0, 0, 0, 0);
+        OWF_Image_Clear(state->flippedSourceImage, 0, 0, 0, 0);
+        OWF_Image_Clear(state->rotatedSourceImage, 0, 0, 0, 0);
+#endif
+
+    /* setup mask in case the element has one */
+    if (element->maskComposed)
+    {
+        OWF_IMAGE*          image = NULL;
+        OWFsubpixel*        pix = NULL;
+        WFCint              i = 0;
+
+        DPRINT(("Processing element mask"));
+        OWF_ASSERT(&element->mask);
+        OWF_ASSERT(&element->mask->streamHandle);
+        image = element->mask->lockedStream.image;
+        OWF_ASSERT(image);
+
+        state->originalMaskImage = element->mask->lockedStream.image;        
+        
+        imgf.pixelFormat    = OWF_IMAGE_L32;
+        imgf.linear         = image->format.linear;
+        imgf.premultiplied  = image->format.premultiplied;
+
+        /* mask size is always same as destination rect's */
+        DPRINT(("Binding stream image to scratch buffer"));
+        CREATE_WITH_LIMITS(state->maskImage,
+                           state->scaledSrcRect.width,
+                           state->scaledSrcRect.height,
+                           &imgf,
+                           MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);
+
+        /* initialize mask */
+        DPRINT(("Initializing mask, size = %dx%d", state->scaledSrcRect.width,
+                state->scaledSrcRect.height));
+        pix = (OWFsubpixel*) state->maskImage->data;
+        for (i = 0; i < state->scaledSrcRect.width * state->scaledSrcRect.height; i++)
+        {
+            pix[i] = OWF_FULLY_OPAQUE;
+        }
+    }
+    else
+        {
+        state->originalMaskImage=NULL;
+        }
+    
+    WFC_Pipeline_BlendInfo(context, state);
+
+    DPRINT(("  Cropped source image size is %dx%d",
+           state->croppedSourceImage->width, state->croppedSourceImage->height));
+    DPRINT(("  Scaled source image size is %dx%d",
+            state->scaledSourceImage->width, state->scaledSourceImage->height));
+    DPRINT(("  Mirrored source intermediate image size is %dx%d",
+            state->rotatedSourceIntermediateImage->width, state->rotatedSourceIntermediateImage->height));
+    DPRINT(("  Mirrored source image size is %dx%d",
+            state->flippedSourceImage->width, state->flippedSourceImage->height));
+    DPRINT(("  Rotated source image size is %dx%d",
+            state->rotatedSourceImage->width, state->rotatedSourceImage->height));  
+    
+    return state;
+}
+
+/*---------------------------------------------------------------------------
+ *  Composition pipeline cleanup
+ *
+ *  \param context          Context
+ *  \param element          Element
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL void
+WFC_Pipeline_EndComposition(WFC_CONTEXT* context, WFC_ELEMENT* element, WFC_ELEMENT_STATE* state)
+{
+
+    if (!context || !element)
+    {
+        DPRINT(("WFC_Element_EndComposition: context == NULL || "
+                "element == NULL"));
+    }
+
+
+    OWF_ASSERT(state);
+    state->originalSourceImage=NULL;
+    state->originalMaskImage=NULL;
+
+}
+
+/*---------------------------------------------------------------------------
+ *  \brief Source conversion stage
+ *
+ *  \param context          Context
+ *  \param element          Element
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL void
+WFC_Pipeline_ExecuteSourceConversionStage(WFC_CONTEXT* context,
+        WFC_ELEMENT_STATE* state)
+{
+    /* this stage could be embedded in cropping stage */
+
+
+    if (NULL == context || NULL == state)
+    {
+        DPRINT(("WFC_Context_ExecuteSourceConversionStage: context = %p, "
+                "state = %p",
+                context, state));
+        return;
+    }
+
+    OWF_ASSERT(state->originalSourceImage);
+
+    OWF_Image_SourceFormatConversion(state->convertedSourceImage,
+                                     state->originalSourceImage);
+
+    /* convert mask from stream format to internal format */
+    if (state->originalMaskImage)
+    {
+        if (!OWF_Image_ConvertMask(state->maskImage, state->originalMaskImage))
+        {
+            state->originalMaskImage=NULL;
+        }
+    }
+}
+
+/*---------------------------------------------------------------------------
+ *  \brief Crop stage
+ *
+ *  \param context          Context
+ *  \param element          Element
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL void
+WFC_Pipeline_ExecuteCropStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state)
+{
+    OWF_RECTANGLE           sourceRect,
+                            cropRect;
+
+    DPRINT(("WFC_Pipeline_ExecuteCropStage"));
+
+    if (NULL == context || NULL == state)
+    {
+        DPRINT(("WFC_Context_ExecuteCropStage: context = %p, state = %p",
+               context, state));
+    }
+    else
+    {
+
+        /* Source rectangle */
+        OWF_Rect_Set(&sourceRect,
+                     state->oversizedCropRect.x, state->oversizedCropRect.y,
+                     state->oversizedCropRect.width, state->oversizedCropRect.height);
+
+        /* cropped source size - supports oversized integer and 1 pixel boundary */
+        OWF_Rect_Set(&cropRect,
+                     0, 0,
+                     state->oversizedCropRect.width, state->oversizedCropRect.height);
+
+        OWF_Image_Blit(state->croppedSourceImage, &cropRect,
+                       state->convertedSourceImage, &sourceRect);
+    }
+}
+
+/*---------------------------------------------------------------------------
+ *  \brief Flip stage
+ *
+ *  \param context          Context
+ *  \param element          Element
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL void
+WFC_Pipeline_ExecuteFlipStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state)
+{
+    OWF_FLIP_DIRECTION      flipping;
+    
+    if (NULL == context || NULL == state)
+    {
+        DPRINT(("WFC_Context_ExecuteFlipStage: context = %p, state = %p",
+               context, state));
+    }
+    else
+    {
+        OWF_ASSERT(state);
+        flipping = state->sourceFlip > 0.0f ? OWF_FLIP_VERTICALLY
+                                          : OWF_FLIP_NONE;
+        
+        OWF_Image_Flip(state->flippedSourceImage, flipping);
+    }
+}
+
+/*---------------------------------------------------------------------------
+ *  \brief Rotation stage
+ *
+ *  \param context          Context
+ *  \param element          Element
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL void
+WFC_Pipeline_ExecuteRotationStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state)
+{
+    OWF_ROTATION            rot = OWF_ROTATION_0;
+    OWF_RECTANGLE           rect;    
+    WFCRotation             rotation;
+
+
+    if (NULL == context || NULL == state)
+    {
+        DPRINT(("WFC_Context_ExecuteRotationStage: context = %p, state = %p",
+               context, state));
+        return;
+    }
+    OWF_ASSERT(state);
+
+    rotation = state->rotation;
+    DPRINT(("  Element rotation = %d", rotation));
+
+    switch (rotation)
+    {
+        case WFC_ROTATION_0:
+        {
+            return; /* Rotate copies back into input buffer so just skip */
+        }
+
+        case WFC_ROTATION_90:
+        {
+            rot = OWF_ROTATION_90;
+            break;
+        }
+
+        case WFC_ROTATION_180:
+        {
+            rot = OWF_ROTATION_180;
+            break;
+        }
+
+        case WFC_ROTATION_270:
+        {
+            rot = OWF_ROTATION_270;
+            break;
+        }
+
+        default:
+        {
+            OWF_ASSERT(0);
+        }
+    }
+
+    /* rotate the the image using rotatedSourceIntermediateImage */
+    OWF_Image_Rotate(state->rotatedSourceIntermediateImage,
+                     state->flippedSourceImage,
+                     rot);
+
+    /* blit rotated image back to original image buffer */
+    rect.x      = 0;
+    rect.y      = 0;
+    rect.width  = state->rotatedSourceIntermediateImage->width;
+    rect.height = state->rotatedSourceIntermediateImage->height;
+
+    DPRINT(("  Source image dimensions after rotation = %dx%d",
+           rect.width, rect.height));
+
+    OWF_Image_Blit(state->rotatedSourceImage,
+                   &rect,
+                   state->rotatedSourceIntermediateImage,
+                   &rect);
+    
+}
+
+/*---------------------------------------------------------------------------
+ *  \brief Scaling stage
+ *
+ *  \param context          Context
+ *  \param element          Element
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL void
+WFC_Pipeline_ExecuteScalingStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state)
+{
+    OWF_RECTANGLE           scaledRect,
+                            cropRect;
+    OWF_FILTERING           filteringMode = OWF_FILTER_POINT_SAMPLING;
+    WFCScaleFilter          filter;
+
+    DPRINT(("WFC_Context_ExecuteScalingStage(%p,%p)", context, state));
+
+    if (NULL == context || NULL == state)
+    {
+        DPRINT(("WFC_Context_ExecuteScalingStage: context = %p, state = %p",
+               context, state));
+        return;
+    }
+
+    OWF_ASSERT(state);
+
+    filter = state->sourceScaleFilter;
+
+    switch (filter)
+    {
+        case WFC_SCALE_FILTER_NONE:
+        case WFC_SCALE_FILTER_FASTER:
+        {
+            filteringMode = OWF_FILTER_POINT_SAMPLING;
+            DPRINT(("  Using point-sampling filter"));
+            break;
+        }
+        case WFC_SCALE_FILTER_BETTER:
+        {
+            filteringMode = OWF_FILTER_BILINEAR;
+            DPRINT(("  Using bilinear filter"));
+            break;
+        }
+
+        case WFC_SCALE_FILTER_FORCE_32BIT:
+        {
+            /* To shut the compiler up -- not a valid filtering mode.
+             * Validity is ensured when the filter attribute value
+             * is set, thus it shouldn't have this value ever. */
+            OWF_ASSERT(0);
+            break;
+        }
+    }
+
+    OWF_Rect_Set(&cropRect, 1, 1,
+                 state->rotatedSourceImage->width - EXTRA_PIXEL_BOUNDARY,
+                 state->rotatedSourceImage->height - EXTRA_PIXEL_BOUNDARY);
+
+    OWF_Rect_Set(&scaledRect, 0, 0, state->destinationRect[2], state->destinationRect[3]);
+    
+    if (  scaledRect.width != state->transformedSourceRect[2] 
+      ||  scaledRect.height != state->transformedSourceRect[3]
+      ||  state->sourceRect[0] != floor(state->sourceRect[0])
+      ||  state->sourceRect[1] != floor(state->sourceRect[1])
+    )
+    {
+        /* scale the image */
+        OWF_Image_Stretch(state->scaledSourceImage, &scaledRect,
+                          state->rotatedSourceImage, state->transformedSourceRect,
+                          filteringMode);
+    }
+    else
+    {
+        /* 1:1 copy, no need to scale */
+        OWF_Image_Blit(state->scaledSourceImage, &scaledRect,
+                       state->rotatedSourceImage, &cropRect);
+    }
+    
+}
+
+/*---------------------------------------------------------------------------
+ *  \brief Blending stage
+ *
+ *  \param context          Context
+ *  \param element          Element
+ *----------------------------------------------------------------------------*/
+OWF_API_CALL void
+WFC_Pipeline_ExecuteBlendingStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state)
+{
+    OWF_TRANSPARENCY        blendMode = OWF_TRANSPARENCY_NONE;
+    WFCbitfield             transparency = 0;
+
+    DPRINT(("WFC_Pipeline_ExecuteBlendingStage"));
+
+    if (NULL == context || NULL == state)
+    {
+        return;
+    }
+
+    DPRINT(("  context = %d, state = %d",
+           context->handle, state));
+
+    OWF_ASSERT(state);
+
+    transparency = state->transparencyTypes;
+    blendMode = OWF_TRANSPARENCY_NONE;
+
+    if (transparency & WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA)
+    {
+        blendMode = (OWF_TRANSPARENCY)(blendMode|OWF_TRANSPARENCY_GLOBAL_ALPHA);
+    }
+
+    if (transparency & WFC_TRANSPARENCY_SOURCE)
+    {
+        OWF_Image_PremultiplyAlpha(state->scaledSourceImage);
+        blendMode = (OWF_TRANSPARENCY)(blendMode|OWF_TRANSPARENCY_SOURCE_ALPHA);
+    }
+
+    if ((transparency & WFC_TRANSPARENCY_MASK) && state->originalMaskImage)
+    {
+        blendMode = (OWF_TRANSPARENCY)(blendMode|OWF_TRANSPARENCY_MASK);
+    }
+
+    OWF_Image_Blend(&state->blendInfo, blendMode);
+}