diff -r 000000000000 -r 5d03bc08d59c graphicscomposition/openwfcompositionengine/composition/src/wfcpipeline.c --- /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 +#include +#include + +#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); +}