home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / central / mimages.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  56.0 KB  |  2,219 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #define    JMC_INIT_IMGCB_ID
  20.  
  21.     // Netscape
  22. // #include "mdmacmem.h"
  23. #include "client.h"
  24. #include "xp_mcom.h"
  25. #include "merrors.h"
  26. #include "xpassert.h"
  27. #include "mimages.h"
  28. #include "miconutils.h"
  29. #include "il_util.h"
  30. #include "il_icons.h"
  31. #include "CBrowserContext.h"
  32. #include "CHTMLView.h"
  33. #include "RandomFrontEndCrap.h"
  34. #include <UDrawingState.h>
  35. #include "UTextBox.h"
  36. #include "uerrmgr.h"
  37. #include "resgui.h"
  38. #ifndef NSPR20
  39. #include "prglobal.h"
  40. #endif
  41. #include "MacMemAllocator.h"
  42. #include "xlate.h"
  43.  
  44. #ifdef PROFILE
  45. #pragma profile on
  46. #endif
  47.  
  48.  
  49. #define    TRACK_IMAGE_CACHE_SIZE        0
  50.  
  51. #pragma mark --- TYPES ---
  52.  
  53. /*
  54.  * We store color spaces for the following bit depths:
  55.  * 1, 2, 4, 8, 2gray, 4gray, 8gray, 16, 32.
  56.  * Grayscale spaces are lower than colour spaces so that we can do a numerical compare
  57.  * on indices.
  58.  */
  59.  
  60. enum ColorSpaceIndex {
  61.     kFirstColorSpace = 0,
  62.     kOneBit = 0,
  63.     kEightBitGray,
  64.     kEightBitColor,
  65.     kSixteenBit,
  66.     kThirtytwoBit,
  67.     kNumColorSpaces
  68. };
  69.  
  70. enum DefaultColors {
  71.     kDefaultBGColorRed = 192,
  72.     kDefaultBGColorGreen = 192,
  73.     kDefaultBGColorBlue = 192
  74. };
  75.  
  76. /*
  77.  * Our internal Pixmap structure. What's the policy for internal priv. structs as to
  78.  * header files, etc?
  79.  */
  80.  
  81. typedef struct NS_PixMap
  82. {
  83.     PixMap        pixmap;
  84.     Handle        buffer_handle;
  85.     void *        image_buffer;
  86.     int32        lock_count;
  87.     Boolean        tiled;
  88. } NS_PixMap;
  89.  
  90.  
  91. typedef struct DrawingState
  92. {
  93.     short        copyMode;
  94.     NS_PixMap *    pixmap;
  95.     NS_PixMap *    mask;
  96. } DrawingState;
  97.  
  98.  
  99. typedef struct PictureGWorldState {
  100.     GWorldPtr    gworld;
  101.     RGBColor    transparentColor;
  102.     Int32        transparentIndex;
  103.     CTabHandle    ctab;
  104.     Int32        imageHeight;
  105.     Int32        bandHeight;
  106.     NS_PixMap *    image;
  107.     NS_PixMap *    mask;
  108. } PictureGWorldState;
  109.  
  110. /* BRAIN DAMAGE: This scary thing came from the old code */
  111. #define IL_ICON_OFFSET 300
  112.  
  113. /*
  114.  * Internal function prototypes
  115.  */
  116.  
  117. static OSErr AllocatePixMap ( IL_Pixmap * il_pixmap, jint width, jint height,
  118.     NS_PixMap * fe_pixmap, CTabHandle ctab );
  119.  
  120. static ColorSpaceIndex GetNextBestColorSpaceIndex ( ColorSpaceIndex index );
  121. static ColorSpaceIndex ConvertColorSpaceToIndex ( IL_ColorSpace * color_space );
  122. static ColorSpaceIndex ConvertDepthToColorSpaceIndex ( Int32 depth, Boolean grayScale );
  123. static IL_ColorSpace * GetColorSpace ( MWContext * context, ColorSpaceIndex space_index, CTabHandle * color_table );
  124. static CTabHandle ConvertColorSpaceToColorTable ( IL_ColorSpace * color_space );
  125. static void SetColorSpaceTransparentColor ( IL_ColorSpace * color_space, Uint8 red, Uint8 green, Uint8 blue );
  126.  
  127. static OSErr CreatePictureGWorld ( IL_Pixmap * image, IL_Pixmap * mask, PictureGWorldState * state );
  128. static void TeardownPictureGWorld ( PictureGWorldState * state );
  129. static void CopyPicture ( PictureGWorldState * state );
  130. static void CreateUniqueTransparentColor ( IL_Pixmap * image, PictureGWorldState * state );
  131. static Boolean FindColorInCTable ( CTabHandle ctab, Uint32 skipIndex, RGBColor * rgb );
  132.  
  133. static void LockPixmapBuffer ( IL_Pixmap * pixmap );
  134. static void UnlockPixmapBuffer ( IL_Pixmap * pixmap );
  135.  
  136. static void DrawScaledImage ( DrawingState * state, Point topLeft, jint x_offset,
  137.     jint y_offset, jint width, jint height );
  138. static void DrawTiledImage ( DrawingState * state, Point topLeft, jint x_offset,
  139.     jint y_offset, jint width, jint height );
  140.  
  141. static CIconHandle GetIconHandle ( jint iconID );
  142. static IL_GroupContext * CreateImageGroupContext ( MWContext * context );
  143.  
  144. static OSErr PreparePixmapForDrawing ( IL_Pixmap * image, IL_Pixmap * mask, Boolean canCopyMask,
  145.     DrawingState * state );
  146. static void DoneDrawingPixmap ( IL_Pixmap * image, IL_Pixmap * mask, DrawingState * state );
  147.  
  148. /*
  149.  * Globals
  150.  */
  151.  
  152. IL_ColorSpace *    gColorSpaces[ kNumColorSpaces ] = { NULL, NULL, NULL, NULL, NULL };
  153. CTabHandle        gColorTables[ kNumColorSpaces ] = { NULL, NULL, NULL, NULL, NULL };
  154. CTabHandle        gOneBitTable = NULL;
  155.  
  156. #if TRACK_IMAGE_CACHE_SIZE
  157. static Uint32    gCacheSize = 0;
  158. static Uint32    gMaxCacheSize = 0;
  159. #endif
  160.  
  161. #pragma mark --- IMAGE LIB CALLBACKS ---
  162.  
  163. /*
  164.  * Callback procs for the ImageLib
  165.  */
  166.  
  167. JMC_PUBLIC_API(void*)
  168. _IMGCB_getBackwardCompatibleInterface(struct IMGCB* /*self*/, const JMCInterfaceID* /*iid*/,
  169.     JMCException* */*exception*/)
  170. {
  171.     return NULL;
  172. }
  173.  
  174. JMC_PUBLIC_API(void)
  175. _IMGCB_init(struct IMGCB* /*self*/, JMCException* */*exception*/)
  176. {
  177.  
  178. }
  179.  
  180. JMC_PUBLIC_API(void)
  181. _IMGCB_NewPixmap(struct IMGCB* /*self*/, jint /*op*/, void* a, jint width, jint height, IL_Pixmap* pixmap,
  182.     IL_Pixmap* mask)
  183. {
  184.     MWContext *        context = (MWContext *) a;
  185.     NS_PixMap *        fe_pixmap;
  186.     NS_PixMap *        fe_mask;
  187.     OSErr            err;
  188.     ColorSpaceIndex    space_index;
  189.     ColorSpaceIndex    image_index;
  190.     CTabHandle        ctab;
  191.     IL_ColorSpace *    color_space;
  192.     FreeMemoryStats    freeMemory;
  193.     Uint32            freeTempMemory;
  194.     
  195.     XP_ASSERT(pixmap != NULL);
  196.  
  197.     ctab = NULL;
  198.     
  199.     /* BRAIN DAMAGE - for now let the image lib do any scaling */
  200.     pixmap->header.width = width;
  201.     pixmap->header.height = height;
  202.     
  203.     fe_pixmap = XP_NEW(NS_PixMap);
  204.     XP_ASSERT(fe_pixmap != NULL);
  205.     if ( fe_pixmap != NULL )
  206.         {
  207.         fe_pixmap->lock_count = 0;
  208.         fe_pixmap->image_buffer = 0L;
  209.         fe_pixmap->buffer_handle = 0L;
  210.         fe_pixmap->tiled = false;
  211.         
  212.         color_space = pixmap->header.color_space;
  213.         
  214.         /*
  215.          * if this pixmap's color space is of lower resolution than our current
  216.          * screen depth, then use the images, otherwise use the screen depth.
  217.          */
  218.         
  219.         space_index = ConvertDepthToColorSpaceIndex( 0, false );
  220.         
  221.         if ( color_space != NULL )
  222.             {
  223.             image_index = ConvertColorSpaceToIndex ( color_space );
  224.             
  225.             if ( image_index < space_index )
  226.                 {
  227.                 /*
  228.                  * This image appears to be at a lower colour depth, but it may have a 
  229.                  * unique color table, so we may want to allocate it at a deeper depth.
  230.                  * So, if we're getting short on memory, decrease the depth, otherwise
  231.                  * use the default depth.
  232.                  *
  233.                  * We don't really base this on the size of the image as we ideally want to
  234.                  * start decreasing the size of images, before we run out of memory (which
  235.                  * other parts of the browser may not handle as well).
  236.                  */
  237.                 memtotal ( 1024, &freeMemory );
  238.                 freeTempMemory = TempFreeMem();
  239.                 
  240.                 if (( freeMemory.totalFreeBytes < 0x10000 ) || ( freeTempMemory < 0x40000 ))
  241.                     {
  242.                     space_index = image_index;
  243.                     }
  244.                 }
  245.             
  246.             /* we don't want this color space anymore */
  247.             IL_ReleaseColorSpace ( color_space );
  248.             pixmap->header.color_space = NULL;
  249.             color_space = NULL;
  250.             }
  251.         
  252.         /*
  253.          * Try to allocate the pixmap at the ideal colour depth. If we can't, then keep
  254.          * downgrading the colour resolution until we can.
  255.          */
  256.         do
  257.             {
  258.             color_space = GetColorSpace ( context, space_index, &ctab );
  259.             
  260.             if ( color_space != NULL && ctab != NULL )
  261.                 {
  262.                 pixmap->header.color_space = color_space;
  263.                 err = AllocatePixMap ( pixmap, width, height, fe_pixmap, ctab );
  264.                 if ( err == noErr )
  265.                     {
  266.                     break;
  267.                     }
  268.                 }
  269.             
  270.             space_index = GetNextBestColorSpaceIndex ( space_index );
  271.             }
  272.         while ( space_index < kNumColorSpaces );
  273.         
  274.         if ( err == noErr )
  275.             {
  276.             /* add a ref to this color space */
  277.             IL_AddRefToColorSpace ( color_space );
  278.             XP_ASSERT(pixmap->header.color_space != NULL);
  279.             }
  280.         else
  281.             {
  282.             pixmap->header.color_space = NULL;
  283.             XP_DELETE(fe_pixmap);
  284.             fe_pixmap = NULL;
  285.             }
  286.         }
  287.     
  288.     pixmap->client_data = fe_pixmap;
  289.     
  290.     if ( mask != NULL )
  291.         {
  292.         /* BRAIN DAMAGE - for now let the image lib do any scaling */
  293.         mask->header.width = width;
  294.         mask->header.height = height;
  295.         
  296.         fe_mask = XP_NEW(NS_PixMap);
  297.         XP_ASSERT(fe_mask != NULL);
  298.         if ( fe_mask != NULL )
  299.             {
  300.             fe_mask->lock_count = 0;
  301.             fe_mask->image_buffer = NULL;
  302.             fe_mask->buffer_handle = NULL;
  303.             fe_mask->tiled = false;
  304.             
  305.             err = AllocatePixMap ( mask, width, height, fe_mask, gOneBitTable );
  306.             if ( err == noErr )
  307.                 {
  308.                 mask->client_data = fe_mask;
  309.                 }
  310.             else
  311.                 {
  312.                 XP_DELETE(fe_mask);
  313.                 }
  314.             }
  315.         }
  316.     
  317.     /*
  318.      * If the image has a transparent color, make sure to update it from the current context
  319.      */
  320.     if ( pixmap->header.transparent_pixel != NULL )
  321.         {
  322.         *pixmap->header.transparent_pixel = *context->transparent_pixel;
  323.         }
  324.         
  325.     XP_ASSERT(pixmap->header.color_space->pixmap_depth != 0 );
  326. }
  327.  
  328. JMC_PUBLIC_API(void)
  329. _IMGCB_UpdatePixmap(struct IMGCB* /*self*/, jint /*op*/, void* /*a*/, IL_Pixmap* /*pixmap*/, jint /*x_offset*/,
  330.     jint /*y_offset*/, jint /*width*/, jint /*height*/)
  331. {
  332. }
  333.  
  334. JMC_PUBLIC_API(void)
  335. _IMGCB_ControlPixmapBits(struct IMGCB* /*self*/, jint /*op*/, void* a, IL_Pixmap* pixmap, IL_PixmapControl message)
  336. {
  337.     MWContext *    context = (MWContext *) a;
  338.     NS_PixMap *    fe_pixmap = NULL;
  339.     
  340.     XP_ASSERT(pixmap != NULL);
  341.     
  342.     fe_pixmap = (NS_PixMap *) pixmap->client_data;
  343.     XP_ASSERT(fe_pixmap != NULL);
  344.  
  345.     if ( fe_pixmap != NULL )
  346.     {
  347.         switch ( message )
  348.         {
  349.             case IL_LOCK_BITS:
  350.                 LockPixmapBuffer ( pixmap );
  351.                 break;
  352.             
  353.             case IL_UNLOCK_BITS:
  354.                 UnlockPixmapBuffer ( pixmap );
  355.                 break;
  356.         }
  357.     }
  358. }
  359.  
  360. JMC_PUBLIC_API(void)
  361. _IMGCB_DestroyPixmap(struct IMGCB* /*self*/, jint /*op*/, void* a, IL_Pixmap* pixmap)
  362. {
  363.     MWContext *    context = (MWContext *) a;
  364.     NS_PixMap *    fe_pixmap = NULL;
  365.  
  366.     XP_ASSERT(pixmap != NULL);
  367.     fe_pixmap = (NS_PixMap *) pixmap->client_data;
  368.  
  369.     if ( fe_pixmap != NULL )
  370.         {
  371. #if TRACK_IMAGE_CACHE_SIZE
  372.         gCacheSize -= pixmap->header.widthBytes * pixmap->header.height;
  373. #endif
  374.         
  375.         if ( fe_pixmap->buffer_handle != NULL )
  376.             {
  377.             DisposeHandle ( fe_pixmap->buffer_handle );
  378.             }
  379.         
  380.         if ( fe_pixmap->image_buffer != NULL )
  381.             {
  382.             free ( fe_pixmap->image_buffer );
  383.             }
  384.         
  385.         XP_DELETE ( fe_pixmap );
  386.         }
  387. }
  388.  
  389. JMC_PUBLIC_API(void)
  390. _IMGCB_DisplayPixmap(struct IMGCB* /*self*/, jint /*op*/, void* a, IL_Pixmap* image, IL_Pixmap* mask,
  391.     jint x, jint y, jint x_offset, jint y_offset, jint width, jint height)
  392. {
  393.     MWContext *        context = (MWContext *) a;
  394.     NS_PixMap *        fe_pixmap;
  395.     NS_PixMap *        fe_mask;
  396.     SPoint32        topLeftImage;
  397.     StColorState    saveColorState();
  398.     Point            topLeft;
  399.     int32            x_origin;
  400.     int32            y_origin;
  401.     Boolean            canCopyMask;
  402.     OSErr            err;
  403.     DrawingState    state;
  404.     
  405.     CHTMLView* theHTMLView = ExtractHyperView(context);
  406.     if ( image != NULL && theHTMLView && theHTMLView->FocusDraw())
  407.         {
  408.         StColorPenState::Normalize();
  409.         
  410.         theHTMLView->GetLayerOrigin ( &x_origin, &y_origin );
  411.  
  412.         /*
  413.          * Can we use copymask for transparency? QuickDraw can't save Masks to Pictures nor
  414.          * can we print them.
  415.          */
  416.         canCopyMask = ( context->type != MWContextPrint ) && ( qd.thePort->picSave == NULL );
  417.         
  418.         fe_pixmap = (NS_PixMap *) image->client_data;
  419.         fe_mask = mask != NULL ? (NS_PixMap *) mask->client_data : NULL;
  420.         
  421.         if ( fe_pixmap != NULL )
  422.             {            
  423.             topLeftImage.h = x + x_offset + x_origin;
  424.             topLeftImage.v = y + y_offset + y_origin;
  425.  
  426.             theHTMLView->ImageToLocalPoint( topLeftImage, topLeft );
  427.             
  428.             err = PreparePixmapForDrawing ( image, mask, canCopyMask, &state );
  429.             if ( err == noErr )
  430.                 {
  431.                 if ( fe_pixmap->tiled != false )
  432.                     {
  433.                     DrawTiledImage ( &state, topLeft, x_offset, y_offset, width, height );
  434.                     }
  435.                 else
  436.                     {
  437.                     DrawScaledImage ( &state, topLeft, x_offset, y_offset, width, height );
  438.                     }
  439.                 
  440.                 DoneDrawingPixmap ( image, mask, &state );
  441.                 }
  442.             }
  443.         }
  444. }
  445.  
  446. JMC_PUBLIC_API(void)
  447. _IMGCB_DisplayIcon(struct IMGCB* /*self*/, jint /*op*/, void* a, jint x, jint y, jint icon_number)
  448. {
  449.     MWContext *    context = (MWContext *) a;
  450.     Rect        icon_dest;
  451.     CIconHandle    ic;
  452.     PixMap *    pixmap;
  453.     int32        x_origin;
  454.     int32        y_origin;
  455.     SPoint32    topLeftImage;
  456.     Point        topLeft;
  457.     
  458.     CHTMLView* theHTMLView = ExtractHyperView(context);
  459.     if (theHTMLView == NULL)
  460.         return;
  461.  
  462.     ic = GetIconHandle ( icon_number );
  463.     if ( ic != NULL )
  464.     {
  465.         pixmap = &(*ic)->iconPMap;
  466.         
  467.         // Convert from layer-relative coordinates to local coordinates
  468.         theHTMLView->GetLayerOrigin ( &x_origin, &y_origin );
  469.         topLeftImage.h = x + x_origin;
  470.         topLeftImage.v = y + y_origin;
  471.         theHTMLView->ImageToLocalPoint( topLeftImage, topLeft );
  472.     
  473.         icon_dest.left = topLeft.h;
  474.         icon_dest.top = topLeft.v;
  475.         icon_dest.right = icon_dest.left + ( pixmap->bounds.right - pixmap->bounds.left );
  476.         icon_dest.bottom = icon_dest.top + ( pixmap->bounds.bottom - pixmap->bounds.top );
  477.         
  478.         ::PlotCIconHandle( &icon_dest, atAbsoluteCenter, ttNone, ic );
  479.         CIconList::ReturnIcon ( ic );
  480.     }
  481. }
  482.  
  483. JMC_PUBLIC_API(void)
  484. _IMGCB_GetIconDimensions(struct IMGCB* /*self*/, jint /*op*/, void* a, int* width, int* height, jint icon_number)
  485. {
  486.     MWContext *    context = (MWContext *) a;
  487.     CIconHandle    ic;
  488.     PixMap *    pixmap;
  489.     
  490.     ic = GetIconHandle ( icon_number );
  491.     if ( ic == NULL )
  492.     {
  493.         *width = 16;
  494.         *height = 16;
  495.     }
  496.     else
  497.     {
  498.         pixmap = &(*ic)->iconPMap;
  499.         *width = pixmap->bounds.right - pixmap->bounds.left;
  500.         *height = pixmap->bounds.bottom - pixmap->bounds.top;
  501.  
  502.         CIconList::ReturnIcon ( ic );
  503.     }
  504. }
  505.  
  506. #pragma mark --- PUBLIC FUNCTIONS ---
  507.  
  508. EClickKind FindImagePart (
  509.                     MWContext *            context,
  510.                     LO_ImageStruct *    image,
  511.                     SPoint32 *            where,
  512.                     cstring *            url,
  513.                     cstring *            target,
  514.                     LO_AnchorData *    &    anchor )
  515. {
  516.     SPoint32            local_point;
  517.     EClickKind            click;
  518.     int                    iconWidth;
  519.     int                    iconHeight;
  520.     
  521.     click = eNone;
  522.     
  523.     /*
  524.      * Convert the document coordinate to an image local coordinate
  525.      */
  526.     local_point.h = where->h - ( image->x + image->x_offset + image->border_width );
  527.     local_point.v = where->v - ( image->y + image->y_offset + image->border_width );
  528.  
  529.     if (image->anchor_href)
  530.         {
  531.         PA_LOCK(*url, char*, (char*)image->anchor_href->anchor);
  532.         PA_UNLOCK(loImage->anchor_href->anchor );
  533.         PA_LOCK(*target, char*, (char*)image->anchor_href->target);
  534.         PA_UNLOCK(loImage->anchor_href->target );
  535.         }
  536.     
  537.     if ( image->image_attr->attrmask & LO_ATTR_ISFORM )
  538.     {
  539.         char s[100];
  540.  
  541.         // Ñ form image
  542.         click = eImageForm;
  543.         char * printString = GetCString(IMAGE_SUBMIT_FORM);
  544.         sprintf (s, (char*)printString, local_point.h, local_point.v); // "Submit form:%d,%d"
  545.         *url = s;
  546.     }
  547.     else if ( image->image_attr->usemap_name != NULL )
  548.     {
  549.         // Ñ client-side image maps
  550.         anchor = LO_MapXYToAreaAnchor( context, image, local_point.h, local_point.v );
  551.         if ( anchor )
  552.         {
  553.             PA_LOCK( *url, char*, (char*)anchor->anchor );
  554.             PA_UNLOCK( anchor->anchor );
  555.             PA_LOCK( *target, char*, (char*)anchor->target );
  556.             PA_UNLOCK( anchor->target );
  557.             click = eImageAnchor;
  558.         }
  559.         else
  560.             click = eNone;
  561.     }
  562.     else if ( (image->image_attr->attrmask & LO_ATTR_ISMAP) && image->anchor_href )
  563.     {
  564.         // Ñ╩ISMAP
  565.         click = eImageIsmap;
  566.         char s[50];
  567.         url->truncAt( '?' );
  568.         url->truncAt( '#' );
  569.         sprintf( s, "?%d,%d", local_point.h, local_point.v );
  570.         *url += s;
  571.     }
  572.     else if ( IsImageComplete ( image ) == FALSE )
  573.     {
  574.         // Did we click in an icon or an alt text?
  575.         // BRAIN DAMAGE
  576. #ifdef OLD_IMAGE_LIB
  577.         // Ñ delayed image
  578.         if (((IconProxy*)imageProxy)->ClickInIcon(mImageWhere.h, mImageWhere.v))
  579.             theKind = eImageIcon;
  580.         else if ( ((IconProxy*)imageProxy)->ClickInAltText(mImageWhere.h, mImageWhere.v) && loImage->anchor_href)
  581.             theKind = eImageAltText;
  582.         else
  583.             theKind = eNone;
  584.  
  585. #endif
  586.         /* is the image an icon? */
  587.         if ( image->is_icon )
  588.             {
  589.             IL_GetIconDimensions ( context->img_cx, image->icon_number, &iconWidth, &iconHeight );
  590.             
  591.             /*
  592.              * If the image has no anchor or the click is inside the icon, mark the click as being
  593.              * the icon
  594.              */
  595.             if ( ( ( local_point.h < iconWidth ) && ( local_point.v < iconHeight ) )
  596.                  || ( image->anchor_href == NULL ) )
  597.                 {
  598.                 click = eImageIcon;
  599.                 }
  600.             else
  601.                 {
  602.                 click = eImageAltText;
  603.                 }
  604.             }
  605.     }
  606.     else
  607.     {
  608.         // Ñ plain image with an anchor
  609.         if ( image->anchor_href )
  610.         {
  611.             click = eImageAnchor;
  612.         }
  613.     }
  614.     
  615.     return click;
  616. }
  617.  
  618. BOOL IsImageComplete (
  619.             LO_ImageStruct *    image )
  620. {
  621.     return ((image->image_status == IL_IMAGE_COMPLETE) || 
  622.         (image->image_status == IL_FRAME_COMPLETE));
  623. }
  624.  
  625. // a hack to get the URL of the image
  626. // if the image is using that reconnect hack, we get the URL of the document
  627. // instead of the URL of the image
  628. cstring GetURLFromImageElement(
  629.                 CBrowserContext *    inOwningContext,
  630.                 LO_ImageStruct *    inElement)
  631. {
  632.     cstring retString;
  633.     cstring urlString = (char*)inElement->image_url;
  634.  
  635.     // Ñ╩handle anything starting with "internal-"
  636.     if (IsInternalTypeLink(urlString))    
  637.         {
  638.         // Ñ handle special mail & news reconnects for internal decoded images
  639.         //        that start "internal-external-reconnect:" followed by the original
  640.         //        URL
  641.         if (IsMailNewsReconnect(urlString))
  642.             retString = &urlString[XP_STRLEN(reconnectHack) + 1];
  643.         // Ñ handle "internal-external-reconnect" case when we don't have an
  644.         //        associated anchor_href
  645.         else if (!inElement->anchor_href && IsInternalImage(urlString))
  646.             {
  647.             retString = inOwningContext->GetCurrentURL();
  648.             }
  649.         else
  650.         // Ñ jwz's hack upon a hack!
  651.         //    That is, if there is both an image and an anchor, and the address of
  652.         //    the image is internal-external-reconnect, use the anchor for the image,
  653.         //    and pretend there was no anchor.
  654.  
  655.         //    A side effect of the way I did this is that internal-external-reconnect
  656.         //    images which have HREF (mail and news articles) are clickable links to
  657.         //    themselves; we could special case this, but it doesn't hurt anything,
  658.         //    and could even be mistaken for intentional, so who cares ( JWZ wrote
  659.         //    that origially and I don't think it applies to the actual logic here - tgm ).
  660.             {
  661.             retString = (char*)inElement->anchor_href->anchor;
  662.             }
  663.         }
  664.     else
  665.         retString = urlString;
  666.         
  667.     return retString;
  668. }
  669.  
  670. PicHandle ConvertImageElementToPICT(
  671.                 LO_ImageStruct *    inElement)
  672. {
  673.     PicHandle            pic;
  674.     OpenCPicParams        picParams;
  675.     IL_Pixmap *            image;
  676.     IL_Pixmap *            mask;
  677.     DrawingState        state;
  678.     OSErr                err;
  679.     NS_PixMap *            fe_pixmap;
  680.     Rect                dstRect;
  681.     PictureGWorldState    picState;
  682.     GrafPtr                oldPort;
  683.     CGrafPort            cport;
  684.     
  685.     err = noErr;
  686.     
  687.     /*
  688.      * We render into our own port so that we don't need to play with other origin/port setting
  689.      * fun
  690.      */
  691.     GetPort ( &oldPort );
  692.     OpenCPort ( &cport );
  693.     
  694.     if ( QDError() != noErr )
  695.         return NULL;
  696.         
  697.     SetPort ( (GrafPtr) &cport );
  698.     
  699.     SetRect ( &picParams.srcRect, 0, 0, inElement->width, inElement->height );
  700.     picParams.hRes = 72L << 16;
  701.     picParams.vRes = 72L << 16;
  702.     picParams.version = 0;
  703.     picParams.reserved1 = 0;
  704.     picParams.reserved2 = 0;
  705.     
  706.     image = IL_GetImagePixmap ( inElement->image_req );
  707.     mask = IL_GetMaskPixmap ( inElement->image_req );
  708.     
  709.     if ( image == NULL )
  710.         {
  711.         return NULL;
  712.         }
  713.         
  714.     pic = OpenCPicture ( &picParams );
  715.     if ( pic != NULL )
  716.         {
  717.         /* if we have no mask, then we're just dandy */
  718.         if ( mask == NULL )
  719.             {
  720.             err = PreparePixmapForDrawing ( image, mask, false, &state );
  721.             if ( err == noErr )
  722.                 {
  723.                 fe_pixmap = state.pixmap;
  724.                 SetRect ( &dstRect, 0, 0, inElement->width, inElement->height );
  725.                 
  726.                 CopyBits ( (BitMap *) &fe_pixmap->pixmap, &qd.thePort->portBits,
  727.                     &fe_pixmap->pixmap.bounds, &dstRect, srcCopy, NULL );
  728.                 
  729.                 DoneDrawingPixmap ( image, mask, &state );
  730.                 }
  731.             }
  732.         else
  733.             {
  734.             /*
  735.              * We have transparency, so we suck. What we basically do is allocate an offscreen,
  736.              * render a unique color into the background, copymask the image over it and then
  737.              * copy that image into a picture.
  738.              *
  739.              * This particularly sucks for grayscale images as we need to make sure that our
  740.              * transparent color is unique.
  741.              *
  742.              * Thus, for indexed images, we create a color table that contains our reserved
  743.              * entry as a reserved index. We then CopyBits the original image onto it. Then,
  744.              * we set our reserved entry to a magic value and do a final CopyBits with transparent
  745.              * mode into the picture.
  746.              */
  747.             
  748.             err = CreatePictureGWorld ( image, mask, &picState );
  749.             if ( err == noErr )
  750.                 {
  751.                 LockPixmapBuffer ( image );
  752.                 LockPixmapBuffer ( mask );
  753.                 
  754.                 CopyPicture ( &picState );
  755.  
  756.                 UnlockPixmapBuffer ( image );
  757.                 UnlockPixmapBuffer ( mask );
  758.  
  759.                 TeardownPictureGWorld ( &picState );
  760.                 }
  761.             }
  762.                 
  763.         ClosePicture();
  764.         }
  765.     
  766.     SetPort ( oldPort );
  767.     CloseCPort ( &cport );
  768.     
  769.     /*
  770.      * If we got an error, don't return a bad picture
  771.      */
  772.     if ( err != noErr )
  773.         {
  774.         KillPicture ( pic );
  775.         pic = NULL;
  776.         }
  777.         
  778.     return pic;
  779. }
  780.  
  781. void CreateImageContext (
  782.             MWContext *            context )
  783. {
  784.     IL_DisplayData    data;
  785.     ColorSpaceIndex    space_index;
  786.     
  787.     /*
  788.      * Create a new image context.
  789.      */
  790.     context->img_cx = CreateImageGroupContext ( context );
  791.     Assert_(context->img_cx != NULL);
  792.     
  793.     if ( context->img_cx != NULL )
  794.     {
  795.         /*
  796.          * Set the context's color space to be our best one
  797.          */
  798.         space_index = ConvertDepthToColorSpaceIndex( 0, false );
  799.         context->color_space = GetColorSpace ( context, space_index, NULL );
  800.         PR_ASSERT(context->color_space != NULL);
  801.         
  802.         if ( context->type == MWContextPrint )
  803.             {
  804.             data.display_type = IL_Printer;
  805.             }
  806.         else
  807.             {
  808.             data.display_type = IL_Console;
  809.             }
  810.             
  811.         data.color_space = context->color_space;
  812.         data.progressive_display = CPrefs::GetBoolean(CPrefs::DisplayWhileLoading) ? 
  813.             PR_TRUE : PR_FALSE;
  814.         data.dither_mode = IL_Auto;
  815.  
  816.         IL_SetDisplayMode ( context->img_cx,
  817.             IL_PROGRESSIVE_DISPLAY | IL_DITHER_MODE | IL_COLOR_SPACE | IL_DISPLAY_TYPE, &data );
  818.     }
  819.     
  820.     /*
  821.      * Get a standard one bit table for masks
  822.      */
  823.     if ( gOneBitTable == NULL )
  824.     {
  825.         gOneBitTable = GetCTable ( 1 );
  826.     }
  827.     
  828.     /*
  829.      * Set the default background color
  830.      */
  831.     SetImageContextBackgroundColor ( context, kDefaultBGColorRed, kDefaultBGColorGreen, kDefaultBGColorBlue );
  832. }
  833.  
  834. void DestroyImageContext (
  835.             MWContext *            context )
  836. {
  837.     if ( context->color_space != NULL )
  838.     {
  839.         context->color_space = NULL;
  840.     }
  841.     
  842.     if ( context->img_cx != NULL )
  843.     {
  844.         IL_DestroyGroupContext ( context->img_cx );
  845.         context->img_cx = NULL;
  846.     }
  847. }
  848.  
  849. void SetImageContextBackgroundColor (
  850.             MWContext *            context,
  851.             Uint8                 red,
  852.             Uint8                green,
  853.             Uint8                 blue)
  854. {
  855.     IL_ColorSpace *    color_space;
  856.     IL_IRGB *        trans_pixel;
  857.     Uint8            count;
  858.  
  859.     color_space = context->color_space;
  860.     trans_pixel = context->transparent_pixel;
  861.     
  862.     if ( trans_pixel == NULL )
  863.         {
  864.         trans_pixel = context->transparent_pixel = XP_NEW_ZAP(IL_IRGB);
  865.         if ( trans_pixel == NULL )
  866.             return;
  867.         }
  868.  
  869.     /* Set the color of the transparent pixel. */
  870.     trans_pixel->red = red;
  871.     trans_pixel->green = green;
  872.     trans_pixel->blue = blue;
  873.     if ( color_space->type == NI_PseudoColor )
  874.         {
  875.         trans_pixel->index = color_space->cmap.num_colors - 1;
  876.         }
  877.  
  878.     /*
  879.      * For PseudoColor color spaces, we must also update our color map with this
  880.      * new color. Our transparent/background color is always at the end of the color map.
  881.      */
  882.     XP_ASSERT(color_space);
  883.     SetColorSpaceTransparentColor ( color_space, red, green, blue );
  884.     
  885.     /*
  886.      * Now set the transparent color for any other cached spaces
  887.      */
  888.     for ( count = 0; count < kNumColorSpaces; ++count )
  889.         {
  890.         if ( gColorSpaces[ count ] != NULL )
  891.             {
  892.             SetColorSpaceTransparentColor ( gColorSpaces[ count ], red, green, blue );
  893.             }
  894.         }
  895. }
  896.  
  897. GDHandle GetDeepestDevice (
  898.                 void )
  899. {
  900.     GDHandle deepest = GetMainDevice();
  901.     short depth = GetDepth (deepest);
  902.     
  903.     for (GDHandle current = GetDeviceList(); current; current = GetNextDevice (current)) {
  904.         if (UDrawingUtils::IsActiveScreenDevice (current)) {
  905.             short curDepth = GetDepth (current);
  906.             if (depth < curDepth) {
  907.                 depth = curDepth;
  908.                 deepest = current;
  909.             }
  910.         }
  911.     }
  912.  
  913.     return deepest;
  914. }
  915.  
  916. Boolean VerifyDisplayContextColorSpace (
  917.                 MWContext * context )
  918. {
  919.     ColorSpaceIndex    screen_index;
  920.     ColorSpaceIndex    current_index;
  921.     IL_ColorSpace *    color_space;
  922.     IL_DisplayData    data;
  923.     Boolean            mustReload;
  924.     uint32            cacheSize;
  925.     
  926.     mustReload = false;
  927.     
  928.     /*
  929.      * Make sure that the current display color space matches the context's color space
  930.      */
  931.     screen_index = ConvertDepthToColorSpaceIndex ( 0, false );
  932.     current_index = ConvertColorSpaceToIndex ( context->color_space );
  933.     if ( screen_index != current_index )
  934.         {
  935.         /* the color space of the screen has changed, update our display context */
  936.         color_space = GetColorSpace ( context, screen_index, NULL );
  937.         if ( color_space != NULL )
  938.             {
  939.             context->color_space = color_space;
  940.         
  941.             data.color_space = color_space;
  942.             IL_SetDisplayMode ( context->img_cx, IL_COLOR_SPACE, &data );
  943.             
  944.             SetColorSpaceTransparentColor ( color_space, context->transparent_pixel->red,
  945.                 context->transparent_pixel->green, context->transparent_pixel->blue );
  946.             
  947.             /* if this new space is deeper than the old, we should reload */
  948.             mustReload = screen_index > current_index;
  949.             
  950.             /* and if we do need to reload, we should flush the image cache as well */
  951.             /* it's up to our caller to decide if they want to reload the current page */
  952.             if ( mustReload )
  953.                 {
  954.                 /* the only way to do this is to set the cache to 0 size and then restore it */
  955.                 cacheSize = IL_GetCacheSize();
  956.                 IL_SetCacheSize ( 0 );
  957.                 IL_SetCacheSize ( cacheSize );
  958.                 }
  959.             }
  960.         }
  961.     
  962.     return mustReload;
  963. }
  964.  
  965. #pragma mark --- PRIVATE FUNCTIONS ---
  966.  
  967. /*
  968.  * Private Utilities
  969.  */
  970.  
  971. static IL_GroupContext * CreateImageGroupContext ( MWContext * context )
  972. {
  973.     IL_GroupContext *    img_cx;
  974.     IMGCB *                img_cb;
  975.     JMCException *        exc;
  976.  
  977.     exc = NULL;
  978.     
  979.     img_cb = IMGCBFactory_Create( &exc );
  980.     if (exc)
  981.     {
  982.         /* XXXM12N Should really return exception */
  983.         JMC_DELETE_EXCEPTION( &exc );
  984.         return 0L;
  985.     }
  986.  
  987.     /*
  988.      * Create an Image Group Context.  IL_NewGroupContext augments the
  989.      * reference count for the JMC callback interface.  The opaque
  990.      * argument to IL_NewGroupContext is the Front End's display
  991.      * context, which will be passed back to all the Image Library's
  992.      * FE callbacks.
  993.      */
  994.     img_cx = IL_NewGroupContext( (void*) context, (IMGCBIF *)img_cb);
  995.     
  996.     return img_cx;
  997. }
  998.  
  999. static OSErr AllocatePixMap ( IL_Pixmap * il_pixmap, jint width, jint height,
  1000.     NS_PixMap * fe_pixmap, CTabHandle ctab )
  1001. {
  1002.     UInt32            rowbytes;
  1003.     Uint32            pixmap_depth;
  1004.     OSErr            err;
  1005.     IL_ColorSpace *    color_space;
  1006.     PixMap *        pixmap;
  1007.     Uint32            buffer_size;
  1008.     
  1009.     err = noErr;
  1010.     pixmap = &fe_pixmap->pixmap;
  1011.     
  1012.     /*
  1013.      * Sanity checks
  1014.      */
  1015.     if ( il_pixmap == NULL || fe_pixmap == NULL || ctab == NULL )
  1016.     {
  1017.         return -1;
  1018.     }
  1019.     
  1020.     /*
  1021.      * Are we tiling this image?
  1022.      */
  1023.     if ( il_pixmap->header.width == width && il_pixmap->header.height == height )
  1024.     {
  1025.         /* yup */
  1026.         fe_pixmap->tiled = true;
  1027.     }
  1028.     else
  1029.     {
  1030.         /* nope, so use the dimensions of the src image as CopyBits can scale */
  1031.         fe_pixmap->tiled = false;
  1032.         width = il_pixmap->header.width;
  1033.         height = il_pixmap->header.height;
  1034.     }
  1035.     
  1036.     /*
  1037.      * Allocate the actual mac pixmap buffer
  1038.      */
  1039.     
  1040.     color_space = il_pixmap->header.color_space;
  1041.     pixmap_depth = color_space->pixmap_depth;
  1042.     
  1043.     pixmap->bounds.top = 0;
  1044.     pixmap->bounds.left = 0;
  1045.     pixmap->bounds.right = width;
  1046.     pixmap->bounds.bottom = height;
  1047.     pixmap->pmVersion = 0;
  1048.     pixmap->packType = 0;
  1049.     pixmap->packSize = 0;
  1050.     pixmap->hRes = 72L << 16;
  1051.     pixmap->vRes = 72L << 16;
  1052.     pixmap->pixelSize = pixmap_depth;
  1053.     pixmap->planeBytes = 0;
  1054.     pixmap->pmReserved = 0;
  1055.     
  1056.     if ( pixmap_depth <= 8 )
  1057.     {
  1058.         /* set our pixel type to indexed */
  1059.         pixmap->pixelType = 0;
  1060.         pixmap->cmpCount = 1;
  1061.         pixmap->cmpSize = pixmap_depth;
  1062.     }
  1063.     else
  1064.     {
  1065.         /* set our pixel type to direct color. we need to be sure to do this */
  1066.         /* to prevent nasty crashes when saving to pictures/printing */
  1067.         pixmap->pixelType = 0x10;
  1068.         pixmap->cmpCount = 3;
  1069.         pixmap->cmpSize = pixmap_depth == 16 ? 5 : 8;
  1070.     }
  1071.     
  1072.     pixmap->pmTable = ctab;
  1073.     
  1074.     rowbytes = width * pixmap_depth;
  1075.     rowbytes = (( rowbytes + 31 ) >> 5) << 2;
  1076.     
  1077.     /*
  1078.      * Sanity check rowBytes to make sure it's not over the QuickDraw limit
  1079.      * This will cause the calling code to downgrade the bit depth until we can allocate
  1080.      * the image, or just fail if it's too big overall
  1081.      */
  1082.     if ( rowbytes > 0x3FFF )
  1083.         {
  1084.         return -1;
  1085.         }
  1086.         
  1087.     il_pixmap->header.widthBytes = rowbytes;
  1088.  
  1089.     pixmap->rowBytes = rowbytes | 0x8000;
  1090.  
  1091.     /*
  1092.      * Allocate the buffer. If the image is really large, we just allocate out of temp
  1093.      * memory directly as it won't force the allocator to allocate a big tem mem chunk
  1094.      * which might be filled with other blocks that will force it to hang around for a
  1095.      * long time.
  1096.      *
  1097.      * I will probably change the large block allocator to always use temp memory for
  1098.      * huge blocks as it will simplify this code and fragment the large block heap less.
  1099.      */
  1100.     buffer_size = rowbytes * height;
  1101.     if ( buffer_size > 63 * 1024L )
  1102.         {
  1103.         fe_pixmap->buffer_handle = TempNewHandle ( buffer_size, &err );
  1104.         
  1105.         /*
  1106.          * If this fails, then go ahead and try malloc...
  1107.          */
  1108.         if ( fe_pixmap->buffer_handle == NULL )
  1109.             {
  1110.             fe_pixmap->image_buffer = malloc ( buffer_size );
  1111.             if ( fe_pixmap->image_buffer == NULL )
  1112.                 {
  1113.                 err = memFullErr;
  1114.                 }
  1115.             else
  1116.                 {
  1117.                 err = noErr;
  1118.                 }
  1119.             }
  1120.         }
  1121.     else
  1122.         {
  1123.         fe_pixmap->image_buffer = malloc ( buffer_size );
  1124.         if ( fe_pixmap->image_buffer == NULL )
  1125.             {
  1126.             err = memFullErr;
  1127.             }
  1128.         }
  1129.  
  1130.     pixmap->baseAddr = (Ptr) 0xFF5E0001;
  1131.     il_pixmap->bits = (Ptr) 0xFF5E0001;
  1132.  
  1133. #if TRACK_IMAGE_CACHE_SIZE
  1134.     if ( err == noErr )
  1135.         {
  1136.         gCacheSize += buffer_size;
  1137.         if ( gCacheSize > gMaxCacheSize )
  1138.             gMaxCacheSize = gCacheSize;
  1139.         }
  1140. #endif
  1141.         
  1142.     return err;
  1143. }
  1144.  
  1145. static ColorSpaceIndex GetNextBestColorSpaceIndex ( ColorSpaceIndex index )
  1146. {
  1147.     switch ( index )
  1148.         {
  1149.         default:                index = kNumColorSpaces;    break;
  1150.         case kOneBit:            index = kNumColorSpaces;    break;
  1151.         case kEightBitColor:    index = kOneBit;            break;
  1152.         case kSixteenBit:        index = kEightBitColor;        break;
  1153.         case kThirtytwoBit:        index = kSixteenBit;        break;
  1154.         }
  1155.     
  1156.     return index;
  1157. }
  1158.  
  1159. static ColorSpaceIndex ConvertColorSpaceToIndex ( IL_ColorSpace * color_space )
  1160. {
  1161.     ColorSpaceIndex    index;
  1162.  
  1163.     index = kEightBitColor;
  1164.     
  1165.     switch ( color_space->type )
  1166.         {
  1167.         case NI_TrueColor:
  1168.             if ( color_space->pixmap_depth > 16 )
  1169.                 {
  1170.                 index = kThirtytwoBit;
  1171.                 }
  1172.             else
  1173.                 {
  1174.                 index = kSixteenBit;
  1175.                 }
  1176.                 
  1177.             break;
  1178.         
  1179.         case NI_PseudoColor:
  1180.             switch ( color_space->pixmap_depth )
  1181.                 {
  1182.                 case 1:        index = kOneBit;        break;
  1183.                 case 2:        index = kEightBitColor;    break;
  1184.                 case 4:        index = kEightBitColor;    break;
  1185.                 case 8:        index = kEightBitColor;    break;
  1186.                 }
  1187.                 
  1188.             break;
  1189.         
  1190.         case NI_GreyScale:
  1191.             switch ( color_space->pixmap_depth )
  1192.                 {
  1193.                 case 1:        index = kOneBit;        break;
  1194.                 case 2:        index = kEightBitGray;    break;
  1195.                 case 4:        index = kEightBitGray;    break;
  1196.                 case 8:        index = kEightBitGray;    break;
  1197.                 }
  1198.  
  1199.             break;
  1200.         }
  1201.     
  1202.     return index;
  1203. }
  1204.  
  1205. static ColorSpaceIndex ConvertDepthToColorSpaceIndex ( Int32 depth, Boolean grayscale )
  1206. {
  1207.     ColorSpaceIndex    index;
  1208.     GDHandle        gd;
  1209.     
  1210.     /*
  1211.      * We default image depth to the depth of the deepest screen.
  1212.      */
  1213.     if ( depth == 0 )
  1214.         {
  1215.         gd = GetDeepestDevice();
  1216.         depth = GetDepth ( gd );
  1217.         
  1218.         /* check that magic bit to see if it's a grayscale device */
  1219.         grayscale = ( (*gd)->gdFlags & ( 1 << gdDevType ) ) == 0;
  1220.         }
  1221.     
  1222.     /*
  1223.      * If we're looking at allocating a direct pixmap, and the user's machine
  1224.      * is low on temp memory, then downgrade to 8 bit
  1225.      */
  1226.     if ( ( depth >= 16 ) && ( TempFreeMem() < ( 2048L * 1024L )) )
  1227.         {
  1228.         depth = 8;
  1229.         }
  1230.     
  1231.     if ( grayscale )
  1232.         {
  1233.         switch ( depth )
  1234.             {
  1235.             case 1:        index = kOneBit;        break;
  1236.             case 2:        index = kEightBitGray;    break;
  1237.             case 4:        index = kEightBitGray;    break;
  1238.             case 8:        index = kEightBitGray;    break;
  1239.             case 16:    index = kSixteenBit;    break;
  1240.             case 32:    index = kThirtytwoBit;    break;
  1241.             default:    index = kEightBitColor;    break;
  1242.             }
  1243.         }
  1244.     else
  1245.         {
  1246.         switch ( depth )
  1247.             {
  1248.             case 1:        index = kOneBit;        break;
  1249.             case 2:        index = kEightBitColor;    break;
  1250.             case 4:        index = kEightBitColor;    break;
  1251.             case 8:        index = kEightBitColor;    break;
  1252.             case 16:    index = kSixteenBit;    break;
  1253.             case 32:    index = kThirtytwoBit;    break;
  1254.             default:    index = kEightBitColor;    break;
  1255.             }
  1256.         }
  1257.     
  1258.     return index;
  1259. }
  1260.  
  1261. static IL_ColorSpace * AllocateColorSpace ( MWContext * context, ColorSpaceIndex space_index )
  1262. {
  1263.     IL_RGBBits        rgb;
  1264.     Int32            depth;
  1265.     Boolean            grayscale;
  1266.     IL_ColorMap *    color_map;
  1267.     IL_ColorSpace *    color_space;
  1268.     Int32            index;
  1269.     Uint8 *            index_map;
  1270.     Int32            num_colors;
  1271.     IL_IRGB            transparent_color;
  1272.     
  1273.     color_space = NULL;
  1274.     
  1275.     /* convert the space index back to depth/grayscale */
  1276.     switch ( space_index )
  1277.         {
  1278.         default:                return NULL;
  1279.         case kOneBit:            depth = 1; grayscale = true;    break;
  1280.         case kEightBitGray:        depth = 8; grayscale = true;    break;
  1281.         case kEightBitColor:    depth = 8; grayscale = false;    break;
  1282.         case kSixteenBit:        depth = 16; grayscale = false;    break;
  1283.         case kThirtytwoBit:        depth = 32; grayscale = false;    break;
  1284.         }
  1285.     
  1286.     if ( depth == 16 )
  1287.         {
  1288.         /*
  1289.          * Create a 16 bit color space
  1290.          */
  1291.         rgb.red_bits = 5;
  1292.         rgb.red_shift = 10;
  1293.         rgb.green_bits = 5;
  1294.         rgb.green_shift = 5;
  1295.         rgb.blue_bits = 5;
  1296.         rgb.blue_shift = 0;
  1297.         
  1298.         color_space = IL_CreateTrueColorSpace ( &rgb, 16 );
  1299.         }
  1300.     else
  1301.     if ( depth == 32 )
  1302.         {
  1303.         /*
  1304.          * Create a 32 bit color space
  1305.          */
  1306.         rgb.red_bits = 8;
  1307.         rgb.red_shift = 16;
  1308.         rgb.green_bits = 8;
  1309.         rgb.green_shift = 8;
  1310.         rgb.blue_bits = 8;
  1311.         rgb.blue_shift = 0;
  1312.         
  1313.         color_space = IL_CreateTrueColorSpace ( &rgb, 32 );
  1314.         }
  1315.     else
  1316.     if ( grayscale )
  1317.         {
  1318.         /*
  1319.          * Create an indexed grayscale space.
  1320.          */
  1321.         color_space = IL_CreateGreyScaleColorSpace ( depth, depth );
  1322.         }
  1323.     else
  1324.         {
  1325.         /*
  1326.          * Create an indexed color space.
  1327.          */
  1328.         
  1329.         /*
  1330.          * First create a color map with a reserved color for the transparent color.
  1331.          * When we first create a context, we won't yet have a transparent color, so
  1332.          * then we just set it to the default background color
  1333.          */
  1334.         if ( context->transparent_pixel != NULL )
  1335.             {
  1336.             transparent_color.red = context->transparent_pixel->red;
  1337.             transparent_color.green = context->transparent_pixel->green;
  1338.             transparent_color.blue = context->transparent_pixel->blue;
  1339.             }
  1340.         else
  1341.             {
  1342.             transparent_color.red = kDefaultBGColorRed;
  1343.             transparent_color.green = kDefaultBGColorGreen;
  1344.             transparent_color.blue = kDefaultBGColorBlue;
  1345.             }
  1346.         
  1347.         transparent_color.index = 0;
  1348.         
  1349.         color_map = IL_NewCubeColorMap ( NULL, 0, 1 << depth );
  1350.         
  1351.         /* Allocate the index map for this color map */
  1352.         if ( color_map != NULL )
  1353.             {
  1354.             IL_AddColorToColorMap ( color_map, &transparent_color );
  1355.                         
  1356.             num_colors = ( 1 << depth );
  1357.             
  1358.             index_map = (Uint8 *) XP_ALLOC ( sizeof(uint8) * num_colors );
  1359.             if ( index_map != NULL )
  1360.                 {
  1361.                 for ( index = num_colors - 1; index >= 0; --index )
  1362.                     {
  1363.                     index_map[ index ] = index;
  1364.                     }
  1365.                 
  1366.                 color_map->index = index_map;
  1367.                 }
  1368.             else
  1369.                 {
  1370.                 IL_DestroyColorMap ( color_map );
  1371.                 color_map = NULL;
  1372.                 }
  1373.             }
  1374.         
  1375.         /* Now build a color space around it */
  1376.         if ( color_map != NULL )
  1377.             {
  1378.             color_space = IL_CreatePseudoColorSpace ( color_map, depth, depth );
  1379.             if ( color_space == NULL )
  1380.                 {
  1381.                 IL_DestroyColorMap ( color_map );
  1382.                 color_map = NULL;
  1383.                 }
  1384.             }
  1385.         }
  1386.     
  1387.     return color_space;
  1388. }
  1389.  
  1390. static IL_ColorSpace * GetColorSpace ( MWContext * context, ColorSpaceIndex space_index, CTabHandle * color_table )
  1391. {
  1392.     IL_ColorSpace *    color_space;
  1393.     CTabHandle        ctable;
  1394.     
  1395.     /* bounds check */
  1396.     if ( space_index >= kNumColorSpaces )
  1397.         {
  1398.         return NULL;
  1399.         }
  1400.     
  1401.     ctable = NULL;
  1402.     if ( color_table != NULL )
  1403.         {
  1404.         *color_table = NULL;
  1405.         }
  1406.  
  1407.     color_space = gColorSpaces[ space_index ];
  1408.  
  1409.     /*
  1410.      * Do we need to allocate a space?
  1411.      */
  1412.     if ( color_space == NULL )
  1413.         {
  1414.         color_space = AllocateColorSpace ( context, space_index );
  1415.                 
  1416.         /*
  1417.          * Allocate a mac color table for this color space
  1418.          */
  1419.         if ( color_space != NULL )
  1420.             {
  1421.             ctable = ConvertColorSpaceToColorTable ( color_space );
  1422.             if ( ctable == NULL )
  1423.                 {
  1424.                 IL_ReleaseColorSpace ( color_space );
  1425.                 color_space = NULL;
  1426.                 }
  1427.             }
  1428.         
  1429.         /*
  1430.          * Add a reference to this color space so we're sure no one ever deletes it
  1431.          * out from under us (we keep them cached for the life of the browser).
  1432.          */
  1433.         IL_AddRefToColorSpace ( color_space );
  1434.         
  1435.         gColorSpaces[ space_index ] = color_space;
  1436.         gColorTables [ space_index ] = ctable;
  1437.         }
  1438.  
  1439.     if ( color_space != NULL )
  1440.         {
  1441.         ctable = gColorTables [ space_index ];
  1442.         }
  1443.     
  1444.     if ( color_table != NULL )
  1445.         {
  1446.         *color_table = ctable;
  1447.         }
  1448.  
  1449.     return color_space;
  1450. }
  1451.  
  1452. static CTabHandle ConvertColorSpaceToColorTable ( IL_ColorSpace * color_space )
  1453. {
  1454.     CTabHandle    ctab;
  1455.     ColorSpec *    cspecs;
  1456.     uint32        ctab_entries;
  1457.     uint32        count;
  1458.     NI_RGB *    map_colors;
  1459.     
  1460.     ctab = NULL;
  1461.     if ( color_space->pixmap_depth <= 8 )
  1462.         {
  1463.         ctab_entries = color_space->cmap.num_colors;
  1464.         }
  1465.     else
  1466.         {
  1467.         ctab_entries = 1;
  1468.         }
  1469.     
  1470.     ctab = (CTabHandle) NewHandleClear ( sizeof(ColorTable) +
  1471.         sizeof(ColorSpec) * (ctab_entries - 1) );
  1472.     if ( ctab != NULL )
  1473.         {
  1474.         (*ctab)->ctSeed = GetCTSeed();
  1475.         (*ctab)->ctSize = ctab_entries - 1;
  1476.         
  1477.         /*
  1478.          * Grab the color from the color map. If we're direct, then don't bother.
  1479.          */
  1480.         if ( color_space->pixmap_depth <= 8 )
  1481.             {
  1482.             cspecs = &(*ctab)->ctTable[ 0 ];
  1483.             
  1484.             if ( color_space->type == NI_GreyScale )
  1485.                 {
  1486.                 Uint16    color;
  1487.                 Uint16    color_inc;
  1488.                 
  1489.                 color_inc = 256 / ( 1 << color_space->pixmap_depth );
  1490.                 color_inc |= color_inc << 8;
  1491.                 
  1492.                 color = 0;
  1493.                 for ( count = 0; count < ctab_entries; ++count )
  1494.                     {
  1495.                     cspecs->value = count;
  1496.                     cspecs->rgb.red = color;
  1497.                     cspecs->rgb.green = color;
  1498.                     cspecs->rgb.blue = color;
  1499.                     
  1500.                     cspecs++;
  1501.                     color += color_inc;
  1502.                     }
  1503.                 }
  1504.             else
  1505.                 {
  1506.                 map_colors = &color_space->cmap.map[ 0 ];
  1507.                 
  1508.                 for ( count = 0; count < ctab_entries; ++count )
  1509.                     {
  1510.                     cspecs->value = count;
  1511.                     cspecs->rgb.red = ((uint16) map_colors->red << 8 ) | (uint16) map_colors->red;
  1512.                     cspecs->rgb.green = ((uint16) map_colors->green << 8 ) | (uint16) map_colors->green;
  1513.                     cspecs->rgb.blue = ((uint16) map_colors->blue << 8 ) | (uint16) map_colors->blue;
  1514.                     
  1515.                     cspecs++;
  1516.                     map_colors++;
  1517.                     }
  1518.                 }
  1519.             }
  1520.         }
  1521.     
  1522.     return ctab;
  1523. }
  1524.  
  1525. static void SetColorSpaceTransparentColor ( IL_ColorSpace * color_space, Uint8 red, Uint8 green, Uint8 blue )
  1526. {
  1527.     if ( color_space->type == NI_PseudoColor )
  1528.         {
  1529.         IL_RGB *map;
  1530.         
  1531.         /*
  1532.          * The last color in the color map is always our transparent color
  1533.          */
  1534.         map = &color_space->cmap.map[ color_space->cmap.num_colors - 1 ];
  1535.         map->red = red;
  1536.         map->green = green;
  1537.         map->blue = blue;
  1538.         }
  1539. }
  1540.  
  1541. static OSErr CreatePictureGWorld ( IL_Pixmap * image, IL_Pixmap * mask, PictureGWorldState * state )
  1542. {
  1543.     OSErr            err;
  1544.     CTabHandle        ctab;
  1545.     NI_IRGB *        transparent_pixel;
  1546.     IL_ColorSpace *    color_space;
  1547.     CGrafPtr        savePort;
  1548.     GDHandle        saveGD;
  1549.     Boolean            remapTransparentIndex;
  1550.     
  1551.     remapTransparentIndex = false;
  1552.     
  1553.     state->image = (NS_PixMap *) image->client_data;
  1554.     
  1555.     if ( mask != NULL )
  1556.         {
  1557.         state->mask = (NS_PixMap *) mask->client_data;
  1558.         
  1559.         color_space = image->header.color_space;
  1560.         XP_ASSERT(color_space);
  1561.         
  1562.         transparent_pixel = image->header.transparent_pixel;
  1563.         XP_ASSERT(transparent_pixel);
  1564.         
  1565.         /* get our own expended copy of the background/transparent color */
  1566.         state->transparentColor.red = (uint16) transparent_pixel->red | ( (uint16) transparent_pixel->red << 8 );
  1567.         state->transparentColor.green = (uint16) transparent_pixel->green | ( (uint16) transparent_pixel->green << 8 );
  1568.         state->transparentColor.blue = (uint16) transparent_pixel->blue | ( (uint16) transparent_pixel->blue << 8 );
  1569.         
  1570.         /*
  1571.          * If the image has an indexed color color_space, then we know it has a unique
  1572.          * transparent color. So, we can use it's color table for the copybits
  1573.          */
  1574.         if ( image->header.color_space->type == NI_PseudoColor )
  1575.             {
  1576.             ctab = state->image->pixmap.pmTable;
  1577.             err = HandToHand ( (Handle *) &ctab );
  1578.             if ( err != noErr )
  1579.                 return err;
  1580.             
  1581.             /* make sure the background entry contains the correct color */            
  1582.             state->transparentIndex = color_space->cmap.num_colors - 1;
  1583.             (*ctab)->ctTable[ state->transparentIndex ].rgb = state->transparentColor;
  1584.             remapTransparentIndex = true;
  1585.             }
  1586.         else
  1587.         /*
  1588.          * If the image has a grayscale space, we're in a world of hurt. We need to steal
  1589.          * an index to use for the transparent color
  1590.          */
  1591.         if ( image->header.color_space->type == NI_GreyScale )
  1592.             {
  1593.             ctab = state->image->pixmap.pmTable;
  1594.             err = HandToHand ( (Handle *) &ctab );
  1595.             if ( err != noErr )
  1596.                 return err;
  1597.             
  1598.             /* use the default transparent color, but find it's true index */
  1599.             state->transparentIndex = -1;
  1600.             remapTransparentIndex = true;
  1601.             }
  1602.         else
  1603.         /*
  1604.          * The image has a true color space. Hopefully, the transparent color is unique to the
  1605.          * image. If not, (ie the site's bg color is the same as a valid color in the image), we'll
  1606.          * have more be transparent than should be. There's not a whole lot we can do about this
  1607.          */
  1608.             {
  1609.             ctab = NULL;            
  1610.             }
  1611.         
  1612.         state->ctab = ctab;
  1613.  
  1614.         /*
  1615.          * Make sure that our transparent color is unique. We can choose any color we want as it
  1616.          * won't actually be displayed.
  1617.          */
  1618.         CreateUniqueTransparentColor ( image, state );
  1619.                         
  1620.         err = NewGWorld ( &state->gworld, image->header.color_space->pixmap_depth,
  1621.             &state->image->pixmap.bounds, ctab, NULL, useTempMem );
  1622.         
  1623.         /*
  1624.          * If we have an indexed image, then find out where the transparent color maps to
  1625.          * so that we can remove it
  1626.          */
  1627.         if ( err == noErr && remapTransparentIndex )
  1628.             {
  1629.             GetGWorld ( &savePort, &saveGD );
  1630.             SetGWorld ( state->gworld, NULL );
  1631.             
  1632.             /* where does our transparent color really map to? */
  1633.             state->transparentIndex = Color2Index ( &state->transparentColor );
  1634.             
  1635.             /* Remove this from the inverse table */
  1636.             ReserveEntry ( state->transparentIndex, true );
  1637.             
  1638.             /*
  1639.              * get the real RGB color this maps to (should always be the same for PseudoColor but
  1640.              * could be different for grayscape where we may not have a unique color).
  1641.              */
  1642.             Index2Color ( state->transparentIndex, &state->transparentColor );
  1643.             
  1644.             SetGWorld ( savePort, saveGD );
  1645.             }
  1646.         else
  1647.             {
  1648.             state->transparentIndex = -1;
  1649.             }
  1650.         }
  1651.     else
  1652.         {
  1653.         state->mask = NULL;
  1654.         
  1655.         }
  1656.     
  1657.     return err;
  1658. }
  1659.  
  1660. static void TeardownPictureGWorld ( PictureGWorldState * state )
  1661. {
  1662.     if ( state->gworld != NULL )
  1663.         {
  1664.         DisposeGWorld ( state->gworld );
  1665.         }
  1666.     
  1667.     if ( state->ctab != NULL )
  1668.         {
  1669.         DisposeCTable ( state->ctab );
  1670.         }
  1671. }
  1672.  
  1673. static void CreateUniqueTransparentColor ( IL_Pixmap * image, PictureGWorldState * state )
  1674. {
  1675.     RGBColor    rgb;
  1676.     Boolean        foundColor;
  1677.     
  1678.     if ( state->ctab == NULL )
  1679.         return;
  1680.     
  1681.     /*
  1682.      * We have no idea which colors are actually used in the image (unless we want to actually
  1683.      * go over each pixel).
  1684.      *
  1685.      * For direct pixels and grayscale images, we just use the transparent color that came along
  1686.      * with the page. On color images, we actually try to find a unique color
  1687.      */
  1688.  
  1689. #define    INV_TAB_RES        4
  1690. #define    INV_TAB_MAX        ((Uint16)~((0x8000 >> (INV_TAB_RES-1)) - 1))
  1691. #define    INV_TAB_MASK(c)    ((c) & INV_TAB_MAX)
  1692. #define    INV_TAB_INC        (0x8000 >> (INV_TAB_RES-1))
  1693.  
  1694.     if ( image->header.color_space->type == NI_PseudoColor )
  1695.         {
  1696.         /*
  1697.          * We assume QD will use it's default 4bit inverse table, so try and find a unique color
  1698.          * within that space.
  1699.          * First look for our default transparent color. Most of the time it should be unique.
  1700.          */
  1701.                 
  1702.         if ( FindColorInCTable ( state->ctab, state->transparentIndex, &state->transparentColor ))
  1703.             {
  1704.             foundColor = false;
  1705.             
  1706.             /* we found that color, so run through all the colors in the hope of finding something unique */
  1707.             for ( rgb.red = 0; (Uint16)rgb.red <= INV_TAB_MAX; rgb.red += INV_TAB_INC )
  1708.                 {
  1709.                 for ( rgb.green = 0; (Uint16)rgb.green <= INV_TAB_MAX; rgb.green += INV_TAB_INC )
  1710.                     {
  1711.                     for ( rgb.blue = 0; (Uint16)rgb.blue <= INV_TAB_MAX; rgb.blue += INV_TAB_INC )
  1712.                         {
  1713.                         if ( FindColorInCTable ( state->ctab, state->transparentIndex, &rgb ) == false )
  1714.                             {
  1715.                             foundColor = true;
  1716.                             goto foundit;
  1717.                             }
  1718.                         }
  1719.                     }
  1720.                 }
  1721.  
  1722. foundit:                
  1723.             /* if we found a color, then use it */
  1724.             if ( foundColor )
  1725.                 {
  1726.                 state->transparentColor = rgb;
  1727.                 (*state->ctab)->ctTable[ state->transparentIndex ].rgb = rgb;
  1728.                 }
  1729.             }
  1730.         }
  1731. }
  1732.  
  1733. static Boolean FindColorInCTable ( CTabHandle ctab, Uint32 skipIndex, RGBColor * rgb )
  1734. {
  1735.     Boolean        colorIsUsed;
  1736.     Uint32        count;
  1737.     UInt32        num_entries;
  1738.     ColorSpec *    cspecs;
  1739.  
  1740.     cspecs = (*ctab)->ctTable;
  1741.     num_entries = (*ctab)->ctSize;
  1742.     colorIsUsed = false;
  1743.  
  1744.     /* run through the color table and try to find this color */
  1745.     for ( count = 0; count < num_entries; ++count )
  1746.         {
  1747.         /* don't bother checking the current transparent color */
  1748.         if ( count != skipIndex )
  1749.             {
  1750.             /* make sure the color is unique within the resolution of the inverse table */
  1751.             if ( INV_TAB_MASK(cspecs[count].rgb.red) == INV_TAB_MASK(rgb->red) &&
  1752.                     INV_TAB_MASK(cspecs[count].rgb.green) == INV_TAB_MASK(rgb->green) &&
  1753.                     INV_TAB_MASK(cspecs[count].rgb.blue) == INV_TAB_MASK(rgb->blue) )
  1754.                 {
  1755.                 colorIsUsed = true;
  1756.                 break;
  1757.                 }
  1758.             }
  1759.         }
  1760.     
  1761.     return colorIsUsed;
  1762. }
  1763.  
  1764. static void CopyPicture ( PictureGWorldState * state )
  1765. {
  1766.     CGrafPtr        savePort;
  1767.     GDHandle        saveGD;
  1768.     PixMapHandle    pm;
  1769.     SInt8            hState;
  1770.     
  1771.     GetGWorld ( &savePort, &saveGD );
  1772.     pm = GetGWorldPixMap ( state->gworld );
  1773.     hState = HGetState ( (Handle) pm );
  1774.     
  1775.     LockPixels ( pm );
  1776.  
  1777.     SetGWorld ( state->gworld, NULL );
  1778.     
  1779.     /* copy our image into the gworld */
  1780.     CopyBits ( (BitMap *) &state->image->pixmap, (BitMap *) *pm, &state->image->pixmap.bounds,
  1781.         &state->image->pixmap.bounds, srcCopy, NULL );
  1782.     
  1783.     /* make our transparent index writeable again */
  1784.     if ( state->transparentIndex != -1 )
  1785.         {
  1786.         ReserveEntry ( state->transparentIndex, false );
  1787.         
  1788.         /* make sure the value field in the color table for the transparent entry is correct */
  1789.         (*(*pm)->pmTable)->ctTable[ state->transparentIndex ].value = state->transparentIndex;
  1790.         }
  1791.     
  1792.     /* fill the masked area with this color */
  1793.     RGBForeColor ( &state->transparentColor );
  1794.     
  1795.     CopyBits ( (BitMap *) &state->mask->pixmap, (BitMap *) *pm, &state->mask->pixmap.bounds,
  1796.         &state->image->pixmap.bounds, notSrcOr, NULL );
  1797.  
  1798.     SetGWorld ( savePort, saveGD );
  1799.     
  1800.     /* now actually copy the picture data, making the transparent color transparent */
  1801.     ForeColor ( blackColor );    
  1802.     RGBBackColor ( &state->transparentColor );
  1803.     
  1804.     CopyBits ( (BitMap *) *pm, &qd.thePort->portBits, &(*pm)->bounds, &(*pm)->bounds, transparent, NULL );
  1805.     
  1806.     UnlockPixels ( pm );
  1807.     HSetState ( (Handle) pm, hState );
  1808. }
  1809.  
  1810. static void LockPixmapBuffer ( IL_Pixmap * pixmap )
  1811. {
  1812.     NS_PixMap * fe_pixmap;
  1813.     
  1814.     fe_pixmap = (NS_PixMap *) pixmap->client_data;
  1815.     if ( fe_pixmap != NULL )
  1816.         {
  1817.         if ( fe_pixmap->lock_count == 0 )
  1818.             {
  1819.             if ( fe_pixmap->buffer_handle != NULL )
  1820.                 {
  1821.                 HLock ( fe_pixmap->buffer_handle );
  1822.                 fe_pixmap->pixmap.baseAddr = *fe_pixmap->buffer_handle;
  1823.                 }
  1824.             else
  1825.                 {
  1826.                 fe_pixmap->pixmap.baseAddr = (char *) fe_pixmap->image_buffer;
  1827.                 }
  1828.                 
  1829.             pixmap->bits = fe_pixmap->pixmap.baseAddr;
  1830.             }
  1831.         
  1832.         fe_pixmap->lock_count++;
  1833.         }
  1834. }
  1835.  
  1836. static void UnlockPixmapBuffer ( IL_Pixmap * pixmap )
  1837. {
  1838.     NS_PixMap * fe_pixmap;
  1839.  
  1840.     fe_pixmap = (NS_PixMap *) pixmap->client_data;
  1841.  
  1842.     if ( fe_pixmap != NULL )
  1843.         {
  1844.         if ( --fe_pixmap->lock_count == 0 )
  1845.             {
  1846.             if ( fe_pixmap->buffer_handle != NULL )
  1847.                 {
  1848.                 HUnlock ( fe_pixmap->buffer_handle );
  1849.                 }
  1850.  
  1851.             fe_pixmap->pixmap.baseAddr = (Ptr) 0xFF5E0001;
  1852.             pixmap->bits = fe_pixmap->pixmap.baseAddr;
  1853.             }
  1854.         }
  1855. }
  1856.  
  1857.  
  1858. static void DrawScaledImage ( DrawingState * state, Point topLeft, jint x_offset,
  1859.     jint y_offset, jint width, jint height )
  1860. {
  1861.     Rect            srcRect;
  1862.     Rect *            maskRectPtr;
  1863.     Rect            dstRect;
  1864.     PixMap *        maskPtr;
  1865.     NS_PixMap *        fe_pixmap;
  1866.     NS_PixMap *        fe_mask;
  1867.     
  1868.     fe_pixmap = state->pixmap;
  1869.     fe_mask = state->mask;
  1870.     
  1871.     if ( fe_mask != NULL )
  1872.     {
  1873.         maskPtr = &fe_mask->pixmap;
  1874.         maskRectPtr = &maskPtr->bounds;
  1875.     }
  1876.     else
  1877.     {
  1878.         maskPtr = NULL;
  1879.         maskRectPtr = NULL;
  1880.     }
  1881.  
  1882.     srcRect.left = x_offset;
  1883.     srcRect.top = y_offset;
  1884.     srcRect.right = x_offset + width;
  1885.     srcRect.bottom = y_offset + height;
  1886.     
  1887.     /*
  1888.      * Clip src Rect to the image.
  1889.      */
  1890.     if ( fe_pixmap->pixmap.bounds.right < srcRect.right )
  1891.     {
  1892.         srcRect.right = fe_pixmap->pixmap.bounds.right;
  1893.     }
  1894.     if ( fe_pixmap->pixmap.bounds.bottom < srcRect.bottom )
  1895.     {
  1896.         srcRect.bottom = fe_pixmap->pixmap.bounds.bottom;
  1897.     }
  1898.     
  1899.     SetRect ( &dstRect, topLeft.h, topLeft.v, topLeft.h + width, topLeft.v + height );
  1900.                 
  1901.     if ( maskPtr == NULL )
  1902.     {
  1903.         CopyBits ( (BitMap *) &fe_pixmap->pixmap, &qd.thePort->portBits, &srcRect,
  1904.             &dstRect, state->copyMode, NULL );
  1905.     }
  1906.     else
  1907.     {
  1908.         CopyMask ( (BitMap *) &fe_pixmap->pixmap, (BitMap *) maskPtr, &qd.thePort->portBits,
  1909.             &srcRect, maskRectPtr, &dstRect );
  1910.     }
  1911. }
  1912.  
  1913. static void DrawTiledImage ( DrawingState * state, Point topLeft, jint x_offset,
  1914.     jint y_offset, jint width, jint height )
  1915. {
  1916.  
  1917.     Rect            srcRect;
  1918.     Rect *            maskRectPtr;
  1919.     Rect            dstRect;
  1920.     PixMap *        maskPtr;
  1921.     int32            right_clip;
  1922.     int32            bottom_clip;
  1923.     int32            left;
  1924.     int32            top;
  1925.     int32            img_width;
  1926.     int32            img_height;
  1927.     int32            tile_width;
  1928.     int32            tile_height;
  1929.     int32            src_x_offset;
  1930.     int32            src_y_offset;
  1931.     NS_PixMap *        fe_pixmap;
  1932.     NS_PixMap *        fe_mask;
  1933.             
  1934.     fe_pixmap = state->pixmap;
  1935.     fe_mask = state->mask;
  1936.  
  1937.     if ( fe_mask != NULL )
  1938.     {
  1939.         maskPtr = &fe_mask->pixmap;
  1940.         maskRectPtr = &srcRect;
  1941.     }
  1942.     else
  1943.     {
  1944.         maskPtr = NULL;
  1945.         maskRectPtr = NULL;
  1946.     }
  1947.     
  1948.     img_width = fe_pixmap->pixmap.bounds.right - fe_pixmap->pixmap.bounds.left;
  1949.     img_height = fe_pixmap->pixmap.bounds.bottom - fe_pixmap->pixmap.bounds.top;
  1950.  
  1951.     right_clip = topLeft.h + width;
  1952.     bottom_clip = topLeft.v + height;
  1953.     
  1954.     /* the first row may be shorter */
  1955.     tile_height = img_height - ( y_offset % img_height );
  1956.     
  1957.     /*
  1958.      * Walk through all the tiles in dst space
  1959.      */
  1960.     
  1961.     top = topLeft.v;
  1962.     src_y_offset = y_offset % img_height;
  1963.     
  1964.     while ( top < bottom_clip )
  1965.     {
  1966.         left = topLeft.h;
  1967.         tile_width = img_width - ( x_offset % img_width );
  1968.         src_x_offset = x_offset % img_width;
  1969.         
  1970.         while ( left < right_clip )
  1971.         {
  1972.             dstRect.left = left;
  1973.             dstRect.top = top;
  1974.             dstRect.right = left + tile_width;
  1975.             dstRect.bottom = top + tile_height;
  1976.             
  1977.             srcRect.left = src_x_offset;
  1978.             srcRect.top = src_y_offset;
  1979.             srcRect.right = src_x_offset + tile_width;
  1980.             srcRect.bottom = src_y_offset + tile_height;
  1981.                 
  1982.             if ( maskPtr == NULL )
  1983.             {
  1984.                 CopyBits ( (BitMap *) &fe_pixmap->pixmap, &qd.thePort->portBits, &srcRect,
  1985.                     &dstRect, state->copyMode, NULL );
  1986.             }
  1987.             else
  1988.             {
  1989.                 CopyMask ( (BitMap *) &fe_pixmap->pixmap, (BitMap *) maskPtr, &qd.thePort->portBits,
  1990.                     &srcRect, maskRectPtr, &dstRect );
  1991.             }
  1992.             
  1993.             /*
  1994.              * Bump to the next column and be sure to clip if it's the last one
  1995.              */
  1996.             left += tile_width;
  1997.             tile_width = img_width;
  1998.             if ( left + tile_width > right_clip )
  1999.             {
  2000.                 tile_width = right_clip - left;
  2001.             }
  2002.             src_x_offset = 0;
  2003.         }
  2004.         
  2005.         /*
  2006.          * Bump to the next row and be sure to clip if it's the last one
  2007.          */
  2008.         top += tile_height;
  2009.         tile_height = img_height;
  2010.         if ( top + tile_height > bottom_clip )
  2011.         {
  2012.             tile_height = bottom_clip - top;
  2013.         }
  2014.         src_y_offset = 0;
  2015.     }
  2016. }
  2017.  
  2018. static OSErr PreparePixmapForDrawing ( IL_Pixmap * image, IL_Pixmap * mask, Boolean canCopyMask,
  2019.     DrawingState * state )
  2020. {
  2021.     RGBColor        rgb;
  2022.     long            index;
  2023.     NI_IRGB *        transparent_pixel;
  2024.     IL_ColorSpace *    color_space;
  2025.     CTabHandle        ctab;
  2026.     
  2027.     state->copyMode = srcCopy;
  2028.     state->pixmap = (NS_PixMap *) image->client_data;
  2029.     state->mask = NULL;
  2030.     
  2031.     if ( state->pixmap == NULL )
  2032.         {
  2033.         return -1;
  2034.         }
  2035.         
  2036.     color_space = image->header.color_space;
  2037.     XP_ASSERT(color_space);
  2038.     
  2039.     if ( mask != NULL )
  2040.         {
  2041.         state->mask = (NS_PixMap *) mask->client_data;
  2042.         }
  2043.     
  2044.     /*
  2045.      * If we can't copymask and we have a transparent colour, then we need to use QuickDraw's
  2046.      * transparent mode and set the OpColor
  2047.      */
  2048.     transparent_pixel = image->header.transparent_pixel;
  2049.     
  2050.     if ( transparent_pixel != NULL )
  2051.         {
  2052.         /* Extract the transparent color for this pixmap */
  2053.         rgb.red = (uint16) transparent_pixel->red | ( (uint16) transparent_pixel->red << 8 );
  2054.         rgb.green = (uint16) transparent_pixel->green | ( (uint16) transparent_pixel->green << 8 );
  2055.         rgb.blue = (uint16) transparent_pixel->blue | ( (uint16) transparent_pixel->blue << 8 );
  2056.         
  2057.         /* if we have an indexed color space, then update the bg color. Grayscale color */
  2058.         /* spaces assume the color's been mapped to the closest default gray */
  2059.         if (color_space->type == NI_PseudoColor)
  2060.             {
  2061.             index = color_space->cmap.num_colors - 1;
  2062.             
  2063.             ctab = state->pixmap->pixmap.pmTable;
  2064.             (*ctab)->ctTable[ index ].rgb = rgb;
  2065.             }
  2066.         
  2067.         /*
  2068.          * now, if we have a mask, but we can't copymask, then set our transfer mode
  2069.          * to be transparent. We may have problems if the background color matches a
  2070.          * color in the image, but that's life for now...
  2071.          */
  2072.         if ( mask != NULL && !canCopyMask )
  2073.             {
  2074.             /* don't use the mask anymore */
  2075.             state->mask = NULL;
  2076.             
  2077.             state->copyMode = transparent;
  2078.             RGBBackColor ( &rgb );
  2079.             }
  2080.         }
  2081.         
  2082.     LockPixmapBuffer ( image );
  2083.     if ( state->mask != NULL )
  2084.         {
  2085.         LockPixmapBuffer ( mask );
  2086.         }
  2087.  
  2088.     return noErr;
  2089. }
  2090.  
  2091. static void DoneDrawingPixmap ( IL_Pixmap * image, IL_Pixmap * mask, DrawingState * state )
  2092. {
  2093.     UnlockPixmapBuffer ( image );
  2094.     if ( state->mask != NULL )
  2095.         {
  2096.         UnlockPixmapBuffer ( mask );
  2097.         }
  2098. }
  2099.  
  2100. static CIconHandle GetIconHandle ( jint iconID )
  2101. {
  2102.     CIconHandle    ic;
  2103.     
  2104.     if ( iconID == IL_IMAGE_EMBED )
  2105.     {
  2106.         iconID = IL_IMAGE_BAD_DATA;
  2107.     }
  2108.     
  2109.     iconID += IL_ICON_OFFSET;
  2110.  
  2111.     ic = CIconList::GetIcon( iconID );
  2112.     if ( !ic )
  2113.     {
  2114.         if (iconID >= IL_GOPHER_FIRST)
  2115.             iconID = IL_GOPHER_FIRST-1;
  2116.         else if (iconID >= IL_NEWS_FIRST)
  2117.             iconID = IL_NEWS_FIRST-1;
  2118.         else
  2119.             iconID = IL_IMAGE_FIRST-1;
  2120.         iconID = iconID + IL_ICON_OFFSET;
  2121.         ic = CIconList::GetIcon(iconID);
  2122.     }
  2123.  
  2124.     return ic;
  2125. }
  2126.  
  2127. void
  2128. ImageGroupObserver(XP_Observable /*observable*/,
  2129.           XP_ObservableMsg message,
  2130.           void* /*message_data*/,
  2131.           void* closure)
  2132. {
  2133.     MWContext* theContext = static_cast<MWContext*>(closure);
  2134.     Assert_(theContext);
  2135.     if (!theContext)
  2136.         return;
  2137.         
  2138.     CBrowserContext* theBrowserContext = dynamic_cast<CBrowserContext*>(theContext->fe.newContext);
  2139.     Assert_(theContext);
  2140.     if (!theBrowserContext)
  2141.         return;
  2142.     
  2143.     switch(message)
  2144.     {
  2145.         case IL_STARTED_LOADING:
  2146.             theBrowserContext->SetImagesLoading(true);
  2147.             break;
  2148.  
  2149.         case IL_ABORTED_LOADING:
  2150.             theBrowserContext->SetImagesDelayed(true);
  2151.             break;
  2152.  
  2153.         case IL_FINISHED_LOADING:
  2154.             theBrowserContext->SetImagesLoading(false);
  2155.             break;
  2156.  
  2157.         case IL_STARTED_LOOPING:
  2158.             theBrowserContext->SetImagesLooping(true);
  2159.             break;
  2160.  
  2161.         case IL_FINISHED_LOOPING:
  2162.             theBrowserContext->SetImagesLooping(false);
  2163.             break;
  2164.  
  2165.         default:
  2166.             break;
  2167.     }
  2168. }
  2169.  
  2170. void
  2171. FE_MochaImageGroupObserver(XP_Observable /*observable*/,
  2172.           XP_ObservableMsg message,
  2173.           void *message_data,
  2174.           void */*closure*/)
  2175. {
  2176.     IL_GroupMessageData *data = (IL_GroupMessageData *)message_data;
  2177.     MWContext *theContext = (MWContext *)data->display_context;
  2178.  
  2179.     // If we are passed a NULL display context, the MWContext has been
  2180.     // destroyed.
  2181.     if (!theContext)
  2182.         return;
  2183.         
  2184.     CBrowserContext* theBrowserContext = dynamic_cast<CBrowserContext*>(theContext->fe.newContext);
  2185.     if (!theBrowserContext)
  2186.         return;
  2187.     
  2188.     switch(message)
  2189.     {
  2190.         case IL_STARTED_LOADING:
  2191.             theBrowserContext->SetMochaImagesLoading(true);
  2192.             break;
  2193.  
  2194.         case IL_ABORTED_LOADING:
  2195.             theBrowserContext->SetMochaImagesDelayed(true);
  2196.             break;
  2197.  
  2198.         case IL_FINISHED_LOADING:
  2199.             theBrowserContext->SetMochaImagesLoading(false);
  2200.             break;
  2201.  
  2202.         case IL_STARTED_LOOPING:
  2203.             theBrowserContext->SetMochaImagesLooping(true);
  2204.             break;
  2205.  
  2206.         case IL_FINISHED_LOOPING:
  2207.             theBrowserContext->SetMochaImagesLooping(false);
  2208.             break;
  2209.  
  2210.         default:
  2211.             break;
  2212.     }
  2213. }
  2214.  
  2215. #ifdef PROFILE
  2216. #pragma profile off
  2217. #endif
  2218.  
  2219.