webengine/wmlengine/src/image/src/Epoc32SimpleImage.cpp
changeset 0 dd21522fd290
child 10 a359256acfc6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/wmlengine/src/image/src/Epoc32SimpleImage.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,875 @@
+/*
+* Copyright (c) 2000 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+
+#include <e32def.h>  // First to avoid NULL redefine warning (no #ifndef NULL).
+#include "nw_image_epoc32simpleimagei.h"
+#include "Epoc32ImageDecoder.h"
+#include "nw_lmgr_rootbox.h"
+#include "nw_hed_documentroot.h"
+#include "HEDDocumentListener.h"
+#include "nw_hed_contenthandler.h"
+#include "nw_image_iimageobserver.h"
+#include "nw_adt_resizablevector.h"
+#include "GDIDeviceContext.h"
+
+#include "nw_gdi_types.h"
+
+#include <fbs.h>
+#include <bitdev.h>
+#include "BrsrStatusCodes.h"
+#include "nwx_logger.h"
+#include "MemoryManager.h"
+
+
+// Forward declaration which can't be put inside header file without breaking
+// compilation of OOC files.
+
+TBrowserStatusCode 
+scaleBitmap( CFbsBitmap* bitmap, CFbsBitmap** scaledBitmap, TRect* rect );
+
+
+void
+_NW_Image_Epoc32SimpleImage_ImageOpened( NW_Image_AbstractImage_t* aAbstractImage, NW_Bool aFailed,
+                                     NW_Int16 aSuppressDupReformats )
+    {
+    // add the image to out of view list
+    NW_Image_Epoc32Simple_t* thisObj = NW_Image_Epoc32SimpleOf (aAbstractImage);
+
+    if (thisObj->docNodeList)
+        {
+        NW_HED_DocumentNode_t* docNode = 
+            *(NW_HED_DocumentNode_t**)NW_ADT_Vector_ElementAt(thisObj->docNodeList, 0);
+        NW_ASSERT(docNode);
+        NW_HED_DocumentRoot_t* docRoot = (NW_HED_DocumentRoot_t*)NW_HED_DocumentNode_GetRootNode(docNode);
+        NW_LMgr_RootBox_t* rootBox = NW_HED_DocumentRoot_GetRootBox(docRoot);
+        NW_LMgr_RootBox_AddToOutOfViewList(rootBox, aAbstractImage);
+        }
+    _NW_Image_AbstractImage_ImageOpened(aAbstractImage, aFailed, aSuppressDupReformats );
+    }
+
+/* ------------------------------------------------------------------------- *
+   class definition
+ * ------------------------------------------------------------------------- */
+
+/* ------------------------------------------------------------------------- */
+const
+NW_Image_Epoc32Simple_Class_t NW_Image_Epoc32Simple_Class = {
+  { /* NW_Object_Core          */
+    /* super                   */ &NW_Image_AbstractImage_Class,
+    /* queryInterface          */ _NW_Object_Base_QueryInterface
+  },
+  { /* NW_Object_Base          */
+    /* interfaceList           */ NULL
+  },
+  { /* NW_Object_Dynamic       */
+    /* instanceSize            */ sizeof (NW_Image_Epoc32Simple_t),
+    /* construct               */ _NW_Image_Epoc32Simple_Construct,
+    /* destruct                */ _NW_Image_Epoc32Simple_Destruct
+  },
+  { /* NW_Image_Abstract       */
+    /* getSize                 */ _NW_Image_Epoc32Simple_GetSize,
+    /* draw                    */ _NW_Image_Epoc32Simple_Draw,
+    /* drawScaled              */ _NW_Image_Epoc32Simple_DrawScaled,
+    /* drawInRect              */ _NW_Image_Epoc32Simple_DrawInRect,
+    /* incrementImage          */ _NW_Image_Epoc32Simple_IncrementImage,
+    /* getLoopCount            */ _NW_Image_AbstractImage_GetLoopCount,
+    /* setLoopCount            */ _NW_Image_AbstractImage_SetLoopCount,
+    /* getDelay                */ _NW_Image_AbstractImage_GetDelay,
+    /* isAnimated              */ _NW_Image_AbstractImage_IsAnimated,
+    /* setImageObserver        */ _NW_Image_AbstractImage_SetImageObserver,
+    /* removeImageObserver     */ _NW_Image_AbstractImage_RemoveImageObserver,
+    /* imageOpened             */ _NW_Image_Epoc32SimpleImage_ImageOpened,
+    /* imageSizeChanged        */ _NW_Image_AbstractImage_ImageSizeChanged,
+    /* imageDecoded            */ _NW_Image_AbstractImage_ImageDecoded,
+    /* imageOpenStarted        */ _NW_Image_AbstractImage_ImageOpenStarted,
+    /* forceImageDecode        */ _NW_Image_Epoc32Simple_ForceImageDecode
+  },
+  { /* NW_Image_Simple         */
+    /* partialNextChunk        */ _NW_Image_Epoc32Simple_PartialNextChunk
+  }
+};
+
+/* ------------------------------------------------------------------------- *
+   virtual methods
+ * ------------------------------------------------------------------------- */
+
+/* ------------------------------------------------------------------------- */
+
+TBrowserStatusCode 
+_NW_Image_Epoc32Simple_Construct (NW_Object_Dynamic_t* dynamicObject, va_list *argp)
+    {
+    NW_TRY(status) 
+        {
+        NW_Image_Epoc32Simple_t* thisObj;
+        NW_HED_DocumentNode_t* documentNode;
+        
+        // parameter assertion block 
+        NW_ASSERT(NW_Object_IsInstanceOf(dynamicObject, &NW_Image_Epoc32Simple_Class));
+        NW_ASSERT(argp != NULL);
+        
+        // for convenience 
+        thisObj = NW_Image_Epoc32SimpleOf (dynamicObject);
+        
+        // initialize the member variables 
+        // Won't know if image is animated until after it is opened by decoder 
+        NW_Image_AbstractImageOf(thisObj)->isAnimated = NW_FALSE;
+        thisObj->prevFlags = 0;
+        thisObj->needsDecode = NW_FALSE;
+        thisObj->imageDecoding = NW_FALSE;
+        
+        NW_GDI_Dimension3D_t size = va_arg (*argp, NW_GDI_Dimension3D_t); 
+        thisObj->size = size;
+        
+        const void* bitmap = va_arg (*argp, const void*); 
+        thisObj->bitmap = bitmap;
+        
+        const void* mask = va_arg (*argp, const void*); 
+        thisObj->mask = mask;
+
+        thisObj->invertedMask = (NW_Bool)va_arg (*argp, NW_Uint32);
+        
+        // "isTransparent" doesn't appear to be used by any Epoc code 
+        NW_Bool isTransparent = (NW_Bool)va_arg (*argp, NW_Uint32);
+        (void)isTransparent;
+        
+        // Do we have a image type that isn't recognized by Symbian, but we handle
+        thisObj->imageType = (TImageType)va_arg (*argp, NW_Uint32);
+        
+        // in order to make sure that we take rawData ownership, 
+        // the code should not leave before this point.
+        thisObj->rawData = va_arg (*argp, void*); 
+        thisObj->rawDataLength = va_arg (*argp, NW_Int32); 
+        
+        documentNode = va_arg (*argp, NW_HED_DocumentNode_t*);
+        if (documentNode)
+            {
+            thisObj->docNodeList = (NW_ADT_DynamicVector_t*)
+                NW_ADT_ResizableVector_New(sizeof(void*), 10, 5 );
+            // OOM check
+            NW_THROW_OOM_ON_NULL(thisObj->docNodeList, status);
+            
+            NW_THROW_OOM_ON_NULL(NW_ADT_DynamicVector_InsertAt(thisObj->docNodeList, 
+                &documentNode, NW_ADT_Vector_AtEnd), status);
+            }
+        
+        // If the image is not provided, it needs to be converted from the raw data.
+        // Construct an image decoder to do this. 
+        if (!thisObj->bitmap)
+            {
+            TRAPD(err, thisObj->decoder = CEpoc32ImageDecoder::NewL(thisObj));
+            if (err == KErrNoMemory)
+                {
+                NW_THROW_STATUS(status, KBrsrOutOfMemory);
+                }
+            else if (err != KErrNone)
+                {
+                NW_THROW_STATUS(status, KBrsrFailure);
+                }
+            }
+
+           thisObj->srcHeight = 0;
+           thisObj->srcWidth  = 0;
+
+        // and finally invoke our superclass constructor 
+        status = _NW_Image_AbstractImage_Construct(dynamicObject, argp);
+        
+        _NW_THROW_ON_ERROR(status);      
+        }
+    NW_CATCH(status) 
+        {
+        }
+    NW_FINALLY 
+        {
+        return status;
+        } 
+    NW_END_TRY
+    }
+
+/* ------------------------------------------------------------------------- */
+void
+_NW_Image_Epoc32Simple_Destruct (NW_Object_Dynamic_t* dynamicObject)
+  {
+  NW_Image_Epoc32Simple_t* thisObj;
+
+  /* parameter assertion block */
+  NW_ASSERT (NW_Object_IsInstanceOf (dynamicObject, &NW_Image_Epoc32Simple_Class));
+
+  /* for convenience */
+  thisObj = NW_Image_Epoc32SimpleOf (dynamicObject);
+
+  // first notify the observers on the destroy event
+  NW_Image_AbstractImage_ImageDestroyed( NW_Image_AbstractImageOf( thisObj ) );
+
+  /* Delete decoder, rawData & images */
+  CEpoc32ImageDecoder* decoder = STATIC_CAST(CEpoc32ImageDecoder*, thisObj->decoder);
+  delete decoder;
+
+  NW_Image_Epoc32Simple_DestroyRawData( thisObj );
+
+  if( thisObj->docNodeList )
+    {
+    NW_Object_Delete(thisObj->docNodeList);
+    }
+
+  // image ownership is transfered when decoding completes.
+  if( thisObj->imageDecoding == NW_FALSE )
+    {
+    CFbsBitmap* oldBitmap = CONST_CAST(CFbsBitmap*, (const CFbsBitmap*)thisObj->bitmap);
+    delete oldBitmap;
+    CFbsBitmap* oldMask = CONST_CAST(CFbsBitmap*, (const CFbsBitmap*)thisObj->mask);
+    delete oldMask;
+    }
+  }
+
+
+
+/* ------------------------------------------------------------------------- */
+TBrowserStatusCode
+_NW_Image_Epoc32Simple_PartialNextChunk( NW_Image_AbstractImage_t* image,
+                                         NW_Buffer_t* nextChunk )
+  {
+  TBrowserStatusCode status = KBrsrSuccess;
+  NW_Image_Epoc32Simple_t* thisObj;
+
+  NW_ASSERT( NW_Object_IsInstanceOf( image, &NW_Image_Epoc32Simple_Class ) );
+
+  thisObj = NW_Image_Epoc32SimpleOf( image );
+  NW_ASSERT( thisObj->decoder!= NULL );
+
+  // buffer chunks
+  void* tempBuffer;
+  tempBuffer = NW_Mem_Malloc( thisObj->rawDataLength + nextChunk->length );
+  if( tempBuffer != NULL )
+    {
+    // copy old buffer
+    NW_Mem_memcpy( tempBuffer, thisObj->rawData, thisObj->rawDataLength );
+    // free old buffer
+    NW_Mem_Free( thisObj->rawData );
+    // copy new chunk  
+    NW_Mem_memcpy( ((NW_Byte*)tempBuffer) + thisObj->rawDataLength, 
+      nextChunk->data, nextChunk->length );
+    // set new buffer`
+    thisObj->rawData = tempBuffer;
+    // update length info
+    thisObj->rawDataLength+= nextChunk->length;
+
+#ifdef INCREMENTAL_IMAGE_ON
+    CEpoc32ImageDecoder* decoder = STATIC_CAST( CEpoc32ImageDecoder*, thisObj->decoder );
+
+    TRAPD( error, decoder->PartialNextChunkL( nextChunk ) );
+
+    if( error == KErrNoMemory )
+      {
+      status = KBrsrOutOfMemory;
+      }
+    else if( error != KErrNone )
+      {
+      status = KBrsrFailure;
+      }
+#endif // INCREMENTAL_IMAGE_ON
+
+    }
+  else
+    {
+    status = KBrsrOutOfMemory;
+    }
+  // release chunk
+  NW_Buffer_Free( nextChunk );
+
+  return status;
+  }
+
+/* ------------------------------------------------------------------------- */
+TBrowserStatusCode
+_NW_Image_Epoc32Simple_GetSize (const NW_Image_AbstractImage_t* image,
+                                NW_GDI_Dimension3D_t* size)
+{
+  /* parameter assertion block */
+  NW_ASSERT (NW_Object_IsInstanceOf (image, &NW_Image_Epoc32Simple_Class));
+  NW_ASSERT (size != NULL);
+
+  /* set the size and return */
+  *size = NW_Image_Epoc32SimpleOf (image)->size;
+
+  return KBrsrSuccess;
+}
+
+/* ------------------------------------------------------------------------- */
+TBrowserStatusCode
+_NW_Image_Epoc32Simple_Draw (NW_Image_AbstractImage_t* image,
+                             CGDIDeviceContext* deviceContext,
+                             const NW_GDI_Point2D_t* location)
+{
+  return NW_Image_AbstractImage_DrawInRect (image, deviceContext, location, NULL, NULL);
+}
+
+/* ------------------------------------------------------------------------- */
+TBrowserStatusCode
+_NW_Image_Epoc32Simple_DrawScaled (NW_Image_AbstractImage_t* image,
+                                   CGDIDeviceContext* deviceContext,
+                                   const NW_GDI_Point2D_t* location,
+                                   const NW_GDI_Dimension3D_t* size)
+{
+  return NW_Image_AbstractImage_DrawInRect (image, deviceContext, location, size, NULL);
+}
+
+/* ------------------------------------------------------------------------- 
+ * Function:    _NW_Image_Epoc32Simple_DrawInRect
+ * Description: Draw scaled image on a certain location within a rectangle.
+ *
+ * @param     image:          the simple image to be drawn
+ * @param     deviceContext:  the device context object.
+ * @param     location:       the top-left point to start drawing
+ * @param     size:           the size to scale the image to.
+ * @param     rect:           the rectangle to draw the image within
+ *
+ * note: Both the parameters size and rect could be NULL.
+ *       If the size is NULL, the image is not scaled before being drawn.
+ *       If the rect is NULL, draw the entire image.
+*/
+TBrowserStatusCode
+_NW_Image_Epoc32Simple_DrawInRect (NW_Image_AbstractImage_t* image,
+                                   CGDIDeviceContext* deviceContext,
+                                   const NW_GDI_Point2D_t* location,
+                                   const NW_GDI_Dimension3D_t* size,
+                                   const NW_GDI_Rectangle_t* rect)
+{
+  NW_Image_Epoc32Simple_t* thisObj;
+  NW_GDI_ImageBlock_t imageBlock;
+  NW_GDI_Rectangle_t cropRect;
+  NW_Bool imageScaled = NW_FALSE;
+  NW_Bool imageOverlapped = NW_FALSE;
+  NW_GDI_Rectangle_t overlap;
+  TBrowserStatusCode status = KBrsrSuccess;
+
+  /* parameter assertion block */
+  NW_ASSERT (NW_Object_IsInstanceOf (image, &NW_Image_Epoc32Simple_Class));
+  NW_ASSERT (location != NULL);
+
+  /* for convenience */
+  thisObj = NW_Image_Epoc32SimpleOf (image);
+  CEpoc32ImageDecoder* decoder = STATIC_CAST(CEpoc32ImageDecoder*, thisObj->decoder);
+
+  /* If there is a decoder, then the image needs to be decoded before displaying
+   * if not done already, or if "needsDecode" (animated image has moved on to
+   * next frame).
+   */
+  if (decoder != NULL && (thisObj->bitmap == NULL || thisObj->needsDecode))
+    {
+    decoder->Decode();
+    }
+
+  /* If there is already a bitmap, draw it. When the results of the decode operation
+   * come back this function will be called again; then there should be a bitmap.
+   */
+  if( thisObj->bitmap )
+    {
+    imageBlock.colPalette.data = NULL;
+    imageBlock.conversionStatus = NW_GDI_Image_ConversionRequired;
+    imageBlock.size = thisObj->size;
+    imageBlock.data = thisObj->bitmap;
+    imageBlock.mask = thisObj->mask;
+    imageBlock.invertedMask = thisObj->invertedMask;
+
+    /* check if scaling required */
+    if( size )
+      {
+      // if the image is scaled for some reason, then we have to make sure
+      // that we are having the right size of it.
+      CFbsBitmap* realBitmap = CONST_CAST(CFbsBitmap*, (const CFbsBitmap*)thisObj->bitmap);
+      TSize bitmapRealSize = realBitmap->SizeInPixels();
+
+      if( thisObj->size.width != size->width || thisObj->size.height != size->height || 
+          bitmapRealSize.iWidth != size->width || bitmapRealSize.iHeight != size->height )
+        {
+        NW_GDI_ImageBlock_t scaledImageBlock;
+    
+        // scale current data 
+        status = deviceContext->ScaleImage ( size, &imageBlock, &scaledImageBlock);
+
+        if (status == KBrsrSuccess)
+          {
+          imageScaled = NW_TRUE;
+          imageBlock.data = scaledImageBlock.data;
+          imageBlock.mask = scaledImageBlock.mask;
+          imageBlock.size = *size;
+          }
+        } 
+      }
+    
+    /* if the parameter rect is NULL, we want to draw the entire image,
+    else we only want to draw the overlap of image and the showing rectangle */
+    if (rect == NULL)
+    {
+      cropRect.point.x = 0;
+      cropRect.point.y = 0;
+      cropRect.dimension.width = imageBlock.size.width;
+      cropRect.dimension.height = imageBlock.size.height;
+    }
+    else
+    {
+      /* now based on the overlap of imageblock and showing rectangle,
+      calculate the crop rectangle which is used to crop the image, the 
+      difference between the overlap and crop image is: crop image's 
+      coordinates are relative to image not absolute.
+      example       (as x, y, width, height)
+      rect            (10, 10, 50, 50)
+      image           (30, 30, 40, 40)
+      overlap area    (30, 30, 30, 30)
+      crop rectangle  ( 0,  0, 30, 30)
+      */
+      imageOverlapped = TRUE;
+      overlap.point.x = (location->x > rect->point.x) ? location->x : rect->point.x;
+      overlap.point.y = (location->y > rect->point.y) ? location->y : rect->point.y;
+      
+      if (location->x + imageBlock.size.width > rect->point.x + rect->dimension.width) 
+        overlap.dimension.width = rect->point.x + rect->dimension.width - overlap.point.x;
+      else
+        overlap.dimension.width = location->x + imageBlock.size.width - overlap.point.x;
+      
+      if (location->y + imageBlock.size.height > rect->point.y + rect->dimension.height) 
+        overlap.dimension.height = rect->point.y + rect->dimension.height - overlap.point.y;
+      else
+        overlap.dimension.height = location->y + imageBlock.size.height - overlap.point.y;
+      
+      cropRect.point.x = overlap.point.x - location->x;
+      cropRect.point.y = overlap.point.y - location->y;
+      cropRect.dimension = overlap.dimension;
+
+      /* if the rectangle and the image location does not overlap, return*/
+      if (overlap.dimension.height <= 0 || overlap.dimension.width <= 0)
+        return KBrsrSuccess;
+
+        /* if the rectangle and the image location does not overlap, return
+        if (rect->point.x > location->x + imageBlock.size.width ||
+        rect->point.y > location->y + imageBlock.size.height ||
+        location->x > rect->point.x + rect->dimension.width ||
+        location->y > rect->point.y + rect->dimension.height)
+        return KBrsrSuccess;
+        
+          if (rect->point.x < location->x)
+          {
+          cropRect.point.x = 0;
+          cropRect.dimension.width = rect->point.x + rect->dimension.width - location->x ;
+          }
+          else
+          {
+          cropRect.point.x = rect->point.x - location->x;
+          cropRect.dimension.width = location->x + imageBlock.size.width - rect->point.x;
+          }
+          if (rect->point.y < location->y)
+          {
+          cropRect.point.y = 0;
+          cropRect.dimension.height = rect->point.y + rect->dimension.height - location->y;
+          }
+          else
+          {
+          cropRect.point.y = rect->point.y - location->y;
+          cropRect.dimension.width = location->y + imageBlock.size.height - rect->->point.y;
+          }
+          }
+      */
+    /* do the draw */
+
+    }
+
+	if (imageOverlapped)
+		deviceContext->DrawImage (&overlap.point, 
+                              &cropRect,
+                              &imageBlock);
+	else
+		deviceContext->DrawImage (location, 
+                              &cropRect,
+                              &imageBlock);
+    if (imageScaled)
+    {
+        CFbsBitmap* bitmap = CONST_CAST(CFbsBitmap*, (const CFbsBitmap*)imageBlock.data);
+        delete bitmap;
+        CFbsBitmap* mask = CONST_CAST(CFbsBitmap*, (const CFbsBitmap*)imageBlock.mask);
+        delete mask;
+    }
+  }
+  return status;
+}
+
+/* ------------------------------------------------------------------------- */
+/* _NW_Image_Epoc32Simple_IncrementImage
+ *
+ * Called on an animated image to cause it to move on to the next image.
+ * Tells the decoder to go to the next image, and sets "needsDecode" to
+ * NW_TRUE so that the decode will be done on the next attempt to draw.
+ */
+TBrowserStatusCode
+_NW_Image_Epoc32Simple_IncrementImage(NW_Image_AbstractImage_t* image)
+{
+  NW_ASSERT (NW_Object_IsInstanceOf (image, &NW_Image_Epoc32Simple_Class));
+
+  NW_Bool   startingFrameSequenceOver=NW_FALSE;
+
+  /* for convenience */
+  NW_Image_Epoc32Simple_t* thisObj = NW_Image_Epoc32SimpleOf (image);
+
+  CEpoc32ImageDecoder* decoder = STATIC_CAST(CEpoc32ImageDecoder*, thisObj->decoder);
+
+  if (decoder)
+    {
+  if (decoder->IncrementImage(startingFrameSequenceOver))
+  {
+    /* update loop count if starting frame sequence again */
+    if(startingFrameSequenceOver == NW_TRUE)
+    {
+      if(image->loopCount != -1)
+      {
+        image->loopCount--;
+      }
+    }
+      }
+    thisObj->needsDecode = NW_TRUE;
+    return KBrsrSuccess;
+  }
+  return KBrsrFailure;
+}
+
+/* ------------------------------------------------------------------------- */
+TBrowserStatusCode
+NW_Image_Epoc32Simple_AddDocNode(NW_Image_Epoc32Simple_t* thisObj, 
+                                 NW_HED_DocumentNode_t* documentNode)
+{
+  if (NW_ADT_DynamicVector_InsertAt(thisObj->docNodeList, &documentNode, NW_ADT_Vector_AtEnd) == NULL)
+    return KBrsrOutOfMemory;
+  return KBrsrSuccess;
+}
+
+
+/* ------------------------------------------------------------------------- */
+TBrowserStatusCode
+NW_Image_Epoc32Simple_Initialize( NW_Image_Epoc32Simple_t* thisObj )
+  {
+  TBrowserStatusCode status = KBrsrFailure;
+
+  NW_ASSERT( NW_Object_IsInstanceOf( thisObj, &NW_Image_Epoc32Simple_Class ) );
+  // let the decoder know that we've got all the raw data
+  if( thisObj->decoder )
+    {
+    CEpoc32ImageDecoder* decoder = STATIC_CAST( CEpoc32ImageDecoder*, thisObj->decoder );
+    decoder->ImageDataComplete();
+    status = KBrsrSuccess;
+    }
+
+  return status;
+  }
+
+/* ------------------------------------------------------------------------- *
+   convenience functions
+ * ------------------------------------------------------------------------- */
+
+/* ------------------------------------------------------------------------- */
+NW_Image_Epoc32Simple_t*
+NW_Image_Epoc32Simple_New (NW_GDI_Dimension3D_t size, 
+                           const void* data, 
+                           const void* mask,
+                           NW_Bool invertedMask,
+                           NW_Bool isTransparent,
+                           TImageType imageType,
+                           void* rawData,
+                           NW_Int32 length,
+                           NW_HED_DocumentNode_t* documentNode)
+{
+  //lint -e{437} Passing struct to ellipsis
+  return (NW_Image_Epoc32Simple_t*) NW_Object_New (&NW_Image_Epoc32Simple_Class, 
+                                                   size,
+                                                   data,
+                                                   mask,
+                                                   (NW_Uint32)invertedMask,
+                                                   (NW_Uint32)isTransparent,
+                                                   (NW_Uint32)imageType,
+                                                   rawData,
+                                                   length,
+                                                   documentNode);
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* NW_Image_Epoc32Simple_SetSize
+ *
+ * Called when the image has been opened by the image decoder. Sets the
+ * (unscaled) image size.
+ */
+TBrowserStatusCode
+NW_Image_Epoc32Simple_SetSize (NW_Image_AbstractImage_t* image,
+                               NW_GDI_Dimension3D_t* aSize)
+{
+  NW_Image_Epoc32Simple_t* thisObj;
+  TBrowserStatusCode status = KBrsrSuccess;
+
+  /* parameter assertion block */
+  NW_ASSERT (NW_Object_IsInstanceOf (image, &NW_Image_Epoc32Simple_Class));
+  NW_ASSERT (aSize != NULL);
+
+  /* for convenience */
+  thisObj = NW_Image_Epoc32SimpleOf (image);
+
+  // we have to inform observers about the size change.
+  NW_GDI_Dimension3D_s oldSize = thisObj->size;
+  // set the size
+  thisObj->size = *aSize;
+  // first check if the previous size was valid.
+  if( oldSize.width != 0 && thisObj->size.height != 0 )
+  {
+    // check if the size has changed at all 
+    if( oldSize.width != aSize->width || 
+        oldSize.height != aSize->height )
+    {
+      NW_Image_AbstractImage_ImageSizeChanged( NW_Image_AbstractImageOf( thisObj ) );
+    }
+  }
+  return status;
+}
+
+/* ------------------------------------------------------------------------- */
+TBrowserStatusCode
+_NW_Image_Epoc32Simple_ForceImageDecode( NW_Image_AbstractImage_t* epocImage )
+  {
+  TBrowserStatusCode status = KBrsrSuccess;
+  NW_Image_Epoc32Simple_t* thisObj;
+
+  NW_ASSERT( epocImage != NULL );
+  NW_ASSERT( NW_Object_IsInstanceOf( epocImage, &NW_Image_Epoc32Simple_Class ) );
+
+  thisObj = NW_Image_Epoc32SimpleOf( epocImage );
+
+  CEpoc32ImageDecoder* decoder = STATIC_CAST( CEpoc32ImageDecoder*, thisObj->decoder );
+  status = decoder->Decode();
+  
+  return status;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* NW_Image_Epoc32Simple_SetAnimation
+ *
+ * Calling this function implies that the image is animated. It sets the delay
+ * time, and notes that the image is animated.
+ */
+TBrowserStatusCode
+NW_Image_Epoc32Simple_SetAnimation(NW_Image_AbstractImage_t* image,
+                                   NW_Bool isAnimated,
+                                   NW_Uint32 delay )
+{
+  image->isAnimated = isAnimated;
+  image->delay = delay;
+  return KBrsrSuccess;
+}
+
+/* ------------------------------------------------------------------------- */
+/* NW_Image_Epoc32Simple_SetBitmapL
+ *
+ * Called by the image decoder when it has finished processing. Sets the bitmap
+ * data, then forces a redraw.
+ *
+ * Parameters:
+ *  image:     this object
+ *  bitmap:    new bitmap to display
+ *  mask:      new bitmap mask
+ *  frameNum:  Current frame number (if animated)
+ *  frameInfo: Details about current frame
+ *  frameIsReady: the frame is fully decoded
+ */
+static
+void
+NW_Image_Epoc32Simple_SetBitmapL(NW_Image_Epoc32Simple_t* image,
+                                CFbsBitmap* bitmap,
+                                CFbsBitmap* mask,
+                                NW_Int32 frameNum,
+                                TFrameInfo* frameInfo,
+                                NW_Bool frameIsReady )
+  {
+  if( frameIsReady == NW_TRUE )
+    {
+    // if the image has just been decoded, then image->bitmap is same as bitmap
+    // init image->bitmap to NULL.
+    if( image->imageDecoding == NW_TRUE )
+      {
+      image->bitmap = NULL;
+      image->mask = NULL;
+      image->imageDecoding = NW_FALSE;
+      }
+    CFbsBitmap* existingBitmap = CONST_CAST(CFbsBitmap*, (const CFbsBitmap*)image->bitmap);
+    CFbsBitmap* existingMask = CONST_CAST(CFbsBitmap*, (const CFbsBitmap*)image->mask);
+
+    // If there is transparency but no disposal property defined, then assume
+    // the disposal property ELeaveInPlace.
+    if( (frameInfo->iFlags & TFrameInfo::ETransparencyPossible) &&
+      !(image->prevFlags & (TFrameInfo::ERestoreToBackground | TFrameInfo::ERestoreToPrevious)) )
+      {
+      image->prevFlags |= TFrameInfo::ELeaveInPlace;
+      }
+
+    // If there is an existing bitmap, then it must be animated. If the previous
+    // frame had the flag "ELeaveInPlace", then the new bitmap must be rendered
+    // on top of the old one for things to work properly. This does not apply to
+    // the first frame when the animation goes back to the start (frameNum == 0).
+    TPoint aStartPoint(0,0);
+	if (existingBitmap != NULL && (image->prevFlags & TFrameInfo::ELeaveInPlace) && 
+	   (frameNum > 0 || frameInfo->iFrameCoordsInPixels.iTl != aStartPoint)){
+      // Push mask & bitmap on the cleanup stack to make sure they get deleted.
+      CleanupStack::PushL(mask);
+      CleanupStack::PushL(bitmap);
+
+      // Render new bitmap on top of old bitmap.
+      CFbsBitGc* bitmapContext=NULL;
+      CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL(existingBitmap);
+      CleanupStack::PushL(bitmapDevice);
+      User::LeaveIfError(bitmapDevice->CreateContext(bitmapContext));
+      CleanupStack::PushL(bitmapContext);
+      if(frameNum == 0)
+		 bitmapContext->Clear();
+      if (mask == NULL)
+        bitmapContext->BitBlt(frameInfo->iFrameCoordsInPixels.iTl, bitmap, frameInfo->iFrameCoordsInPixels.Size());
+      else
+        bitmapContext->BitBltMasked(frameInfo->iFrameCoordsInPixels.iTl, bitmap, frameInfo->iFrameCoordsInPixels.Size(), mask, EFalse);
+
+      // Delete device, context & bitmap
+      CleanupStack::PopAndDestroy(3);
+		
+      // If both masks exist, draw the new on top of the old.
+      if (existingMask != NULL && mask != NULL)
+        {
+        CFbsBitGc* maskContext=NULL;
+        CFbsBitmapDevice* maskDevice = CFbsBitmapDevice::NewL(existingMask);
+        CleanupStack::PushL(maskDevice);
+        User::LeaveIfError(maskDevice->CreateContext(maskContext));
+        CleanupStack::PushL(maskContext);
+        maskContext->BitBltMasked(frameInfo->iFrameCoordsInPixels.iTl, mask, frameInfo->iFrameCoordsInPixels.Size(), mask, EFalse);
+        CleanupStack::PopAndDestroy(2);
+        delete mask;
+        }
+      else if (mask != NULL)
+        {
+        // If the first image had no mask, then after that we would have to fill in the whole frame
+        // anyway, so there is no point keeping a mask.
+        delete mask;
+        }
+      // Pop mask from cleanup stack
+      CleanupStack::Pop();
+      }
+    else
+    {
+        // The new bitmap and mask have no dependancy on the old; just replace the old
+        // with the new.
+        if(image->bitmap){
+          TInt bitmapHandle = bitmap->Handle();
+          CFbsBitmap* pBitmap = (CFbsBitmap*)image->bitmap;
+          pBitmap->Duplicate(bitmapHandle);
+        }
+        else{
+            image->bitmap = bitmap;
+        } 
+        
+        if(image->mask){
+           TInt bitmapHandle = mask->Handle();
+           CFbsBitmap* pBitmask = (CFbsBitmap*)image->mask;
+           pBitmask->Duplicate(bitmapHandle);
+        }
+        else{ 
+            image->mask = mask;
+        }
+    }
+    image->needsDecode = NW_FALSE;
+    image->prevFlags = frameInfo->iFlags;
+    }
+  else
+    {
+    image->imageDecoding = NW_TRUE;
+    image->bitmap = bitmap;
+    image->mask = mask;
+    }
+  }
+
+/* ------------------------------------------------------------------------- */
+/* NW_Image_Epoc32Simple_DestroyRawData
+ *
+*/
+void NW_Image_Epoc32Simple_DestroyRawData( NW_Image_Epoc32Simple_t* aImage )
+  {
+  NW_ASSERT( aImage != NULL );
+
+  if( aImage->rawData )
+    {
+    delete aImage->rawData ;
+    aImage->rawData = NULL;
+    }
+  }
+
+/* ------------------------------------------------------------------------- */
+/* NW_Image_Epoc32Simple_SetBitmap
+ *
+ * Non-leaving version of function "NW_Image_Epoc32Simple_SetBitmap". Called by
+ * the image decoder when it has finished processing. Sets the bitmap data,
+ * then forces a redraw. Parameters are "void*" so that OOC files can include
+ * header file.
+ *
+ * Parameters:
+ *  image:     this object
+ *  bitmap:    new bitmap to display
+ *  mask:      new bitmap mask
+ *  frameNum:  Current frame number (if animated)
+ *  frameInfo: Details about current frame
+ */
+void
+NW_Image_Epoc32Simple_SetBitmap(NW_Image_Epoc32Simple_t* image,
+                                void* bitmap,
+                                void* mask,
+                                NW_Int32 frameNum,
+                                void* frameInfo,
+                                NW_Bool frameIsReady )
+{
+  TInt err;
+  TRAP(err, NW_Image_Epoc32Simple_SetBitmapL(image, 
+                                              (CFbsBitmap*)bitmap,
+                                              (CFbsBitmap*)mask,
+                                              frameNum,
+                                              (TFrameInfo*)frameInfo, 
+                                              frameIsReady));
+}
+
+// first we check if image is visible, we go through the observer list for that.
+// Observer knows which image is visible. If image is not visible, then we
+// delete the image which is out of view. In case that the decoding is still going on 
+// we cancel the decoding for out of view image
+void
+NW_Image_Epoc32Simple_OutOfView( NW_Image_Epoc32Simple_t* aEpocImage )
+    {
+      NW_Bool isVisible = NW_Image_AbstractImage_IsVisible(NW_Image_AbstractImageOf(aEpocImage));
+      if(( aEpocImage->imageDecoding == NW_FALSE ) && (aEpocImage->bitmap) && (!isVisible))
+        {
+        // delet the image bitmap
+        CFbsBitmap* oldBitmap = CONST_CAST(CFbsBitmap*, (const CFbsBitmap*)aEpocImage->bitmap);
+        delete oldBitmap;
+        aEpocImage->bitmap = NULL;
+        CFbsBitmap* oldMask = CONST_CAST(CFbsBitmap*, (const CFbsBitmap*)aEpocImage->mask);
+        delete oldMask;
+        aEpocImage->mask = NULL;
+        }
+      else if ( aEpocImage->imageDecoding )
+        {
+        // cancel decoding
+        CEpoc32ImageDecoder* decoder = STATIC_CAST(CEpoc32ImageDecoder*, aEpocImage->decoder);
+        decoder->Cancel();
+        }
+    }