os/graphics/graphicscomposition/openwfcompositionengine/composition/src/wfcpipeline.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /* Copyright (c) 2009-2010 The Khronos Group Inc.
     2  * Portions copyright (c) 2009-2010  Nokia Corporation and/or its subsidiary(-ies)
     3  *
     4  * Permission is hereby granted, free of charge, to any person obtaining a
     5  * copy of this software and/or associated documentation files (the
     6  * "Materials"), to deal in the Materials without restriction, including
     7  * without limitation the rights to use, copy, modify, merge, publish,
     8  * distribute, sublicense, and/or sell copies of the Materials, and to
     9  * permit persons to whom the Materials are furnished to do so, subject to
    10  * the following conditions:
    11  *
    12  * The above copyright notice and this permission notice shall be included
    13  * in all copies or substantial portions of the Materials.
    14  *
    15  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    21  * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
    22  */
    23 
    24 /*! \ingroup wfc
    25  *  \file wfcpipeline.c
    26  *
    27  *  \brief SI Composition pipeline stages
    28  *
    29  *  Each pipeline stage is implemented in their respective functions
    30  *  that take context and element as parameter. Composition status is
    31  *  stored in elements state variable (struct WFC_ELEMENT_STATE.)
    32  *  State has no strict input/output variables, each stage reads/writes
    33  *  those variables it needs
    34  */
    35 #include <string.h>
    36 #include <stdlib.h>
    37 #include <math.h>
    38 
    39 #include "WF/wfc.h"
    40 #include "wfccontext.h"
    41 #include "wfcelement.h"
    42 #include "wfcimageprovider.h"
    43 #include "wfcstructs.h"
    44 #include "wfcscene.h"
    45 
    46 #include "owfobject.h"
    47 
    48 #include "owfnativestream.h"
    49 #include "owfmemory.h"
    50 #include "owfimage.h"
    51 #include "owfdebug.h"
    52 
    53 #define EXTRA_PIXEL_BOUNDARY 2
    54 
    55 /*!
    56  *  \brief Check element destination visibility
    57  *
    58  *  Check if element's destination rectangle is
    59  *  inside context's visible limits.
    60  *
    61  *  \param context          Context
    62  *  \param element          Element
    63  *
    64  *  \return Boolean value indicating whether element is visible or not
    65  */
    66 
    67 static WFCboolean
    68 WFC_Pipeline_ElementIsVisible(WFC_CONTEXT* context, WFC_ELEMENT* element)
    69 {
    70     OWF_RECTANGLE bounds, rect, drect;
    71 
    72     if ((context->rotation == WFC_ROTATION_90) || (context->rotation == WFC_ROTATION_270))
    73         {
    74         OWF_Rect_Set(&bounds, 0, 0, context->targetHeight, context->targetWidth);
    75         }
    76     else
    77         {
    78         OWF_Rect_Set(&bounds, 0, 0, context->targetWidth, context->targetHeight);
    79         }
    80     
    81     OWF_Rect_Set(&rect, element->dstRect[0], element->dstRect[1],
    82             element->dstRect[2], element->dstRect[3]);
    83 
    84     /* check destination rectangle against bounds - exit if not visible */
    85     if (!OWF_Rect_Clip(&drect, &rect, &bounds))
    86     {
    87         return WFC_FALSE;
    88     }
    89 
    90     return WFC_TRUE;
    91 }
    92 
    93 static void 
    94 WFC_Pipeline_BlendInfo(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state)
    95 {
    96 
    97     OWF_ASSERT(state);    
    98     
    99     /* setup blending parameters */
   100     state->blendInfo.destination.image     = context->state.internalTargetImage;
   101     state->blendInfo.destination.rectangle = &state->dstRect;
   102     state->blendInfo.source.image          = state->scaledSourceImage;
   103     state->blendInfo.source.rectangle      = &state->scaledSrcRect;
   104     state->blendInfo.mask                  = state->originalMaskImage ? state->maskImage : NULL;
   105     state->blendInfo.globalAlpha           = state->globalAlpha;
   106     
   107     DPRINT(("  globalAplha = %f", state->globalAlpha));
   108     /* no need to check with OWF_ALPHA_MIN_VALUE as it is zero */
   109     OWF_ASSERT(state->blendInfo.globalAlpha <= OWF_ALPHA_MAX_VALUE);    
   110 }
   111 
   112 /*! Transform the source rectangle to represent the floating point viewport
   113     as an offset in the final rotation stage image */
   114 static void
   115 WFC_Pipeline_TransformSource(WFC_ELEMENT_STATE* state)
   116 {
   117     OWFfloat                width, height, totalWidth, totalHeight,
   118                             leftMargin, rightMargin, 
   119                             topMargin, bottomMargin,
   120                             temp;
   121     OWF_FLIP_DIRECTION      flipping;
   122     WFCRotation             rotation;
   123     
   124     
   125     OWF_ASSERT(state);
   126     
   127     width = state->sourceRect[2];
   128     totalWidth = state->sourceRect[0] + state->sourceRect[2];
   129     
   130     height = state->sourceRect[3];
   131     totalHeight = state->sourceRect[1] + state->sourceRect[3];
   132     
   133     /* X margins - includes 1 pixel border */
   134     leftMargin = (state->sourceRect[0] - ((float) floor(state->sourceRect[0]))) + 1.0f;
   135     rightMargin = (((float) ceil(totalWidth)) - totalWidth) + 1.0f;
   136     
   137     /* Y margins - includes 1 pixel border */
   138     topMargin = (state->sourceRect[1] - ((float) floor(state->sourceRect[1]))) + 1.0f;    
   139     bottomMargin = (((float) ceil(totalHeight)) - totalHeight) + 1.0f;
   140     
   141     /* flip stages */
   142     flipping = state->sourceFlip > 0.0f ? OWF_FLIP_VERTICALLY
   143                                       : OWF_FLIP_NONE;
   144     
   145     /* top margin needs to be the bottom margin */
   146     if (flipping & OWF_FLIP_VERTICALLY)
   147     {
   148         temp = topMargin;
   149         topMargin = bottomMargin;
   150         bottomMargin = temp; 
   151     }
   152     
   153     /* rotation stages */
   154     rotation = state->rotation;
   155     
   156     switch (rotation)
   157     {
   158         case WFC_ROTATION_0:
   159         {
   160             break;
   161         }
   162 
   163         case WFC_ROTATION_90:
   164         {
   165             /* switch width and height */
   166             temp = width;
   167             width = height;
   168             height = temp;
   169             
   170             topMargin = leftMargin;
   171             leftMargin = bottomMargin;
   172             
   173             break;
   174         }
   175 
   176         case WFC_ROTATION_180:
   177         {
   178             leftMargin = rightMargin;
   179             topMargin = bottomMargin;
   180         
   181             break;
   182         }
   183 
   184         case WFC_ROTATION_270:
   185         {
   186             /* switch width and height */
   187             temp = width;
   188             width = height;
   189             height = temp; 
   190             
   191             leftMargin = topMargin;
   192             topMargin = rightMargin;
   193             
   194             break;
   195         }
   196 
   197         default:
   198         {
   199             OWF_ASSERT(0);
   200         }
   201     }    
   202     
   203     /* X offset */
   204     state->transformedSourceRect[0] = leftMargin;
   205     /* Y offset */
   206     state->transformedSourceRect[1] = topMargin;
   207     /* width */
   208     state->transformedSourceRect[2] = width;
   209     /* height */
   210     state->transformedSourceRect[3] = height;    
   211 }
   212 
   213 /*! Calculate the oversized integer crop region */
   214 static void
   215 WFC_Pipeline_OversizedViewport(WFC_ELEMENT_STATE* state)
   216 {
   217     OWFint width, height;
   218 
   219     state->oversizedCropRect.x = (int) floor(state->sourceRect[0]);
   220     state->oversizedCropRect.y = (int) floor(state->sourceRect[1]);
   221     
   222     width = (int) ceil(state->sourceRect[0] + state->sourceRect[2]);
   223     state->oversizedCropRect.width = (width - state->oversizedCropRect.x) + EXTRA_PIXEL_BOUNDARY;
   224     
   225     height = (int) ceil(state->sourceRect[1] + state->sourceRect[3]);    
   226     state->oversizedCropRect.height = (height - state->oversizedCropRect.y) + EXTRA_PIXEL_BOUNDARY;
   227 }
   228 
   229 /*-----------------------------------------------------------*
   230  * Initial creation of element state object created just once per context
   231  *-----------------------------------------------------------*/
   232 OWF_API_CALL void WFC_Pipeline_DestroyState(WFC_CONTEXT* context)
   233 {
   234     WFC_ELEMENT_STATE*      state;
   235     state= &context->prototypeElementState;
   236     OWF_Image_Destroy(state->scaledSourceImage);
   237     OWF_Image_Destroy(state->croppedSourceImage);
   238     OWF_Image_Destroy(state->convertedSourceImage);
   239     OWF_Image_Destroy(state->rotatedSourceIntermediateImage);
   240     OWF_Image_Destroy(state->flippedSourceImage);
   241     OWF_Image_Destroy(state->rotatedSourceImage);    
   242     OWF_Image_Destroy(state->maskImage);
   243     state->scaledSourceImage=NULL;
   244     state->croppedSourceImage=NULL;
   245     state->convertedSourceImage=NULL;
   246     state->rotatedSourceIntermediateImage=NULL;
   247     state->flippedSourceImage=NULL;
   248     state->rotatedSourceImage=NULL;    
   249     state->maskImage=NULL;
   250 }
   251 
   252 OWF_API_CALL OWFboolean WFC_Pipeline_CreateState(WFC_CONTEXT* context)
   253 {
   254     WFC_ELEMENT_STATE*      state;
   255     OWF_IMAGE_FORMAT        fmt;
   256     
   257     fmt.pixelFormat    = OWF_IMAGE_ARGB_INTERNAL;
   258     fmt.linear         = OWF_FALSE;
   259     fmt.premultiplied  = OWF_FALSE;
   260     fmt.rowPadding     = 1;
   261     state= &context->prototypeElementState;
   262     /* All buffers are initially created the full size of the scratch buffers, whicgh records the buffer size in bytes */
   263     state->convertedSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[1], 0);
   264     state->croppedSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[2], 0);
   265     state->flippedSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[2], 0);    
   266 
   267     state->rotatedSourceIntermediateImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[1], 0);      
   268     state->rotatedSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[2], 0);  
   269     state->scaledSourceImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[3], 0);
   270     fmt.pixelFormat    = OWF_IMAGE_L32;
   271     state->maskImage=OWF_Image_Create(MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT, &fmt, context->scratchBuffer[4], 0);
   272     if (!state->convertedSourceImage||!state->croppedSourceImage||!state->flippedSourceImage
   273         ||!state->rotatedSourceIntermediateImage||!state->rotatedSourceImage
   274         ||!state->scaledSourceImage||!state->maskImage
   275         )
   276         {
   277         WFC_Pipeline_DestroyState(context);
   278         return OWF_FALSE;
   279         }
   280     return OWF_TRUE;
   281 }
   282 
   283 
   284 /*---------------------------------------------------------------------------
   285  *  Composition pipeline preparation
   286  *
   287  *  \param context          Context
   288  *  \param element          Element
   289  *
   290  *  \return Boolean value indicating whether preparation succeeded
   291  *----------------------------------------------------------------------------*/
   292 #ifdef DEBUG
   293 /* reset size to original extent then try to set it to the target size */
   294 #define CREATE_WITH_LIMITS(img, imgW, imgH, fmt, maxW, maxH) \
   295     { \
   296         OWFboolean resized; \
   297         OWF_Image_SetSize(img, maxW, maxH); \
   298         OWF_Image_SetFlags(img,(fmt)->premultiplied,(fmt)->linear); \
   299         resized = OWF_Image_SetSize(img, imgW, imgH); \
   300         OWF_ASSERT(resized); \
   301     }
   302 #else
   303 #define CREATE_WITH_LIMITS(img, imgW, imgH, fmt, maxW, maxH) \
   304     { \
   305         OWF_Image_SetSize(img, maxW, maxH); \
   306         OWF_Image_SetFlags(img,(fmt)->premultiplied,(fmt)->linear); \
   307         OWF_Image_SetSize(img, imgW, imgH); \
   308     }
   309 #endif
   310 OWF_API_CALL WFC_ELEMENT_STATE*
   311 WFC_Pipeline_BeginComposition(WFC_CONTEXT* context, WFC_ELEMENT* element)
   312 {
   313     WFC_ELEMENT_STATE*      state = &context->prototypeElementState;
   314     OWF_IMAGE_FORMAT        imgf;
   315     OWFint                  sourceWidth;
   316     OWFint                  sourceHeight;
   317     OWFint                  x;
   318     OWFint                  tempWidth, tempHeight;
   319 
   320 
   321     DPRINT(("WFC_Element_BeginComposition(%x,%x)",
   322             context ? context->handle : 0, element ? element->handle : 0));
   323 
   324     if (!context || !element)
   325     {
   326         DPRINT(("  context == NULL || element == NULL"));
   327         return NULL;
   328     }
   329 
   330     if (!WFC_Pipeline_ElementIsVisible(context, element))
   331     {
   332         DPRINT(("  element [%x] totally outside of target - skipped",
   333                         element ? element->handle : 0));
   334         return NULL;
   335     }
   336 
   337     /* setup temporary images used in composition. since the original
   338        source data must not be altered, we must copy it to scratch buffer
   339        and work it there. another scratch buffer is needed for scaling
   340        the image to its final size. same applies for masks; thus a grand total
   341        of 4 scratch buffers are needed. */
   342     OWF_ASSERT(element->source);
   343     OWF_ASSERT(element->source->streamHandle);     
   344     
   345     state->originalSourceImage = element->source->lockedStream.image;
   346     state->rotation = element->sourceRotation;
   347     state->sourceFlip = element->sourceFlip;
   348     state->globalAlpha = element->globalAlpha;
   349     state->sourceScaleFilter = element->sourceScaleFilter;
   350     state->transparencyTypes = element->transparencyTypes;
   351 
   352     if (state->transparencyTypes & WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA)
   353         {
   354         if (state->globalAlpha == OWF_FULLY_TRANSPARENT)
   355             {
   356             /* Fully transparent element - no contribution. */
   357             return NULL;
   358             }
   359         if (state->globalAlpha == OWF_FULLY_OPAQUE)
   360             {
   361             /* Fully opaque global alpha - global alpha can be ignored */
   362             state->transparencyTypes &= ~WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA;
   363             }
   364         }
   365     
   366 /* replicate the source viewport rectangle and target extent rectangle */
   367     for (x = 0; x < 4; x++)
   368     {
   369         state->sourceRect[x] = element->srcRect[x];
   370         state->destinationRect[x] = element->dstRect[x];
   371     }
   372     OWF_Rect_Set(&state->dstRect, element->dstRect[0], element->dstRect[1],
   373                  element->dstRect[2], element->dstRect[3]);    
   374     
   375     /* transform the source rectangle to represent the floating point viewport
   376        as an offset in the final rotation stage image */
   377     WFC_Pipeline_TransformSource(state);
   378     
   379     imgf.pixelFormat    = OWF_IMAGE_ARGB_INTERNAL;
   380     imgf.linear         = element->source->lockedStream.image->format.linear;
   381     imgf.premultiplied  = element->source->lockedStream.image->format.premultiplied;
   382     imgf.rowPadding     = 1;
   383 
   384     /* add a 1 pixel boundary so we can replicate the edges */
   385     sourceWidth = element->source->lockedStream.image->width + EXTRA_PIXEL_BOUNDARY;
   386     sourceHeight = element->source->lockedStream.image->height + EXTRA_PIXEL_BOUNDARY;
   387     
   388     CREATE_WITH_LIMITS(state->convertedSourceImage,
   389                        sourceWidth,
   390                        sourceHeight,
   391                        &imgf,
   392                        MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);
   393     
   394     /* calculate the oversized integer crop region (inc. 1 pixel boundary)
   395        so edge replication can be performed */
   396     WFC_Pipeline_OversizedViewport(state);    
   397     
   398     /* subsequent temporary renderstage pipeline images need to use the oversized
   399        integer crop region */
   400     CREATE_WITH_LIMITS(state->croppedSourceImage,
   401                        state->oversizedCropRect.width, state->oversizedCropRect.height,
   402                        &imgf,
   403                        MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);
   404     
   405     CREATE_WITH_LIMITS(state->flippedSourceImage,
   406                        state->oversizedCropRect.width, state->oversizedCropRect.height,
   407                        &imgf,
   408                        MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);    
   409     
   410 
   411     if (state->rotation == WFC_ROTATION_90 || state->rotation == WFC_ROTATION_270)
   412     {
   413         tempHeight = state->oversizedCropRect.width;
   414         tempWidth = state->oversizedCropRect.height;
   415     }
   416     else
   417     {
   418         tempWidth = state->oversizedCropRect.width;
   419         tempHeight = state->oversizedCropRect.height;
   420     }
   421 
   422     CREATE_WITH_LIMITS(state->rotatedSourceIntermediateImage,
   423                        tempWidth, tempHeight,
   424                        &imgf,
   425                        MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);      
   426     
   427 
   428      /* no rotation required - just use the previous stages (flip) buffer */
   429     CREATE_WITH_LIMITS(state->rotatedSourceImage,
   430                        tempWidth, tempHeight,
   431                        &imgf,
   432                        MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);  
   433 
   434     /* finally, scaled image uses destination width and height */
   435     OWF_Rect_Set(&state->scaledSrcRect, 0, 0, element->dstRect[2], element->dstRect[3]);
   436     CREATE_WITH_LIMITS(state->scaledSourceImage,
   437                        state->scaledSrcRect.width,
   438                        state->scaledSrcRect.height,
   439                        &imgf,
   440                         MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);
   441 
   442     if (!(state->convertedSourceImage && state->croppedSourceImage &&
   443           state->scaledSourceImage && state->rotatedSourceIntermediateImage &&
   444           state->flippedSourceImage && state->rotatedSourceImage))
   445     {
   446         DPRINT(("  Preparation of intermediate pipeline image buffers failed"
   447                 "  (May be caused by overflow or out-of-memory situation)"));
   448         DPRINT(("    convertedSourceImage = %p", state->convertedSourceImage));
   449         DPRINT(("    croppedSourceImage = %p", state->croppedSourceImage));
   450         DPRINT(("    scaledSourceImage = %p", state->scaledSourceImage));
   451         DPRINT(("    rotatedSourceIntermediateImage = %p", state->rotatedSourceIntermediateImage));
   452         DPRINT(("    flippedSourceImage = %p", state->flippedSourceImage));
   453         DPRINT(("    rotatedSourceImage = %p", state->rotatedSourceImage));
   454 
   455 
   456         return (WFC_ELEMENT_STATE*)WFC_FALSE;
   457     }
   458 
   459 #ifdef DEBUG
   460         OWF_Image_Clear(state->convertedSourceImage, 0, 0, 0, 0);
   461         OWF_Image_Clear(state->croppedSourceImage, 0, 0, 0, 0);
   462         OWF_Image_Clear(state->scaledSourceImage, 0, 0, 0, 0);
   463         OWF_Image_Clear(state->rotatedSourceIntermediateImage, 0, 0, 0, 0);
   464         OWF_Image_Clear(state->flippedSourceImage, 0, 0, 0, 0);
   465         OWF_Image_Clear(state->rotatedSourceImage, 0, 0, 0, 0);
   466 #endif
   467 
   468     /* setup mask in case the element has one */
   469     if (element->maskComposed)
   470     {
   471         OWF_IMAGE*          image = NULL;
   472         OWFsubpixel*        pix = NULL;
   473         WFCint              i = 0;
   474 
   475         DPRINT(("Processing element mask"));
   476         OWF_ASSERT(&element->mask);
   477         OWF_ASSERT(&element->mask->streamHandle);
   478         image = element->mask->lockedStream.image;
   479         OWF_ASSERT(image);
   480 
   481         state->originalMaskImage = element->mask->lockedStream.image;        
   482         
   483         imgf.pixelFormat    = OWF_IMAGE_L32;
   484         imgf.linear         = image->format.linear;
   485         imgf.premultiplied  = image->format.premultiplied;
   486 
   487         /* mask size is always same as destination rect's */
   488         DPRINT(("Binding stream image to scratch buffer"));
   489         CREATE_WITH_LIMITS(state->maskImage,
   490                            state->scaledSrcRect.width,
   491                            state->scaledSrcRect.height,
   492                            &imgf,
   493                            MAX_SOURCE_WIDTH, MAX_SOURCE_HEIGHT);
   494 
   495         /* initialize mask */
   496         DPRINT(("Initializing mask, size = %dx%d", state->scaledSrcRect.width,
   497                 state->scaledSrcRect.height));
   498         pix = (OWFsubpixel*) state->maskImage->data;
   499         for (i = 0; i < state->scaledSrcRect.width * state->scaledSrcRect.height; i++)
   500         {
   501             pix[i] = OWF_FULLY_OPAQUE;
   502         }
   503     }
   504     else
   505         {
   506         state->originalMaskImage=NULL;
   507         }
   508     
   509     WFC_Pipeline_BlendInfo(context, state);
   510 
   511     DPRINT(("  Cropped source image size is %dx%d",
   512            state->croppedSourceImage->width, state->croppedSourceImage->height));
   513     DPRINT(("  Scaled source image size is %dx%d",
   514             state->scaledSourceImage->width, state->scaledSourceImage->height));
   515     DPRINT(("  Mirrored source intermediate image size is %dx%d",
   516             state->rotatedSourceIntermediateImage->width, state->rotatedSourceIntermediateImage->height));
   517     DPRINT(("  Mirrored source image size is %dx%d",
   518             state->flippedSourceImage->width, state->flippedSourceImage->height));
   519     DPRINT(("  Rotated source image size is %dx%d",
   520             state->rotatedSourceImage->width, state->rotatedSourceImage->height));  
   521     
   522     return state;
   523 }
   524 
   525 /*---------------------------------------------------------------------------
   526  *  Composition pipeline cleanup
   527  *
   528  *  \param context          Context
   529  *  \param element          Element
   530  *----------------------------------------------------------------------------*/
   531 OWF_API_CALL void
   532 WFC_Pipeline_EndComposition(WFC_CONTEXT* context, WFC_ELEMENT* element, WFC_ELEMENT_STATE* state)
   533 {
   534 
   535     if (!context || !element)
   536     {
   537         DPRINT(("WFC_Element_EndComposition: context == NULL || "
   538                 "element == NULL"));
   539     }
   540 
   541 
   542     OWF_ASSERT(state);
   543     state->originalSourceImage=NULL;
   544     state->originalMaskImage=NULL;
   545 
   546 }
   547 
   548 /*---------------------------------------------------------------------------
   549  *  \brief Source conversion stage
   550  *
   551  *  \param context          Context
   552  *  \param element          Element
   553  *----------------------------------------------------------------------------*/
   554 OWF_API_CALL void
   555 WFC_Pipeline_ExecuteSourceConversionStage(WFC_CONTEXT* context,
   556         WFC_ELEMENT_STATE* state)
   557 {
   558     /* this stage could be embedded in cropping stage */
   559 
   560 
   561     if (NULL == context || NULL == state)
   562     {
   563         DPRINT(("WFC_Context_ExecuteSourceConversionStage: context = %p, "
   564                 "state = %p",
   565                 context, state));
   566         return;
   567     }
   568 
   569     OWF_ASSERT(state->originalSourceImage);
   570 
   571     OWF_Image_SourceFormatConversion(state->convertedSourceImage,
   572                                      state->originalSourceImage);
   573 
   574     /* convert mask from stream format to internal format */
   575     if (state->originalMaskImage)
   576     {
   577         if (!OWF_Image_ConvertMask(state->maskImage, state->originalMaskImage))
   578         {
   579             state->originalMaskImage=NULL;
   580         }
   581     }
   582 }
   583 
   584 /*---------------------------------------------------------------------------
   585  *  \brief Crop stage
   586  *
   587  *  \param context          Context
   588  *  \param element          Element
   589  *----------------------------------------------------------------------------*/
   590 OWF_API_CALL void
   591 WFC_Pipeline_ExecuteCropStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state)
   592 {
   593     OWF_RECTANGLE           sourceRect,
   594                             cropRect;
   595 
   596     DPRINT(("WFC_Pipeline_ExecuteCropStage"));
   597 
   598     if (NULL == context || NULL == state)
   599     {
   600         DPRINT(("WFC_Context_ExecuteCropStage: context = %p, state = %p",
   601                context, state));
   602     }
   603     else
   604     {
   605         /* Source rectangle */
   606         OWF_Rect_Set(&sourceRect,
   607                      state->oversizedCropRect.x, state->oversizedCropRect.y,
   608                      state->oversizedCropRect.width, state->oversizedCropRect.height);
   609 
   610         /* cropped source size - supports oversized integer and 1 pixel boundary */
   611         OWF_Rect_Set(&cropRect,
   612                      0, 0,
   613                      state->oversizedCropRect.width, state->oversizedCropRect.height);
   614 
   615         OWF_Image_Blit(state->croppedSourceImage, &cropRect,
   616                        state->convertedSourceImage, &sourceRect);
   617     }
   618 }
   619 
   620 /*---------------------------------------------------------------------------
   621  *  \brief Flip stage
   622  *
   623  *  \param context          Context
   624  *  \param element          Element
   625  *----------------------------------------------------------------------------*/
   626 OWF_API_CALL void
   627 WFC_Pipeline_ExecuteFlipStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state)
   628 {
   629     OWF_FLIP_DIRECTION      flipping;
   630 	
   631     if (NULL == context || NULL == state)
   632     {
   633         DPRINT(("WFC_Context_ExecuteFlipStage: context = %p, state = %p",
   634                context, state));
   635     }
   636     else
   637     {
   638         flipping = state->sourceFlip > 0.0f ? OWF_FLIP_VERTICALLY
   639                                           : OWF_FLIP_NONE;
   640         
   641         OWF_Image_Flip(state->flippedSourceImage, flipping);
   642     }
   643 }
   644 
   645 /*---------------------------------------------------------------------------
   646  *  \brief Rotation stage
   647  *
   648  *  \param context          Context
   649  *  \param element          Element
   650  *----------------------------------------------------------------------------*/
   651 OWF_API_CALL void
   652 WFC_Pipeline_ExecuteRotationStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state)
   653 {
   654     OWF_ROTATION            rot = OWF_ROTATION_0;
   655     OWF_RECTANGLE           rect;    
   656     WFCRotation             rotation;
   657 
   658     if (NULL == context || NULL == state)
   659     {
   660         DPRINT(("WFC_Context_ExecuteRotationStage: context = %p, state = %p",
   661                context, state));
   662         return;
   663     }
   664 
   665     rotation = state->rotation;
   666     DPRINT(("  Element rotation = %d", rotation));
   667 
   668     switch (rotation)
   669     {
   670         case WFC_ROTATION_0:
   671         {
   672             return; /* Rotate copies back into input buffer so just skip */
   673         }
   674 
   675         case WFC_ROTATION_90:
   676         {
   677             rot = OWF_ROTATION_90;
   678             break;
   679         }
   680 
   681         case WFC_ROTATION_180:
   682         {
   683             rot = OWF_ROTATION_180;
   684             break;
   685         }
   686 
   687         case WFC_ROTATION_270:
   688         {
   689             rot = OWF_ROTATION_270;
   690             break;
   691         }
   692 
   693         default:
   694         {
   695             OWF_ASSERT(0);
   696         }
   697     }
   698 
   699     /* rotate the the image using rotatedSourceIntermediateImage */
   700     OWF_Image_Rotate(state->rotatedSourceIntermediateImage,
   701                      state->flippedSourceImage,
   702                      rot);
   703 
   704     /* blit rotated image back to original image buffer */
   705     rect.x      = 0;
   706     rect.y      = 0;
   707     rect.width  = state->rotatedSourceIntermediateImage->width;
   708     rect.height = state->rotatedSourceIntermediateImage->height;
   709 
   710     DPRINT(("  Source image dimensions after rotation = %dx%d",
   711            rect.width, rect.height));
   712 
   713     OWF_Image_Blit(state->rotatedSourceImage,
   714                    &rect,
   715                    state->rotatedSourceIntermediateImage,
   716                    &rect);
   717     
   718 }
   719 
   720 /*---------------------------------------------------------------------------
   721  *  \brief Scaling stage
   722  *
   723  *  \param context          Context
   724  *  \param element          Element
   725  *----------------------------------------------------------------------------*/
   726 OWF_API_CALL void
   727 WFC_Pipeline_ExecuteScalingStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state)
   728 {
   729     OWF_RECTANGLE           scaledRect,
   730                             cropRect;
   731     OWF_FILTERING           filteringMode = OWF_FILTER_POINT_SAMPLING;
   732     WFCScaleFilter          filter;
   733 	
   734     DPRINT(("WFC_Context_ExecuteScalingStage(%p,%p)", context, state));
   735 
   736     if (NULL == context || NULL == state)
   737     {
   738         DPRINT(("WFC_Context_ExecuteScalingStage: context = %p, state = %p",
   739                context, state));
   740         return;
   741     }
   742 
   743     filter = state->sourceScaleFilter;
   744 
   745     switch (filter)
   746     {
   747         case WFC_SCALE_FILTER_NONE:
   748         case WFC_SCALE_FILTER_FASTER:
   749         {
   750             filteringMode = OWF_FILTER_POINT_SAMPLING;
   751             DPRINT(("  Using point-sampling filter"));
   752             break;
   753         }
   754         case WFC_SCALE_FILTER_BETTER:
   755         {
   756             filteringMode = OWF_FILTER_BILINEAR;
   757             DPRINT(("  Using bilinear filter"));
   758             break;
   759         }
   760 
   761         case WFC_SCALE_FILTER_FORCE_32BIT:
   762         {
   763             /* To shut the compiler up -- not a valid filtering mode.
   764              * Validity is ensured when the filter attribute value
   765              * is set, thus it shouldn't have this value ever. */
   766             OWF_ASSERT(0);
   767             break;
   768         }
   769     }
   770 
   771     OWF_Rect_Set(&cropRect, 1, 1,
   772                  state->rotatedSourceImage->width - EXTRA_PIXEL_BOUNDARY,
   773                  state->rotatedSourceImage->height - EXTRA_PIXEL_BOUNDARY);
   774 
   775     OWF_Rect_Set(&scaledRect, 0, 0, state->destinationRect[2], state->destinationRect[3]);
   776     
   777     if (  scaledRect.width != state->transformedSourceRect[2] 
   778       ||  scaledRect.height != state->transformedSourceRect[3]
   779       ||  state->sourceRect[0] != floor(state->sourceRect[0])
   780       ||  state->sourceRect[1] != floor(state->sourceRect[1])
   781     )
   782     {
   783         /* scale the image */
   784         OWF_Image_Stretch(state->scaledSourceImage, &scaledRect,
   785                           state->rotatedSourceImage, state->transformedSourceRect,
   786                           filteringMode);
   787     }
   788     else
   789     {
   790         /* 1:1 copy, no need to scale */
   791         OWF_Image_Blit(state->scaledSourceImage, &scaledRect,
   792                        state->rotatedSourceImage, &cropRect);
   793     }
   794     
   795 }
   796 
   797 /*---------------------------------------------------------------------------
   798  *  \brief Blending stage
   799  *
   800  *  \param context          Context
   801  *  \param element          Element
   802  *----------------------------------------------------------------------------*/
   803 OWF_API_CALL void
   804 WFC_Pipeline_ExecuteBlendingStage(WFC_CONTEXT* context, WFC_ELEMENT_STATE* state)
   805 {
   806     OWF_TRANSPARENCY        blendMode = OWF_TRANSPARENCY_NONE;
   807     WFCbitfield             transparency = 0;
   808 	
   809     DPRINT(("WFC_Pipeline_ExecuteBlendingStage"));
   810 
   811     if (NULL == context || NULL == state)
   812     {
   813         return;
   814     }
   815 
   816     DPRINT(("  context = %d, state = %d",
   817            context->handle, state));
   818 
   819     transparency = state->transparencyTypes;
   820     blendMode = OWF_TRANSPARENCY_NONE;
   821 
   822     if (transparency & WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA)
   823     {
   824         blendMode = (OWF_TRANSPARENCY)(blendMode|OWF_TRANSPARENCY_GLOBAL_ALPHA);
   825     }
   826 
   827     if (transparency & WFC_TRANSPARENCY_SOURCE)
   828     {
   829         OWF_Image_PremultiplyAlpha(state->scaledSourceImage);
   830         blendMode = (OWF_TRANSPARENCY)(blendMode|OWF_TRANSPARENCY_SOURCE_ALPHA);
   831     }
   832 
   833     if ((transparency & WFC_TRANSPARENCY_MASK) && state->originalMaskImage)
   834     {
   835         blendMode = (OWF_TRANSPARENCY)(blendMode|OWF_TRANSPARENCY_MASK);
   836     }
   837 
   838     OWF_Image_Blend(&state->blendInfo, blendMode);
   839 }