graphicscomposition/openwfcompositionengine/composition/src/wfcelement.c
changeset 0 5d03bc08d59c
child 36 01a6848ebfd7
child 139 975c90a56547
child 163 bbf46f59e123
equal deleted inserted replaced
-1:000000000000 0:5d03bc08d59c
       
     1 /* Copyright (c) 2009 The Khronos Group Inc.
       
     2  *
       
     3  * Permission is hereby granted, free of charge, to any person obtaining a
       
     4  * copy of this software and/or associated documentation files (the
       
     5  * "Materials"), to deal in the Materials without restriction, including
       
     6  * without limitation the rights to use, copy, modify, merge, publish,
       
     7  * distribute, sublicense, and/or sell copies of the Materials, and to
       
     8  * permit persons to whom the Materials are furnished to do so, subject to
       
     9  * the following conditions:
       
    10  *
       
    11  * The above copyright notice and this permission notice shall be included
       
    12  * in all copies or substantial portions of the Materials.
       
    13  *
       
    14  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       
    15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       
    16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
       
    17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
       
    18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
       
    19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       
    20  * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
       
    21  */
       
    22 /*! \ingroup wfc
       
    23  *  \file wfcelement.c
       
    24  *
       
    25  *  \brief SI Element handling
       
    26  */
       
    27 #include <stdio.h>
       
    28 #include <stdlib.h>
       
    29 #include <math.h>
       
    30 #include <string.h>
       
    31 
       
    32 #include <WF/wfc.h>
       
    33 
       
    34 #include "wfcelement.h"
       
    35 #include "wfccontext.h"
       
    36 #include "wfcdevice.h"
       
    37 #include "wfcstructs.h"
       
    38 #include "wfcimageprovider.h"
       
    39 #include "owfnativestream.h"
       
    40 #include "owfattributes.h"
       
    41 #include "owfmemory.h"
       
    42 #include "owfobject.h"
       
    43 
       
    44 #include "owfdebug.h"
       
    45 
       
    46 #ifdef __cplusplus
       
    47 extern "C" {
       
    48 #endif
       
    49 
       
    50 #define FIRST_ELEMENT_HANDLE    3000
       
    51 
       
    52 #define FAIL_IF(c,e)        if (c) { return e; }
       
    53 
       
    54 
       
    55 static const WFCbitfield    validTransparencyModes[] = {
       
    56                                 WFC_TRANSPARENCY_NONE,
       
    57                                 WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA,
       
    58                                 WFC_TRANSPARENCY_SOURCE,
       
    59                                 WFC_TRANSPARENCY_MASK,
       
    60                                 WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA |
       
    61                                     WFC_TRANSPARENCY_SOURCE,
       
    62                                 WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA |
       
    63                                     WFC_TRANSPARENCY_MASK
       
    64                             };
       
    65 
       
    66 /*---------------------------------------------------------------------------
       
    67  *
       
    68  *----------------------------------------------------------------------------*/
       
    69 void
       
    70 WFC_Element_Initialize(WFC_ELEMENT* element)
       
    71 {
       
    72     element->dstRect[0]         = 0;
       
    73     element->dstRect[1]         = 0;
       
    74     element->dstRect[2]         = 0;
       
    75     element->dstRect[3]         = 0;
       
    76     element->srcRect[0]         = 0;
       
    77     element->srcRect[1]         = 0;
       
    78     element->srcRect[2]         = 0;
       
    79     element->srcRect[3]         = 0;
       
    80 
       
    81     element->source             = WFC_INVALID_HANDLE;
       
    82     element->sourceFlip         = WFC_FALSE;
       
    83     element->sourceRotation     = WFC_ROTATION_0;
       
    84     element->sourceScaleFilter  = WFC_SCALE_FILTER_NONE;
       
    85     element->transparencyTypes  = 0;
       
    86     element->globalAlpha        = OWF_ALPHA_MAX_VALUE;
       
    87     element->maskHandle         = WFC_INVALID_HANDLE;
       
    88     element->sourceHandle       = WFC_INVALID_HANDLE;
       
    89 }
       
    90 
       
    91 /*---------------------------------------------------------------------------
       
    92  *
       
    93  *----------------------------------------------------------------------------*/
       
    94 OWF_API_CALL void
       
    95 WFC_Element_Destroy(WFC_ELEMENT* element)
       
    96 {
       
    97     if (element)
       
    98     {
       
    99         DPRINT(("WFC_Element_Destroy"));
       
   100 
       
   101         DPRINT(("  element = %p (%d)", element, element->handle));
       
   102 
       
   103         DESTROY(element->cachedSource);
       
   104         DESTROY(element->cachedMask);
       
   105 
       
   106         DPRINT(("  cachedSource = %p (%d)", element->cachedSource,
       
   107                                             element->cachedSource ?
       
   108                                                 element->cachedSource->handle :
       
   109                                                 0));
       
   110         DPRINT(("  cachedMask = %p (%d)", element->cachedMask,
       
   111                                           element->cachedMask ?
       
   112                                               element->cachedMask->handle :
       
   113                                               0));
       
   114 
       
   115         DESTROY(element->source);
       
   116         DESTROY(element->mask);
       
   117 
       
   118         DPRINT(("  source = %p (%d)", element->source,
       
   119                                       element->source ?
       
   120                                           element->source->handle :
       
   121                                           0));
       
   122         DPRINT(("  mask = %p (%d)", element->mask,
       
   123                                     element->mask ?
       
   124                                         element->mask->handle :
       
   125                                         0));
       
   126         DESTROY(element->context);
       
   127 
       
   128         OWF_Pool_PutObject(element);
       
   129     }
       
   130 }
       
   131 
       
   132 /*---------------------------------------------------------------------------
       
   133  *  Create new element into context
       
   134  *
       
   135  *  \param context Context into which to create the element
       
   136  *
       
   137  *  \return New element object or NULL
       
   138  *----------------------------------------------------------------------------*/
       
   139 OWF_API_CALL WFC_ELEMENT*
       
   140 WFC_Element_Create(WFC_CONTEXT* context)
       
   141 {
       
   142     static WFCint           nextElementHandle = FIRST_ELEMENT_HANDLE;
       
   143     WFC_ELEMENT*            element;
       
   144 
       
   145     element = (WFC_ELEMENT*)OWF_Pool_GetObject(context->elementPool);
       
   146 
       
   147     if (element)
       
   148     {
       
   149         WFC_Element_Initialize(element);
       
   150 
       
   151         element->handle = nextElementHandle++;
       
   152 
       
   153         ADDREF(element->context, context);
       
   154         element->device = context->device;
       
   155     }
       
   156     return element;
       
   157 }
       
   158 
       
   159 /*---------------------------------------------------------------------------
       
   160  *
       
   161  *----------------------------------------------------------------------------*/
       
   162 OWF_API_CALL WFC_ELEMENT*
       
   163 WFC_Element_Clone(WFC_ELEMENT* element)
       
   164 {
       
   165     WFC_ELEMENT*        clone;
       
   166     WFC_CONTEXT*        context;
       
   167 
       
   168     OWF_ASSERT(element);
       
   169 
       
   170     DPRINT(("WFC_Element_Clone: element = %d, context = %d", element->handle,
       
   171             element->context->handle));
       
   172 
       
   173     context = CONTEXT(element->context);
       
   174     clone = (WFC_ELEMENT*)OWF_Pool_GetObject(context->elementPool);
       
   175 
       
   176     if (clone)
       
   177     {
       
   178         WFC_Element_Initialize(clone);
       
   179 
       
   180         clone->handle           = element->handle;
       
   181 
       
   182         clone->sourceFlip       = element->sourceFlip;
       
   183         clone->sourceRotation   = element->sourceRotation;
       
   184         clone->sourceScaleFilter= element->sourceScaleFilter;
       
   185         clone->transparencyTypes= element->transparencyTypes;
       
   186         clone->globalAlpha      = element->globalAlpha;
       
   187         clone->maskHandle       = element->maskHandle;
       
   188         clone->sourceHandle     = element->sourceHandle;
       
   189 
       
   190         ADDREF(clone->cachedMask, element->cachedMask);
       
   191         ADDREF(clone->cachedSource, element->cachedSource);
       
   192 
       
   193         ADDREF(clone->mask,     element->mask);
       
   194         ADDREF(clone->source,   element->source);
       
   195         clone->device = element->device;
       
   196 
       
   197         ADDREF(clone->context,  element->context);
       
   198 
       
   199         memcpy(clone->srcRect,  element->srcRect, 4 * sizeof(WFCfloat));
       
   200         memcpy(clone->dstRect,  element->dstRect, 4 * sizeof(WFCfloat));
       
   201 
       
   202     }
       
   203 
       
   204     return clone;
       
   205 }
       
   206 
       
   207 /*---------------------------------------------------------------------------
       
   208  *
       
   209  *----------------------------------------------------------------------------*/
       
   210 static WFCboolean WFC_Element_ClampRectangle(const char* rtype,
       
   211                                              WFCfloat* rect)
       
   212 {
       
   213     /*
       
   214      * int -> float conversion:
       
   215      * ------------------------
       
   216      *
       
   217      * above 2^24 we start to lose precision when performing
       
   218      * conversions between floats & ints, thus we must clamp
       
   219      * values above in order to avoid nasty sign-change effects
       
   220      * and other weird side-effects.
       
   221      *
       
   222      */
       
   223 
       
   224     const WFCfloat          LIMIT = 1.6777216E7f;
       
   225     WFCint                  i;
       
   226     WFCboolean              clamped = WFC_FALSE;
       
   227 
       
   228     /* Prevent compiler warning when DPRINT is disabled */
       
   229     (void) rtype;
       
   230 
       
   231     for (i = 0; i < 4; i++)
       
   232     {
       
   233         if (fabs(rect[i]) > LIMIT)
       
   234         {
       
   235 #ifdef DEBUG
       
   236             static const char* coord[4] = {"x", "y", "width", "height"};
       
   237             (void)coord[0];
       
   238 #endif
       
   239 
       
   240             DPRINT(("  Warning: Precision loss in element's %s rectangle's "
       
   241                     "%s coordinate.",
       
   242                     rtype, coord[i]));
       
   243 
       
   244             rect[i] = rect[i] < 0 ? -LIMIT : LIMIT;
       
   245 
       
   246             clamped = WFC_TRUE;
       
   247         }
       
   248     }
       
   249     return clamped;
       
   250 }
       
   251 /*===========================================================================
       
   252  *
       
   253  * Attribute set-time checking functions. These are used for checking
       
   254  * the attributes before saving them into elements. Attributes are validated
       
   255  * for 2nd time during commit, where e.g. destination rectangle size vs.
       
   256  * mask size dependency is checked.
       
   257  *
       
   258  *============================================================================*/
       
   259 
       
   260 /*---------------------------------------------------------------------------
       
   261  *
       
   262  *----------------------------------------------------------------------------*/
       
   263 static WFCErrorCode
       
   264 WFC_Element_ValidateSourceRectangle(WFC_ELEMENT* element,
       
   265                                     WFCfloat* rect)
       
   266 {
       
   267     WFCErrorCode            result = WFC_ERROR_NONE;
       
   268     
       
   269 #ifndef DEBUG
       
   270     (void) element;
       
   271 #endif    
       
   272 
       
   273     OWF_ASSERT(element);
       
   274     OWF_ASSERT(rect);
       
   275 
       
   276     if (rect[0] < 0.0f || rect[1] < 0.0f || rect[2] < 0.0f || rect[3] < 0.0f)
       
   277     {
       
   278         result = WFC_ERROR_ILLEGAL_ARGUMENT;
       
   279     }
       
   280     else if (WFC_Element_ClampRectangle("source", rect))
       
   281     {
       
   282         result = WFC_ERROR_NONE;
       
   283     }
       
   284     return result;
       
   285 }
       
   286 
       
   287 /*---------------------------------------------------------------------------
       
   288  *
       
   289  *----------------------------------------------------------------------------*/
       
   290 static WFCErrorCode
       
   291 WFC_Element_ValidateDestinationRectangle(WFC_ELEMENT* element,
       
   292                                          WFCfloat* rect)
       
   293 {
       
   294     WFCErrorCode            result = WFC_ERROR_NONE;
       
   295 
       
   296 #ifndef DEBUG
       
   297     (void) element;
       
   298 #endif    
       
   299     
       
   300     OWF_ASSERT(element);
       
   301     OWF_ASSERT(rect);
       
   302 
       
   303     DPRINT(("WFC_Element_ValidateDestinationRectangle(element = %d)",
       
   304             element->handle));
       
   305 
       
   306     if (rect[2] < 0.0f || rect[3] < 0.0f)
       
   307     {
       
   308         result = WFC_ERROR_ILLEGAL_ARGUMENT;
       
   309     }
       
   310     else if (WFC_Element_ClampRectangle("destination", rect))
       
   311     {
       
   312         /* ... return error or something here? */
       
   313         result = WFC_ERROR_NONE;
       
   314     }
       
   315 
       
   316     /* Hmm.. let's clamp the rectangle even more! To 16k*16k at max;
       
   317      * in OWF_Image_Create we calculate the byte size of the image buffer
       
   318      * required, and if we have 4bpp, we get overflow for pixelcounts
       
   319      * >= 65536*16384. */
       
   320     rect[2] = CLAMP(rect[2], 0, 16384);
       
   321     rect[3] = CLAMP(rect[3], 0, 16384);
       
   322 
       
   323     return result;
       
   324 }
       
   325 
       
   326 #define BOOLEAN_TO_ERROR(x) ((x) ? WFC_ERROR_NONE : WFC_ERROR_ILLEGAL_ARGUMENT)
       
   327 
       
   328 /*---------------------------------------------------------------------------
       
   329  *
       
   330  *----------------------------------------------------------------------------*/
       
   331 static WFCErrorCode
       
   332 WFC_Element_ValidateScalarAttributei(WFC_ELEMENT* element,
       
   333                                      WFCElementAttrib attrib,
       
   334                                      WFCint value)
       
   335 {
       
   336     WFCErrorCode            result = WFC_ERROR_NONE;
       
   337 
       
   338     OWF_ASSERT(element);
       
   339 
       
   340     switch (attrib)
       
   341     {
       
   342         case WFC_ELEMENT_SOURCE:
       
   343         {
       
   344             WFC_IMAGE_PROVIDER* source;
       
   345 
       
   346             source = WFC_Device_FindImageProvider(element->device,
       
   347                                                   value,
       
   348                                                   WFC_IMAGE_SOURCE);
       
   349 
       
   350             result = BOOLEAN_TO_ERROR((WFC_INVALID_HANDLE == value) ||
       
   351                                       ((WFC_INVALID_HANDLE != value) &&
       
   352                                        (NULL != source)));
       
   353             break;
       
   354         }
       
   355 
       
   356         case WFC_ELEMENT_MASK:
       
   357         {
       
   358             WFC_IMAGE_PROVIDER* mask;
       
   359 
       
   360             mask = WFC_Device_FindImageProvider(element->device,
       
   361                                                 value,
       
   362                                                 WFC_IMAGE_MASK);
       
   363 
       
   364             result = BOOLEAN_TO_ERROR((WFC_INVALID_HANDLE == value) ||
       
   365                                       ((WFC_INVALID_HANDLE != value) &&
       
   366                                        (NULL != mask)));
       
   367             break;
       
   368         }
       
   369 
       
   370         case WFC_ELEMENT_SOURCE_ROTATION:
       
   371         {
       
   372             WFCRotation rotation = (WFCRotation) value;
       
   373 
       
   374             result = BOOLEAN_TO_ERROR((WFC_ROTATION_0    == rotation ||
       
   375                                        WFC_ROTATION_90   == rotation ||
       
   376                                        WFC_ROTATION_180  == rotation ||
       
   377                                        WFC_ROTATION_270  == rotation));
       
   378             break;
       
   379         }
       
   380 
       
   381         case WFC_ELEMENT_SOURCE_SCALE_FILTER:
       
   382         {
       
   383             WFCScaleFilter  filter = (WFCScaleFilter) value;
       
   384 
       
   385             result = BOOLEAN_TO_ERROR((WFC_SCALE_FILTER_NONE     == filter ||
       
   386                                        WFC_SCALE_FILTER_FASTER   == filter ||
       
   387                                        WFC_SCALE_FILTER_BETTER   == filter));
       
   388             break;
       
   389         }
       
   390 
       
   391         case WFC_ELEMENT_SOURCE_FLIP:
       
   392         {
       
   393             WFCboolean  flip = (WFCboolean) value;
       
   394 
       
   395             result = BOOLEAN_TO_ERROR((WFC_TRUE == flip ||
       
   396                                        WFC_FALSE == flip));
       
   397             break;
       
   398         }
       
   399 
       
   400         case WFC_ELEMENT_TRANSPARENCY_TYPES:
       
   401         {
       
   402             WFCint          ii;
       
   403             WFCint          count = sizeof(validTransparencyModes) /
       
   404                                     sizeof(WFCbitfield);
       
   405             WFCbitfield     types = (WFCbitfield) value;
       
   406 
       
   407             result = WFC_ERROR_ILLEGAL_ARGUMENT;
       
   408             for (ii = 0; ii < count; ii++) {
       
   409                 if (types == validTransparencyModes[ii])
       
   410                 {
       
   411                     result = WFC_ERROR_NONE;
       
   412                     break;
       
   413                 }
       
   414             }
       
   415             break;
       
   416         }
       
   417 
       
   418         default:
       
   419         {
       
   420             result = WFC_ERROR_BAD_ATTRIBUTE;
       
   421             break;
       
   422         }
       
   423     }
       
   424     return result;
       
   425 }
       
   426 
       
   427 /*---------------------------------------------------------------------------
       
   428  *
       
   429  *----------------------------------------------------------------------------*/
       
   430 static WFCErrorCode
       
   431 WFC_Element_ValidateScalarAttributef(WFC_ELEMENT* element,
       
   432                                      WFCElementAttrib attrib,
       
   433                                      WFCfloat value)
       
   434 {
       
   435     WFCErrorCode          result = WFC_ERROR_NONE;
       
   436 
       
   437 #ifndef DEBUG
       
   438     (void) element;
       
   439 #endif
       
   440     
       
   441     OWF_ASSERT(element);
       
   442 
       
   443     switch (attrib)
       
   444     {
       
   445         case WFC_ELEMENT_GLOBAL_ALPHA:
       
   446         {
       
   447             result = BOOLEAN_TO_ERROR(value >= OWF_ALPHA_MIN_VALUE &&
       
   448                                       value <= OWF_ALPHA_MAX_VALUE);
       
   449             break;
       
   450         }
       
   451 
       
   452         /* SPECIAL CASES */
       
   453         case WFC_ELEMENT_SOURCE_FLIP:
       
   454         case WFC_ELEMENT_SOURCE_ROTATION:
       
   455         case WFC_ELEMENT_SOURCE_SCALE_FILTER:
       
   456         case WFC_ELEMENT_TRANSPARENCY_TYPES:
       
   457         case WFC_ELEMENT_SOURCE:
       
   458         case WFC_ELEMENT_MASK:
       
   459         {
       
   460             /* NOTE! special early out here. */
       
   461             result = WFC_ERROR_BAD_ATTRIBUTE;
       
   462             break;
       
   463         }
       
   464 
       
   465         default:
       
   466         {
       
   467             result = WFC_ERROR_ILLEGAL_ARGUMENT;
       
   468             break;
       
   469         }
       
   470     }
       
   471 
       
   472     return result;
       
   473 }
       
   474 
       
   475 /*---------------------------------------------------------------------------
       
   476  *
       
   477  *----------------------------------------------------------------------------*/
       
   478 static void
       
   479 WFC_Element_SetElementImageProvider(WFC_ELEMENT* element,
       
   480                                     WFC_IMAGE_PROVIDER_TYPE type,
       
   481                                     WFCHandle handle)
       
   482 {
       
   483     WFC_IMAGE_PROVIDER*     provider;
       
   484 
       
   485     OWF_ASSERT(element);
       
   486 
       
   487     provider = WFC_Device_FindImageProvider(element->device, handle, type);
       
   488 
       
   489     switch (type)
       
   490     {
       
   491         case WFC_IMAGE_SOURCE:
       
   492         {
       
   493             DESTROY(element->cachedSource);
       
   494             ADDREF(element->cachedSource, provider);
       
   495             element->sourceHandle = handle;
       
   496             break;
       
   497         }
       
   498         case WFC_IMAGE_MASK:
       
   499         {
       
   500             DESTROY(element->cachedMask);
       
   501             ADDREF(element->cachedMask, provider);
       
   502             element->maskHandle = handle;
       
   503             break;
       
   504         }
       
   505     }
       
   506 }
       
   507 
       
   508 /*---------------------------------------------------------------------------
       
   509  *  \brief Set vector integer attribute for an element
       
   510  *
       
   511  *  \param element          Element
       
   512  *  \param attrib           Attribute name
       
   513  *  \param count            Attribute size
       
   514  *  \param values           Attribute vector value
       
   515  *
       
   516  *----------------------------------------------------------------------------*/
       
   517 OWF_API_CALL WFCErrorCode
       
   518 WFC_Element_SetAttribiv(WFC_ELEMENT* element,
       
   519                         WFCElementAttrib attrib,
       
   520                         WFCint count,
       
   521                         const WFCint* values)
       
   522 {
       
   523     WFCErrorCode            result = WFC_ERROR_NONE;
       
   524 
       
   525 
       
   526     FAIL_IF(NULL == values, WFC_ERROR_ILLEGAL_ARGUMENT);
       
   527 
       
   528     switch (attrib)
       
   529     {
       
   530         /* Vector attributes */
       
   531         case WFC_ELEMENT_SOURCE_RECTANGLE:
       
   532         case WFC_ELEMENT_DESTINATION_RECTANGLE:
       
   533         {
       
   534             WFCfloat                rect[4];
       
   535 
       
   536             rect[0] = values[0];
       
   537             rect[1] = values[1];
       
   538             rect[2] = values[2];
       
   539             rect[3] = values[3];
       
   540 
       
   541             result = WFC_Element_SetAttribfv(element, attrib, count, rect);
       
   542             break;
       
   543         }
       
   544 
       
   545         case WFC_ELEMENT_GLOBAL_ALPHA:
       
   546         {
       
   547             WFCfloat    fvalue = values[0] /
       
   548                                  (WFCfloat) OWF_BYTE_MAX_VALUE;
       
   549 
       
   550             result = WFC_Element_SetAttribfv(element,
       
   551                                              attrib,
       
   552                                              1,
       
   553                                              &fvalue);
       
   554             break;
       
   555         }
       
   556 
       
   557         /* Scalar attributes */
       
   558         default:
       
   559         {
       
   560             WFCint          value;
       
   561 
       
   562             FAIL_IF(1 != count, WFC_ERROR_ILLEGAL_ARGUMENT);
       
   563 
       
   564             value = values[0];
       
   565 
       
   566             /* Validate the value thus ensuring it is safe to change it */
       
   567             result = WFC_Element_ValidateScalarAttributei(element,
       
   568                                                           attrib,
       
   569                                                           value);
       
   570             if (WFC_ERROR_NONE != result)
       
   571             {
       
   572                 break;
       
   573             }
       
   574 
       
   575             switch (attrib)
       
   576             {
       
   577                 case WFC_ELEMENT_SOURCE:
       
   578                 {
       
   579                     WFC_Element_SetElementImageProvider(element,
       
   580                                                         WFC_IMAGE_SOURCE,
       
   581                                                         value);
       
   582                     break;
       
   583                 }
       
   584                 case WFC_ELEMENT_MASK:
       
   585                 {
       
   586                     WFC_Element_SetElementImageProvider(element,
       
   587                                                         WFC_IMAGE_MASK,
       
   588                                                         value);
       
   589                     break;
       
   590                 }
       
   591                 case WFC_ELEMENT_SOURCE_FLIP:
       
   592                 {
       
   593                     element->sourceFlip = (WFCboolean)value;
       
   594                     break;
       
   595                 }
       
   596                 case WFC_ELEMENT_SOURCE_ROTATION:
       
   597                 {
       
   598                     element->sourceRotation = (WFCRotation)value;
       
   599                     break;
       
   600                 }
       
   601                 case WFC_ELEMENT_SOURCE_SCALE_FILTER:
       
   602                 {
       
   603                     element->sourceScaleFilter = (WFCScaleFilter)value;
       
   604                     break;
       
   605                 }
       
   606                 case WFC_ELEMENT_TRANSPARENCY_TYPES:
       
   607                 {
       
   608                     element->transparencyTypes = value;
       
   609                     break;
       
   610                 }
       
   611                 default:
       
   612                 {
       
   613                     result = WFC_ERROR_BAD_ATTRIBUTE;
       
   614                     break;
       
   615                 }
       
   616             }
       
   617             break;
       
   618         }
       
   619     }
       
   620 
       
   621     return result;
       
   622 }
       
   623 
       
   624 /*---------------------------------------------------------------------------
       
   625  *
       
   626  *----------------------------------------------------------------------------*/
       
   627 OWF_API_CALL WFCErrorCode
       
   628 WFC_Element_SetAttribfv(WFC_ELEMENT* element,
       
   629                         WFCElementAttrib attrib,
       
   630                         WFCint count,
       
   631                         const WFCfloat* values)
       
   632 {
       
   633     WFCErrorCode            result = WFC_ERROR_NONE;
       
   634 
       
   635     FAIL_IF(NULL == values, WFC_ERROR_ILLEGAL_ARGUMENT);
       
   636 
       
   637     switch (attrib)
       
   638     {
       
   639         /* Vector attributes */
       
   640         case WFC_ELEMENT_SOURCE_RECTANGLE:
       
   641         case WFC_ELEMENT_DESTINATION_RECTANGLE:
       
   642         {
       
   643             WFCfloat        clamped[4];
       
   644 
       
   645             FAIL_IF(4 != count, WFC_ERROR_ILLEGAL_ARGUMENT);
       
   646 
       
   647             memcpy(clamped, values, 4 * sizeof(WFCfloat));
       
   648 
       
   649             if (WFC_ELEMENT_SOURCE_RECTANGLE == attrib)
       
   650             {
       
   651                 /* this clamps the rectangle, in case it has values that
       
   652                  * cause precision loss or other fuzzy behaviour. */
       
   653                 result = WFC_Element_ValidateSourceRectangle(element, clamped);
       
   654 
       
   655                 if (WFC_ERROR_NONE == result)
       
   656                 {
       
   657                     memcpy(element->srcRect, clamped, 4 * sizeof(WFCfloat));
       
   658 
       
   659                     DPRINT(("  Source rectangle set to (%.2f,%.2f,%.2f,%.2f)",
       
   660                             clamped[0], clamped[1], clamped[2], clamped[3]));
       
   661                 }
       
   662                 else
       
   663                 {
       
   664                     DPRINT(("  Source rectangle (%.2f,%.2f,%.2f,%.2f) is " \
       
   665                             "invalid",
       
   666                             values[0], values[1], values[2], values[3]));
       
   667                 }
       
   668             }
       
   669             else
       
   670             {
       
   671                 result = WFC_Element_ValidateDestinationRectangle(element,
       
   672                                                                   clamped);
       
   673                 if (WFC_ERROR_NONE == result)
       
   674                 {
       
   675                     memcpy(element->dstRect, clamped, 4 * sizeof(WFCfloat));
       
   676 
       
   677                     DPRINT(("  Destination rectangle set to " \
       
   678                             "(%.2f,%.2f,%.2f,%.2f)",
       
   679                             clamped[0], clamped[1], clamped[2], clamped[3]));
       
   680                 }
       
   681                 else
       
   682                 {
       
   683                     DPRINT(("  Destination rectangle (%.2f,%.2f,%.2f,%.2f) is "
       
   684                             "invalid",
       
   685                             values[0], values[1], values[2], values[3]));
       
   686                 }
       
   687             }
       
   688             break;
       
   689         }
       
   690 
       
   691         /* scalar attributes */
       
   692         case WFC_ELEMENT_GLOBAL_ALPHA:
       
   693         {
       
   694             /* values[0] must be [0, 1] */
       
   695             WFCfloat        value = values[0];
       
   696 
       
   697             /* value is [0, 1] map to [0, OWF_ALPHA_MAX] */
       
   698             value = value * OWF_ALPHA_MAX_VALUE;
       
   699 
       
   700             /* validate the value */
       
   701             result = WFC_Element_ValidateScalarAttributef(element,
       
   702                                                           attrib,
       
   703                                                           value);
       
   704 
       
   705             if (WFC_ERROR_NONE != result)
       
   706             {
       
   707                 /* invalid value for attribute, out we go */
       
   708                 break;
       
   709             }
       
   710 
       
   711             element->globalAlpha = value;
       
   712             break;
       
   713         }
       
   714 
       
   715         default:
       
   716         {
       
   717             result = WFC_ERROR_BAD_ATTRIBUTE;
       
   718             break;
       
   719         }
       
   720     }
       
   721 
       
   722     return result;
       
   723 }
       
   724 
       
   725 /*---------------------------------------------------------------------------
       
   726  * Attribute getters
       
   727  *----------------------------------------------------------------------------*/
       
   728 OWF_API_CALL WFCErrorCode
       
   729 WFC_Element_GetAttribiv(WFC_ELEMENT* element,
       
   730                         WFCElementAttrib attrib,
       
   731                         WFCint count,
       
   732                         WFCint* values)
       
   733 {
       
   734     WFCErrorCode            result = WFC_ERROR_NONE;
       
   735 
       
   736 
       
   737     FAIL_IF(NULL == values, WFC_ERROR_ILLEGAL_ARGUMENT);
       
   738 
       
   739     switch (attrib)
       
   740     {
       
   741         /* Vector attributes */
       
   742         case WFC_ELEMENT_SOURCE_RECTANGLE:
       
   743         case WFC_ELEMENT_DESTINATION_RECTANGLE:
       
   744         {
       
   745             WFCfloat        rect[4] = {0.0, 0.0, 0.0, 0.0};
       
   746 
       
   747             result = WFC_Element_GetAttribfv(element, attrib, count, rect);
       
   748 
       
   749             if (WFC_ERROR_NONE == result)
       
   750             {
       
   751                 values[0] = floor(rect[0]);
       
   752                 values[1] = floor(rect[1]);
       
   753                 values[2] = floor(rect[2]);
       
   754                 values[3] = floor(rect[3]);
       
   755             }
       
   756             break;
       
   757         }
       
   758 
       
   759         /* Scalar attributes */
       
   760         default:
       
   761         {
       
   762             FAIL_IF(1 != count, WFC_ERROR_ILLEGAL_ARGUMENT);
       
   763 
       
   764             switch (attrib)
       
   765             {
       
   766                 /* pure int attributes */
       
   767                 case WFC_ELEMENT_SOURCE:
       
   768                 {
       
   769                     *values = element->sourceHandle;
       
   770                     break;
       
   771                 }
       
   772                 case WFC_ELEMENT_MASK:
       
   773                 {
       
   774                     *values = element->maskHandle;
       
   775                     break;
       
   776                 }
       
   777                 case WFC_ELEMENT_SOURCE_FLIP:
       
   778                 {
       
   779                     *values = element->sourceFlip;
       
   780                     break;
       
   781                 }
       
   782                 case WFC_ELEMENT_SOURCE_ROTATION:
       
   783                 {
       
   784                     *values = element->sourceRotation;
       
   785                     break;
       
   786                 }
       
   787                 case WFC_ELEMENT_SOURCE_SCALE_FILTER:
       
   788                 {
       
   789                     *values = element->sourceScaleFilter;
       
   790                     break;
       
   791                 }
       
   792                 case WFC_ELEMENT_TRANSPARENCY_TYPES:
       
   793                 {
       
   794                     *values = element->transparencyTypes;
       
   795                     break;
       
   796                 }
       
   797                 case WFC_ELEMENT_GLOBAL_ALPHA:
       
   798                 {
       
   799                     WFCfloat    fvalue;
       
   800 
       
   801                     WFC_Element_GetAttribfv(element, attrib, 1, &fvalue);
       
   802                     *values = floor(OWF_BYTE_MAX_VALUE * fvalue /
       
   803                                     OWF_ALPHA_MAX_VALUE);
       
   804                     break;
       
   805                 }
       
   806                 default:
       
   807                 {
       
   808                     result = WFC_ERROR_BAD_ATTRIBUTE;
       
   809                     break;
       
   810                 }
       
   811             }
       
   812             break;
       
   813         }
       
   814     }
       
   815 
       
   816     return result;
       
   817 }
       
   818 
       
   819 /*---------------------------------------------------------------------------
       
   820  *
       
   821  *----------------------------------------------------------------------------*/
       
   822 OWF_API_CALL WFCErrorCode
       
   823 WFC_Element_GetAttribfv(WFC_ELEMENT* element,
       
   824                         WFCElementAttrib attrib,
       
   825                         WFCint count,
       
   826                         WFCfloat* values)
       
   827 {
       
   828     WFCErrorCode            result = WFC_ERROR_NONE;
       
   829 
       
   830     FAIL_IF(NULL == values, WFC_ERROR_ILLEGAL_ARGUMENT);
       
   831 
       
   832     switch (attrib)
       
   833     {
       
   834         /* Vector attributes */
       
   835         case WFC_ELEMENT_SOURCE_RECTANGLE:
       
   836         case WFC_ELEMENT_DESTINATION_RECTANGLE:
       
   837         {
       
   838             FAIL_IF(4 != count, WFC_ERROR_ILLEGAL_ARGUMENT);
       
   839 
       
   840             if (WFC_ELEMENT_SOURCE_RECTANGLE == attrib)
       
   841             {
       
   842                 values[0] = element->srcRect[0];
       
   843                 values[1] = element->srcRect[1];
       
   844                 values[2] = element->srcRect[2];
       
   845                 values[3] = element->srcRect[3];
       
   846             }
       
   847             else
       
   848             {
       
   849                 values[0] = element->dstRect[0];
       
   850                 values[1] = element->dstRect[1];
       
   851                 values[2] = element->dstRect[2];
       
   852                 values[3] = element->dstRect[3];
       
   853             }
       
   854             break;
       
   855         }
       
   856 
       
   857         /* Scalar attributes */
       
   858         default:
       
   859         {
       
   860             switch (attrib)
       
   861             {
       
   862                 case WFC_ELEMENT_GLOBAL_ALPHA:
       
   863                 {
       
   864                     *values = element->globalAlpha;
       
   865                     break;
       
   866                 }
       
   867                 default:
       
   868                 {
       
   869                     result = WFC_ERROR_BAD_ATTRIBUTE;
       
   870                     break;
       
   871                 }
       
   872             }
       
   873             break;
       
   874         }
       
   875     }
       
   876 
       
   877     return result;
       
   878 }
       
   879 
       
   880 /*---------------------------------------------------------------------------
       
   881  *  Attribute checkers to use during commit to check element
       
   882  *  for inconsistencies.
       
   883  *----------------------------------------------------------------------------*/
       
   884 static WFCboolean
       
   885 WFC_Element_CheckAttribute(WFC_ELEMENT* element,
       
   886                            WFCElementAttrib attrib)
       
   887 {
       
   888 #define VALIDATE_SCALAR_I(v)    \
       
   889     (WFC_Element_ValidateScalarAttributei(element, attrib, v) == \
       
   890             WFC_ERROR_NONE ? WFC_TRUE : WFC_FALSE)
       
   891 #define VALIDATE_SCALAR_F(v)    \
       
   892     (WFC_Element_ValidateScalarAttributef(element, attrib, v) == \
       
   893             WFC_ERROR_NONE ? WFC_TRUE : WFC_FALSE)
       
   894 
       
   895     WFCboolean              result = WFC_TRUE;
       
   896 
       
   897     DPRINT(("WFC_Element_CheckAttribute(%08x,%0x)",
       
   898            element, attrib));
       
   899 
       
   900     switch (attrib)
       
   901     {
       
   902         /*
       
   903         INTEGER-ATTRIBUTES
       
   904         */
       
   905         case WFC_ELEMENT_SOURCE:
       
   906         {
       
   907             /* Validated when the attribute was modified */
       
   908             break;
       
   909         }
       
   910 
       
   911         case WFC_ELEMENT_MASK:
       
   912         {
       
   913             /* Validated when the attribute was modified */
       
   914             break;
       
   915         }
       
   916 
       
   917         case WFC_ELEMENT_SOURCE_FLIP:
       
   918         {
       
   919             result = VALIDATE_SCALAR_I(element->sourceFlip) ? WFC_TRUE: WFC_FALSE;
       
   920             if (!result)
       
   921             {
       
   922                 DPRINT(("  Element source flipping is invalid (%d)",
       
   923                         element->sourceFlip));
       
   924             }
       
   925             break;
       
   926         }
       
   927 
       
   928         case WFC_ELEMENT_SOURCE_ROTATION:
       
   929         {
       
   930             result = VALIDATE_SCALAR_I(element->sourceRotation) ? WFC_TRUE: WFC_FALSE;
       
   931 
       
   932             if (!result)
       
   933             {
       
   934                 DPRINT(("  Element source rotation is invalid (%d)",
       
   935                         element->sourceRotation));
       
   936             }
       
   937             break;
       
   938         }
       
   939 
       
   940         case WFC_ELEMENT_SOURCE_SCALE_FILTER:
       
   941         {
       
   942             result = VALIDATE_SCALAR_I(element->sourceScaleFilter) ? WFC_TRUE: WFC_FALSE;
       
   943 
       
   944             if (!result)
       
   945             {
       
   946                 DPRINT(("  Element source scale filter is invalid (%d)",
       
   947                         element->sourceScaleFilter));
       
   948             }
       
   949             break;
       
   950         }
       
   951 
       
   952         case WFC_ELEMENT_TRANSPARENCY_TYPES:
       
   953         {
       
   954             result = VALIDATE_SCALAR_I(element->transparencyTypes) ? WFC_TRUE: WFC_FALSE;
       
   955 
       
   956             if (!result)
       
   957             {
       
   958                 DPRINT(("  Element transparency type is invalid (%x)",
       
   959                         element->transparencyTypes));
       
   960             }
       
   961             break;
       
   962         }
       
   963 
       
   964         case WFC_ELEMENT_GLOBAL_ALPHA:
       
   965         {
       
   966             result = VALIDATE_SCALAR_F(element->globalAlpha) ? WFC_TRUE: WFC_FALSE;
       
   967             if (!result)
       
   968             {
       
   969                 DPRINT(("  Element global alpha is invalid (%d)",
       
   970                         element->globalAlpha));
       
   971             }
       
   972             break;
       
   973         }
       
   974 
       
   975         case WFC_ELEMENT_DESTINATION_RECTANGLE:
       
   976         {
       
   977             WFC_IMAGE_PROVIDER* mask;
       
   978 
       
   979             /* The <0 test is repeated in SetAttribfv ValidateDestinationRectangle */
       
   980            if (element->dstRect[2] < 0 || element->dstRect[3] < 0)
       
   981             {
       
   982                 DPRINT(("  Element destination rectangle has negative "
       
   983                         "width/height"));
       
   984                 result = WFC_FALSE;
       
   985                 break;
       
   986             }
       
   987             if (element->maskHandle!=WFC_INVALID_HANDLE)
       
   988             {
       
   989                 result = WFC_Element_CheckAttribute(element, WFC_ELEMENT_MASK);
       
   990 
       
   991                 if (result)
       
   992                 {
       
   993                     mask = WFC_Device_FindMask(element->device,
       
   994                                                element->maskHandle);
       
   995                     if (!mask)
       
   996                     {
       
   997                         DPRINT(("  Mask handle is valid, but mask object now destroyed"));
       
   998                         mask=element->cachedMask;
       
   999                         if (!mask)
       
  1000                         {
       
  1001                             mask=element->mask;
       
  1002                         }
       
  1003                     }
       
  1004                     if (mask)
       
  1005                     {
       
  1006                         WFCint  maskWidth, maskHeight;
       
  1007     
       
  1008                         DPRINT(("  Element has a mask"));
       
  1009                         /* if the element has a mask, then width & height must match
       
  1010                            the dimensions of that mask */
       
  1011                         owfNativeStreamGetHeader(mask->streamHandle,&maskWidth, &maskHeight,NULL,NULL,NULL);
       
  1012     
       
  1013                         if (element->dstRect[2] != maskWidth ||
       
  1014                             element->dstRect[3] != maskHeight)
       
  1015                         {
       
  1016                             DPRINT(("  Mask size (%dx%d) != element size (%d,%d)",
       
  1017                                    maskWidth, maskHeight,
       
  1018                                    (int)element->dstRect[2],
       
  1019                                    (int)element->dstRect[3]));
       
  1020                             result = WFC_FALSE;
       
  1021                             break;
       
  1022                         }
       
  1023                     }
       
  1024                     else 
       
  1025                     {
       
  1026                         DPRINT(("  No mask pointers could be opened! Scene not safe!"));
       
  1027                         result = WFC_FALSE;
       
  1028                     }
       
  1029                 }
       
  1030             }
       
  1031             break;
       
  1032         }
       
  1033 
       
  1034         case WFC_ELEMENT_SOURCE_RECTANGLE:
       
  1035         {
       
  1036             WFC_IMAGE_PROVIDER* source;
       
  1037 
       
  1038             result = WFC_Element_CheckAttribute(element, WFC_ELEMENT_SOURCE);
       
  1039             
       
  1040             if (result && element->sourceHandle!=WFC_INVALID_HANDLE)
       
  1041             {   /* no source is valid - the element "will not affect composition results" */
       
  1042                 source = WFC_Device_FindImageProvider(element->device,
       
  1043                                                       element->sourceHandle,
       
  1044                                                       WFC_IMAGE_SOURCE);
       
  1045     
       
  1046                 result = WFC_TRUE;
       
  1047                 if (!source)
       
  1048                 {
       
  1049                     DPRINT(("  Source handle is valid, but source object now destroyed"));
       
  1050                     source=element->cachedSource;
       
  1051                     if (!source)
       
  1052                     {
       
  1053                         source=element->source;
       
  1054                     }
       
  1055                 }
       
  1056                 
       
  1057                 if (source)
       
  1058                 {
       
  1059                     WFCint  sourceWidth, sourceHeight;
       
  1060     
       
  1061                     owfNativeStreamGetHeader(source->streamHandle,&sourceWidth, &sourceHeight,NULL,NULL,NULL);
       
  1062                     /* The <0 test is repeated in SetAttribfv ValidateSourceRectangle */ 
       
  1063                     if ((element->srcRect[0] < 0) ||
       
  1064                         (element->srcRect[1] < 0) ||
       
  1065                         (element->srcRect[2] < 0) ||
       
  1066                         (element->srcRect[3] < 0) ||
       
  1067                         (element->srcRect[0] + element->srcRect[2]) > sourceWidth ||
       
  1068                         (element->srcRect[1] + element->srcRect[3]) > sourceHeight)
       
  1069                     {
       
  1070                         DPRINT(("  Source rectangle out of bounds"));
       
  1071                         DPRINT(("  (%f,%f,%f,%f), source size %dx%d",
       
  1072                                element->srcRect[0], element->srcRect[1],
       
  1073                                element->srcRect[2], element->srcRect[3],
       
  1074                                sourceWidth, sourceHeight));
       
  1075                         result = WFC_FALSE;
       
  1076                         break;
       
  1077                     }
       
  1078                 }
       
  1079                 else
       
  1080                 {
       
  1081                     DPRINT(("  No source pointers could be opened! Scene not safe!"));
       
  1082                     result = WFC_FALSE;
       
  1083                 }
       
  1084             }
       
  1085             break;
       
  1086         }
       
  1087 
       
  1088         case WFC_ELEMENT_FORCE_32BIT:
       
  1089         {
       
  1090             /* to keep compiler happy */
       
  1091             OWF_ASSERT(0);
       
  1092             break;
       
  1093         }
       
  1094     }
       
  1095 
       
  1096     return result;
       
  1097 
       
  1098 #undef VALIDATE_SCALAR_F
       
  1099 #undef VALIDATE_SCALAR_I
       
  1100 }
       
  1101 
       
  1102 /*---------------------------------------------------------------------------
       
  1103  *
       
  1104  *----------------------------------------------------------------------------*/
       
  1105 OWF_API_CALL WFCboolean
       
  1106 WFC_Element_HasConflicts(WFC_ELEMENT* element)
       
  1107 {
       
  1108 #define CHECK(x) \
       
  1109     if (!WFC_Element_CheckAttribute(element, x)) \
       
  1110     {\
       
  1111         DPRINT(("Element %d: Conflict in attribute %08x", element->handle, x));\
       
  1112         return WFC_TRUE; \
       
  1113     }
       
  1114 
       
  1115     CHECK(WFC_ELEMENT_SOURCE);
       
  1116     CHECK(WFC_ELEMENT_MASK);
       
  1117     CHECK(WFC_ELEMENT_SOURCE_RECTANGLE);
       
  1118     CHECK(WFC_ELEMENT_DESTINATION_RECTANGLE);
       
  1119     CHECK(WFC_ELEMENT_SOURCE_FLIP);
       
  1120     CHECK(WFC_ELEMENT_SOURCE_ROTATION);
       
  1121     CHECK(WFC_ELEMENT_SOURCE_SCALE_FILTER);
       
  1122     CHECK(WFC_ELEMENT_TRANSPARENCY_TYPES);
       
  1123     CHECK(WFC_ELEMENT_GLOBAL_ALPHA);
       
  1124 
       
  1125 #undef CHECK
       
  1126 
       
  1127     /* all ok, no conflicts */
       
  1128     return WFC_FALSE;
       
  1129 }
       
  1130 
       
  1131 /*---------------------------------------------------------------------------
       
  1132  *
       
  1133  *----------------------------------------------------------------------------*/
       
  1134 OWF_API_CALL WFCboolean
       
  1135 WFC_Element_AffectsCompositionResults(WFC_ELEMENT* element)
       
  1136 {
       
  1137     if (    (element->transparencyTypes&WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA)
       
  1138        &&   element->globalAlpha==OWF_FULLY_TRANSPARENT )
       
  1139     {
       
  1140         return WFC_FALSE;
       
  1141     }
       
  1142     if (element->sourceHandle==WFC_INVALID_HANDLE)
       
  1143     {
       
  1144         return WFC_FALSE;
       
  1145     }
       
  1146     if (element->dstRect[2]==0.0f || element->dstRect[3]==0.0f)
       
  1147     {
       
  1148         return WFC_FALSE;
       
  1149     }
       
  1150     if (element->srcRect[2]==0.0f || element->srcRect[3]==0.0f)
       
  1151     {
       
  1152         return WFC_FALSE;
       
  1153     }
       
  1154     return WFC_TRUE;
       
  1155     
       
  1156 }
       
  1157 /*---------------------------------------------------------------------------
       
  1158  *
       
  1159  *----------------------------------------------------------------------------*/
       
  1160 OWF_API_CALL void
       
  1161 WFC_Element_Commit(WFC_ELEMENT* element)
       
  1162 {
       
  1163     OWF_ASSERT(element);
       
  1164 
       
  1165     DPRINT(("WFC_Element_Commit(element = %d)\n", element->handle));
       
  1166 
       
  1167     /* replace source/mask ONLY if it has changed. without these checks,
       
  1168      * both source and mask would be overwritten whenever one of them
       
  1169      * is changed.
       
  1170      */
       
  1171 
       
  1172     if (element->cachedSource != element->source)
       
  1173     {
       
  1174         element->source = element->cachedSource;
       
  1175     }
       
  1176 
       
  1177     if (element->cachedMask != element->mask)
       
  1178     {
       
  1179         element->mask = element->cachedMask;
       
  1180     }
       
  1181 
       
  1182     /* these must be reset now that the element is committed -- the only purpose
       
  1183      * of these cached ones is to have source/mask object pointers in the
       
  1184      * element so that source/mask can be safely deleted from the device even
       
  1185      * if that particular image provider is set as source/mask for some element
       
  1186      * that is not yet committed.
       
  1187      */
       
  1188 
       
  1189     DPRINT(("  Prior to destroying cached objects:"));
       
  1190     DPRINT(("    R(cachedMask) = %d", REFCOUNT(element->cachedMask)));
       
  1191     DPRINT(("    R(cachedSource) = %d", REFCOUNT(element->cachedSource)));
       
  1192 
       
  1193     element->cachedSource = NULL;
       
  1194     element->cachedMask = NULL;
       
  1195 
       
  1196     DPRINT(("  new source   = %d\n", element->source ?
       
  1197                                      element->source->handle : 0));
       
  1198     DPRINT(("  new mask     = %d\n", element->mask ?
       
  1199                                      element->mask->handle : 0));
       
  1200 }
       
  1201 
       
  1202 
       
  1203 
       
  1204 #ifdef __cplusplus
       
  1205 }
       
  1206 #endif
       
  1207