--- /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);
+}