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