[mapguide-commits] r5035 - in sandbox/adsk/2.2gp: Common/MapGuideCommon/MapLayer Common/MapGuideCommon/Resources Common/MapGuideCommon/Services Common/Renderers Common/Stylization Server/src/Services/Kml Server/src/Services/Mapping Server/src/Services/Rendering Server/src/Services/Tile

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Fri Jul 16 17:14:16 EDT 2010


Author: brucedechant
Date: 2010-07-16 21:14:16 +0000 (Fri, 16 Jul 2010)
New Revision: 5035

Modified:
   sandbox/adsk/2.2gp/Common/MapGuideCommon/MapLayer/Map.cpp
   sandbox/adsk/2.2gp/Common/MapGuideCommon/MapLayer/Map.h
   sandbox/adsk/2.2gp/Common/MapGuideCommon/Resources/mapguide_en.res
   sandbox/adsk/2.2gp/Common/MapGuideCommon/Services/RenderingOptions.cpp
   sandbox/adsk/2.2gp/Common/Renderers/AGGImageIO.cpp
   sandbox/adsk/2.2gp/Common/Renderers/AGGImageIO.h
   sandbox/adsk/2.2gp/Common/Renderers/AGGRenderer.cpp
   sandbox/adsk/2.2gp/Common/Renderers/AGGRenderer.h
   sandbox/adsk/2.2gp/Common/Stylization/DefaultStylizer.cpp
   sandbox/adsk/2.2gp/Common/Stylization/DefaultStylizer.h
   sandbox/adsk/2.2gp/Common/Stylization/RendererStyles.h
   sandbox/adsk/2.2gp/Server/src/Services/Kml/ServerKmlService.cpp
   sandbox/adsk/2.2gp/Server/src/Services/Mapping/MappingUtil.cpp
   sandbox/adsk/2.2gp/Server/src/Services/Mapping/MappingUtil.h
   sandbox/adsk/2.2gp/Server/src/Services/Rendering/ServerRenderingService.cpp
   sandbox/adsk/2.2gp/Server/src/Services/Tile/ServerTileService.cpp
   sandbox/adsk/2.2gp/Server/src/Services/Tile/ServerTileService.h
Log:
This submission merges the RFC60 code changes into the sandbox/adsk/2.2gp stream.


Modified: sandbox/adsk/2.2gp/Common/MapGuideCommon/MapLayer/Map.cpp
===================================================================
--- sandbox/adsk/2.2gp/Common/MapGuideCommon/MapLayer/Map.cpp	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Common/MapGuideCommon/MapLayer/Map.cpp	2010-07-16 21:14:16 UTC (rev 5035)
@@ -19,7 +19,6 @@
 #include "MdfModel.h"
 #include "SAX2Parser.h"
 #include <map>
-#include <vector>
 
 using namespace std;
 
@@ -35,7 +34,8 @@
 MgMap::MgMap()
     : MgMapBase(),
     m_inSave(false),
-    m_unpackedLayersGroups(false)
+    m_unpackedLayersGroups(false),
+    m_colorPalette(NULL)        // lazy instantiation
 {
 }
 
@@ -46,7 +46,8 @@
 MgMap::MgMap(MgSiteConnection* siteConnection)
     : MgMapBase(),
     m_inSave(false),
-    m_unpackedLayersGroups(false)
+    m_unpackedLayersGroups(false),
+    m_colorPalette(NULL)        // lazy instantiation
 {
     if (NULL == siteConnection)
     {
@@ -118,6 +119,10 @@
     m_mapDefinitionId = SAFE_ADDREF(mapDefinition);
     m_name = mapName;
 
+    // reset the colorlist from our layers (std::list dtor clears the list)
+    delete m_colorPalette;
+    m_colorPalette = NULL;  // initialize to empty (lazy as its only used for 8bit color)
+
     // generate a unique id for this map
     MgUtil::GenerateUuid(m_objectId);
 
@@ -293,7 +298,7 @@
         for(int i = 0; i < layers->GetCount(); i++, displayOrder += LAYER_ZORDER_INCR)
         {
             MapLayer* layer = (MapLayer*)layers->GetAt(i);
-            //create a runtime layer from this layer and add it to the layer collection
+            //create a runtime layer from this layerDefinition and add it to the layer collection
             //pull identity properties as a batch process after the layers are created
             Ptr<MgResourceIdentifier> layerDefId = new MgResourceIdentifier(layer->GetLayerResourceID());
             Ptr<MgLayerBase> rtLayer = new MgLayer(layerDefId, m_resourceService, false, false);
@@ -460,6 +465,10 @@
     m_name = mapName;
     MgMapBase::Create(mapSRS, mapExtent, mapName);
     m_unpackedLayersGroups = true;
+
+    // reset the colorlist from our layers (std::list dtor clears the list)
+    delete m_colorPalette;
+    m_colorPalette = NULL;  // initialize to empty (lazy as its only used for 8bit color)
 }
 
 
@@ -636,6 +645,8 @@
 //
 MgMap::~MgMap()
 {
+    // reset the colorlist from our layers (std::list dtor clears the list)
+    delete m_colorPalette;
 }
 
 
@@ -1102,3 +1113,41 @@
         }
     }
 }
+
+////////////////////////////////////////////////////////////////////////
+// RFC60 ColorPalette Accessor uses lazy instantiation as it's not used
+// for truecolor tiles.  It's used for the map colors collected from the
+// stylization of the visible layers.
+ColorStringList& MgMap::GetColorPalette()
+{
+    if (m_colorPalette == NULL)
+        m_colorPalette = new ColorStringList();
+    else
+    {
+        m_colorPalette->sort();
+        m_colorPalette->unique();
+    }
+    return *m_colorPalette;
+}
+
+////////////////////////////////////////////////////////////////////////
+// RFC60 setter adds list.
+void MgMap::AddColorsToPalette(ColorStringList& newColorPalette)
+{
+    if (NULL == m_colorPalette)
+        GetColorPalette();  // lazy instantiation
+
+    if (!newColorPalette.empty())
+    {
+        ColorStringList::iterator it = newColorPalette.begin();
+        for (; it != newColorPalette.end(); it++)
+        {
+            if (*it != L"")    // filter empty strings
+            {
+                // uppercase the colorcodes (FFABDEFF)
+                std::transform((*it).begin(), (*it).end(), (*it).begin(), towupper);
+                m_colorPalette->push_back(*it);
+            }
+        }
+    }
+}

Modified: sandbox/adsk/2.2gp/Common/MapGuideCommon/MapLayer/Map.h
===================================================================
--- sandbox/adsk/2.2gp/Common/MapGuideCommon/MapLayer/Map.h	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Common/MapGuideCommon/MapLayer/Map.h	2010-07-16 21:14:16 UTC (rev 5035)
@@ -22,22 +22,13 @@
 /// \ingroup Maps_and_Layers_Module
 /// \{
 
-/*TSW remove
 #include "Foundation.h"
 #include <vector>
 #include <list>
 #include <map>
-#include "LayerBase.h"
-#include "LayerGroup.h"
-#include "LayerCollection.h"
-#include "LayerGroupCollection.h"
-#include "MapCollection.h"
-#include "ObjectChange.h"
-#include "ChangeList.h"
-#include "ReadOnlyLayerCollection.h"
-#include "SelectionBase.h"
-*/
 
+typedef std::list<const MdfModel::MdfString> ColorStringList;
+
 class MgMap;
 class MgSiteConnection;
 template class MG_MAPGUIDE_API Ptr<MgMap>;
@@ -579,6 +570,13 @@
     virtual void OnLayerParentChanged(MgLayerBase* layer, CREFSTRING parentId);
 
     //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// RFC60 ColorPalette accessors
+    ///
+    ColorStringList& GetColorPalette();
+    void AddColorsToPalette(ColorStringList& newColorPalette);
+
+    //////////////////////////////////////////////////////////////////
     /// Bulk load identity properties
     ///
     ///
@@ -636,6 +634,7 @@
     Ptr<MgResourceService> m_resourceService;
     bool m_inSave;
     bool m_unpackedLayersGroups;
+    ColorStringList* m_colorPalette;
 };
 /// \}
 

Modified: sandbox/adsk/2.2gp/Common/MapGuideCommon/Resources/mapguide_en.res
===================================================================
--- sandbox/adsk/2.2gp/Common/MapGuideCommon/Resources/mapguide_en.res	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Common/MapGuideCommon/Resources/mapguide_en.res	2010-07-16 21:14:16 UTC (rev 5035)
@@ -291,6 +291,7 @@
 MgMissingSchema                                       = No schema specified.
 MgMissingSrs                                          = No coordinate system specified.
 MgNameNotFound                                        = The name was not found.
+MgNoDataFromRenderer                                  = No data from renderer.
 MgPropertyValuesEmpty                                 = The property values cannot be empty.
 MgReaderIdNotFound                                    = The reader ID was not found.
 MgRepositoryAlreadyOpened                             = The repository is already opened by another process (e.g. If you are running the server interactively as an application from the command line, are you also running the server as a service?).
@@ -309,6 +310,7 @@
 MgStringTooLong                                       = The string is too long.
 MgTagFieldNotFound                                    = The tag contained no fields.
 MgUnableToLockTileFile                                = Unable to lock the tile file.
+MgUnableToOpenLockFile                                = Unable to open the tile lock file.
 MgUnableToOpenTileFile                                = Unable to open the tile file.
 MgUnsupportedService                                  = The site/resource services cannot be enabled/disabled.
 MgUserAndGroupNotEmpty                                = Both the user and group are not empty.

Modified: sandbox/adsk/2.2gp/Common/MapGuideCommon/Services/RenderingOptions.cpp
===================================================================
--- sandbox/adsk/2.2gp/Common/MapGuideCommon/Services/RenderingOptions.cpp	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Common/MapGuideCommon/Services/RenderingOptions.cpp	2010-07-16 21:14:16 UTC (rev 5035)
@@ -35,7 +35,7 @@
 /// Selection color, including filling color and boundary color
 /// </param>
 MgRenderingOptions::MgRenderingOptions(CREFSTRING format, INT32 behavior, MgColor* selectionColor)
-: m_format(format),
+: m_format(MgUtil::ToUpper(format)),
   m_behavior(behavior)
 {
     m_selectionColor = SAFE_ADDREF(selectionColor);
@@ -47,7 +47,7 @@
 /// Get the image format
 /// </summary>
 /// <returns>
-/// The string value
+/// The string value (is in upper case from CTOR)
 /// </returns>
 STRING MgRenderingOptions::GetImageFormat()
 {

Modified: sandbox/adsk/2.2gp/Common/Renderers/AGGImageIO.cpp
===================================================================
--- sandbox/adsk/2.2gp/Common/Renderers/AGGImageIO.cpp	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Common/Renderers/AGGImageIO.cpp	2010-07-16 21:14:16 UTC (rev 5035)
@@ -15,6 +15,7 @@
 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
+//#define _DEBUG_PNG8
 #include "stdafx.h"
 #include "RendererStyles.h"
 #include "AGGImageIO.h"
@@ -29,9 +30,22 @@
 
 #include "GDUtils.h"
 
+#include <assert.h>
+
+#ifdef _DEBUG_PNG8
+#define myassert(COND,L,F) if (!(COND)){ printf("(%d) failed assertion in %d %s", GetCurrentThreadId(), L,F); throw new exception(); }
+#else
+#define myassert(COND,L,F) (COND)
+#endif
+
 #pragma warning(disable : 4611)
 
+enum MS_RETURN_VALUE {MS_SUCCESS, MS_FAILURE, MS_DONE};
 
+// in-memory switch to permit disabling colormapping at runtime
+// (could be in debug ifdefs but will be optimized away in release build anyway)
+static bool s_bUseColorMap = true;
+
 struct png_write_context
 {
     unsigned char* buf;
@@ -653,7 +667,220 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////
+/******************************************************************************
+ * mapgd.c 7803 2008-07-09 05:17:40Z sdlime
+ * Project:  MapServer
+ * Purpose:  GD rendering and other GD related functions.
+ * Author:   Steve Lime and the MapServer team.
+ ******************************************************************************/
+/// copied from mapserver source tree --------> mapgd.c line 3248 - 3463, UV  25.02.2009
+ // copy src to dst using dst's palette
+ // src must be a truecolor image
+ // dst must be a paletted image
+ // method is to fine tune the caching used to lookup color values in the palette:
+ //  -0 is the default method, which allocates cache memory when needed
+ //  -1 is a memory conservative method, that uses very little caching but is much slower
+ //  -2 is a memory hungry caching method (allocates 32MB on the heap) but is the fastest for large images
+ // see bug #2422 for some benchmark timings of these methods
+ //
+static int ImageCopyForcePaletteGD(gdImagePtr src, gdImagePtr dst, int method)
+{
+#ifdef _DEBUG_PNG8
+    long icfp = GetTickCount();  // for performance evaluation
+#endif
+    int x, y;
+    int w, h;
+    int c, r, g, b,color;
+    if(!src || !dst) return MS_FAILURE;
+    // input images have different sizes
+    if(gdImageSX(src) != gdImageSX(dst) || gdImageSY(src) != gdImageSY(dst)) return MS_FAILURE;
+    if(!gdImageTrueColor(src) || gdImageTrueColor(dst)) return MS_FAILURE; /* 24-bit to 8-bit */
+    w = gdImageSX(src);
+    h = gdImageSY(src);
+    if(method==0) {
+        /*default caching strategy*/
+        unsigned short ***cols=(unsigned short***)calloc(256,sizeof(unsigned short**));
+
+        /*pointer to cache, pointed by red component, indexed by green component*/
+        unsigned short **data=(unsigned short**)calloc(256*256,sizeof(unsigned short*));
+
+       for(r=0;r<256;r++) {
+        /*populate the cache*/
+        cols[r]=&(data[r*256]);
+
+        for (y = 0; (y < h); y++) {
+            for (x = 0; (x < w); x++) {
+                c = gdImageGetPixel(src, x, y);
+                r = gdTrueColorGetRed(c);
+                g = gdTrueColorGetGreen(c);
+                b = gdTrueColorGetBlue(c);
+
+                if(cols[r][g]==NULL) {
+                    /*this is the first time we see this r,g couple.
+                     *allocate bytes for the blue component*/
+                    cols[r][g]=(unsigned short*)calloc(256,sizeof(unsigned short));
+                }
+
+                if(!cols[r][g][b]) {
+                    /*this r,g,b triplet was never seen before
+                     * compute its index in the palette and cache the result
+                     */
+                    color = gdImageColorClosest(dst, r, g, b);
+                    dst->pixels[y][x] = color;
+                    /*the cache data was calloc'ed to avoid initialization
+                     * store 'index+1' so we are sure the test for cols[r][g][b]
+                     * returns true, i.e that this color was cached*/
+                    cols[r][g][b]=color+1;
+                }
+                else {
+                    /*the cache data was calloc'ed to avoid initialization
+                     * the cache contains 'index+1' so we must subtract
+                     * 1 to get the real color index*/
+                    dst->pixels[y][x] = cols[r][g][b]-1;
+                } // if
+            } // for x
+        } // for y
+       } // for r
+        for(r=0;r<256;r++)
+            for(g=0;g<256;g++)
+                if(cols[r][g]) /*only free the row if it was used*/
+                    free(cols[r][g]);
+        free(data);
+        free(cols);
+    }
+    else if(method==1) {
+        /*memory conservative method, does not allocate mem on the heap*/
+        int R[10], G[10], B[10], C[10];
+        int i, color, nCache = 0, iCache =0, maxCache=10;
+
+        for (y = 0; (y < h); y++) {
+            for (x = 0; (x < w); x++) {
+                c = gdImageGetPixel(src, x, y);
+                r =  gdTrueColorGetRed(c);
+                g = gdTrueColorGetGreen(c);
+                b = gdTrueColorGetBlue(c);
+                color = -1;
+
+                /* adding a simple cache to keep colors instead of always calling gdImageColorClosest
+               seems to reduce significantly the time passed in this function
+               spcially with large images (bug 2096)*/
+                for (i=0; i<nCache; i++)
+                {
+                    if (R[i] == r)
+                    {
+                        if (G[i] == g && B[i] == b)
+                        {
+                            color = C[i];
+                            break;
+                        }
+                    }
+                }
+
+                if (color == -1)
+                {
+                    color = gdImageColorClosest(dst, r, g, b);
+                    R[iCache] = r;
+                    G[iCache] = g;
+                    B[iCache] = b;
+                    C[iCache] = color;
+                    nCache++;
+                    if (nCache >= maxCache)
+                        nCache = maxCache;
+
+                    iCache++;
+                    if (iCache == maxCache)
+                        iCache = 0;
+                }
+
+                gdImageSetPixel(dst, x, y, color);
+            }
+        }
+    }
+    else if(method==2) {
+        /*memory hungry method, fastest for very large images*/
+
+        /*use a cache for every possible r,g,b triplet
+         * this is usually a full 32MB (when short is 2 bytes) */
+        short *cache=(short*)calloc(16777216,sizeof(short));
+
+        for (y = 0; (y < h); y++) {
+            for (x = 0; (x < w); x++) {
+                int index;
+                c = gdImageGetPixel(src, x, y);
+                index=c&0xFFFFFF; /*use r,g,b for the cache index, i.e. remove alpha*/
+                if(!cache[index]) {
+                    r =  gdTrueColorGetRed(c);
+                    g = gdTrueColorGetGreen(c);
+                    b = gdTrueColorGetBlue(c);
+                    color = gdImageColorClosest(dst, r, g, b);
+                    cache[index]=color+1;
+                    dst->pixels[y][x] = color;
+                }
+                else
+                    dst->pixels[y][x] = cache[index]-1;
+            }
+        }
+        free(cache);
+    }
+#ifdef _DEBUG_PNG8
+    printf("\n(%d) ########################### ImageCopyForcePaletteGD: Time:%6.4f (s)\n", GetCurrentThreadId(), (GetTickCount()-icfp)/1000.0);
+#endif
+
+    if(gdImageTrueColor(dst)) return MS_FAILURE; /* result is not 8-bit */
+    return MS_SUCCESS;
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////////////
+// helper function to create an empty image with a palette provided in std::list<MgColor>
+// inParam: 24bit image, filename of palette file, imagesixeX, imagesizeY
+// return: 8bit image using given palette if provided ...
+static gdImagePtr CreateGdImageWithPalette(gdImagePtr img24, RS_ColorVector* baseColorPalette, int sx, int sy)
+{
+    myassert(sx > 0 && sy > 0, __LINE__, __WFILE__);
+
+    /// allow empty default parameter
+    int ncolors = baseColorPalette? baseColorPalette->size() : 0;
+
+    // create new empty palette image
+    gdImagePtr gdPPalette = gdImageCreatePalette(sx, sy);
+    myassert(gdPPalette, __LINE__, __WFILE__);
+
+    // if the palette file contains less than 256, fill the rest with colors generated
+    // by gd - those can include the base colors
+    if (ncolors < 256)
+    {
+        gdImagePtr gdPPaletteFromImg24 = gdImageCreatePaletteFromTrueColor(img24, 1, 255-ncolors);
+        myassert(gdPPaletteFromImg24, __LINE__, __WFILE__);
+
+        // copy colors from palette into new empty gdpalette
+        for (int c = 0; c < gdPPaletteFromImg24->colorsTotal; c++)
+        {
+            gdImageColorAllocate(gdPPalette,gdPPaletteFromImg24->red[c],
+                                            gdPPaletteFromImg24->green[c],
+                                            gdPPaletteFromImg24->blue[c]);
+        }
+        gdImageDestroy(gdPPaletteFromImg24);
+    }
+#ifdef _DEBUG_PNG8
+    printf("\n(%d) ########################### CreateGdImageWithPalette colors: %d\n", GetCurrentThreadId(), ncolors);
+#endif
+
+    if (baseColorPalette)
+    {
+        // add colors from the colorpalette (duplicate color entries make the used palette less than 256)
+        RS_ColorVector::iterator it;
+        for (it = baseColorPalette->begin();it != baseColorPalette->end(); it++)
+        {
+            gdImageColorAllocate(gdPPalette, (*it).red(), (*it).green(), (*it).blue());
+        }
+    }
+
+    myassert(gdImageTrueColor(gdPPalette) == 0, __LINE__, __WFILE__);   // result is not a 8-bit paletted image
+    return gdPPalette;  // this is an empty image with the right color palette
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////
@@ -662,8 +889,7 @@
 ////////////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////
-
-
+// create an image using the other Save method and store it at filename
 bool AGGImageIO::Save(const RS_String& filename, const RS_String& format,
                  unsigned int* src, int src_width, int src_height,
                  int dst_width, int dst_height, RS_Color& bgColor)
@@ -701,9 +927,13 @@
 }
 
 
+////////////////////////////////////////////////////////////////////////////////////////
+// convert imagebuffer src into the desired format using the provided baseColorPalette for 8bit 
+// (the baseColorPalette is a default parameter NULL)
 RS_ByteData* AGGImageIO::Save(const RS_String& format,
                   unsigned int* src, int src_width, int src_height,
-                  int dst_width, int dst_height, RS_Color& bgColor)
+                  int dst_width, int dst_height, RS_Color& bgColor, 
+                  RS_ColorVector* baseColorPalette)
 {
     bool drop_alpha = bgColor.alpha() == 255;
 
@@ -750,76 +980,97 @@
         }
         else if (format == L"JPG" || format == L"GIF" || format == L"PNG8")
         {
-            gdImagePtr gdimg = gdImageCreateTrueColor(dst_width, dst_height);
+            // gdimg24 contains the 24bit image
+            gdImagePtr gdimg24 = gdImageCreateTrueColor(dst_width, dst_height);
 
-            int bgc = ConvertColor(gdimg, bgColor);
+            int bgc = ConvertColor(gdimg24, bgColor);
 
             // initialize the destination image to the bg color (temporarily turn
             // off alpha blending so the fill has the supplied alpha)
-            gdImageAlphaBlending(gdimg, 0);
-            gdImageFilledRectangle(gdimg, 0, 0, gdImageSX(gdimg)-1, gdImageSY(gdimg)-1, bgc);
+            gdImageAlphaBlending(gdimg24, 0);
+            gdImageFilledRectangle(gdimg24, 0, 0, gdImageSX(gdimg24)-1, gdImageSY(gdimg24)-1, bgc);
 
             // set any transparent color
             if (bgColor.alpha() != 255)
-                gdImageColorTransparent(gdimg, bgc);
+                gdImageColorTransparent(gdimg24, bgc);
 
+            // copy the src data into the gdImage
             unsigned int* ptr = src;
             for (int j=0; j<dst_height; j++)
             {
                 for(int i=0; i<dst_width; i++)
                 {
                     //TODO: can be optimized
-
                     unsigned int c = *ptr++;
                     int a = c >> 24;
-                    int b = (c >> 16) & 0xff;
-                    int g = (c >> 8) & 0xff;
-                    int r = c & 0xff;
-
                     // skip any fully transparent pixels so a transparent
                     // background color will show through
                     if (a != 0)
                     {
-                        int gdc = gdImageColorAllocateAlpha(gdimg, r, g, b, a);
-                        gdImageSetPixel(gdimg, i, j, gdc);
+                        int b = (c >> 16) & 0xff;  // some simple optimization ;-)
+                        int g = (c >> 8) & 0xff;
+                        int r = c & 0xff;
+
+                        int gdc = gdImageColorAllocateAlpha(gdimg24, r, g, b, a);
+                        gdImageSetPixel(gdimg24, i, j, gdc);
                     }
                 }
             }
 
-            gdImageAlphaBlending(gdimg, 1);
+            gdImageAlphaBlending(gdimg24, 1);
 
             // Make output image non-interlaced --- it's a little faster to compress that way.
-            gdImageInterlace(gdimg, 0);
+            gdImageInterlace(gdimg24, 0);
 
             // Make sure the alpha values get saved -- but only if required
             // it is faster not to save them and makes a smaller PNG
-            if (bgColor.alpha() != 255)
-                gdImageSaveAlpha(gdimg, 1);
-            else
-                gdImageSaveAlpha(gdimg, 0);
+            gdImageSaveAlpha(gdimg24, (bgColor.alpha() != 255)? 1 : 0);
 
-            //convert to 256 color paletted image for PNG8, GIF
-            if (format == L"GIF" || format == L"PNG8")
-                gdImageTrueColorToPalette(gdimg, 0, 256);
+            // convert to 256 color paletted image for PNG8, GIF
+            gdImagePtr gdImgPalette = NULL;
+            if (format == L"GIF" || format == L"PNG8") 
+            {
+                /// skip color quantization if no palette given or empty
+                if (baseColorPalette && !baseColorPalette->empty() && s_bUseColorMap) // memory based switch
+                {
+                    gdImgPalette = CreateGdImageWithPalette(gdimg24, baseColorPalette,
+                                                            gdImageSX(gdimg24), gdImageSY(gdimg24));
+                    myassert(gdImgPalette, __LINE__, __WFILE__);
 
+                    // methods are described above - we use method 1 as default????? TODO what's best???
+                    myassert(ImageCopyForcePaletteGD(gdimg24, gdImgPalette, 1) == MS_SUCCESS, __LINE__, __WFILE__);
+
+                    // forced palette GD image now in gdimgPalette
+                }
+                else
+                {
+                    gdImageTrueColorToPalette(gdimg24, 0, 256);  // in place conversion
+                    gdImgPalette = gdimg24;
+                }
+            }
+
             //get an in-memory image stream
             int size = 0;
             unsigned char* data = NULL;
 
             if (format == L"GIF")       // MgImageFormats::Gif
-                data = (unsigned char*)gdImageGifPtr(gdimg, &size);
+                data = (unsigned char*)gdImageGifPtr(gdImgPalette, &size);
+            else if (format == L"PNG8") // MgImageFormats::Png8
+                data = (unsigned char*)gdImagePngPtr(gdImgPalette, &size);
             else if (format == L"JPG")  // MgImageFormats::Jpeg
-                data = (unsigned char*)gdImageJpegPtr(gdimg, &size, 75);
-            else if (format == L"PNG8")   // MgImageFormats::Png8
-                data = (unsigned char*)gdImagePngPtr(gdimg, &size);
+                data = (unsigned char*)gdImageJpegPtr(gdimg24, &size, 75);
 
             std::auto_ptr<RS_ByteData> byteData;
             byteData.reset((NULL == data)? NULL : new RS_ByteData(data, size));
 
             gdFree(data);
 
-            //if we allocated a temporary image to stretch-blit, destroy it
-            gdImageDestroy(gdimg);
+            if (gdimg24 == gdImgPalette)
+                gdimg24 = NULL;     // reset pointer so destructor is not called twice -> exception!!!
+            else    //if we allocated a temporary image to stretch-blit, destroy it
+                gdImageDestroy(gdimg24);
+            //if we allocated a paletted image, destroy it (very likely that is)
+            gdImageDestroy(gdImgPalette);
 
             return byteData.release();
         }
@@ -830,6 +1081,8 @@
     return NULL;
 }
 
+//---------------------------------------------------------------------------
+
 //TODO: This routine should be rewritten to use agg to blend PNGs more accurately
 void AGGImageIO::Combine(const RS_String& src1, const RS_String& src2, const RS_String& dst)
 {

Modified: sandbox/adsk/2.2gp/Common/Renderers/AGGImageIO.h
===================================================================
--- sandbox/adsk/2.2gp/Common/Renderers/AGGImageIO.h	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Common/Renderers/AGGImageIO.h	2010-07-16 21:14:16 UTC (rev 5035)
@@ -26,7 +26,8 @@
 
     static RS_ByteData* Save(const RS_String& format,
                       unsigned int* src, int src_width, int src_height,
-                      int dst_width, int dst_height, RS_Color& bgColor);
+                      int dst_width, int dst_height, RS_Color& bgColor,
+                      RS_ColorVector* baseColorPalette = NULL);
 
     static void Combine(const RS_String& src1, const RS_String& src2, const RS_String& dst);
 

Modified: sandbox/adsk/2.2gp/Common/Renderers/AGGRenderer.cpp
===================================================================
--- sandbox/adsk/2.2gp/Common/Renderers/AGGRenderer.cpp	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Common/Renderers/AGGRenderer.cpp	2010-07-16 21:14:16 UTC (rev 5035)
@@ -96,6 +96,7 @@
 bool AGGRenderer::s_bGeneralizeData = false;
 
 
+//////////////////////////////////////////////////////////////////////////////
 // constructor that allows a backbuffer
 AGGRenderer::AGGRenderer(int width,
                          int height,
@@ -138,6 +139,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 //default constructor
 AGGRenderer::AGGRenderer(int width,
                          int height,
@@ -192,6 +194,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 AGGRenderer::~AGGRenderer()
 {
     delete m_context;
@@ -203,6 +206,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::UpdateBackBuffer(int width, int height, unsigned int* backbuffer)
 {
     if (m_bownbuffer)
@@ -219,6 +223,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 unsigned int* AGGRenderer::GetBackBuffer(int &width, int& height)
 {
     width = m_width;
@@ -227,30 +232,42 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
+// This one writes into a file not returning a bytestream using
+// default parameters for the width and height.
 void AGGRenderer::Save(const RS_String& filename, const RS_String& format)
 {
     Save(filename, format, m_width, m_height);
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
+// This one writes into a file not returning a bytestream.
 void AGGRenderer::Save(const RS_String& filename, const RS_String& format, int width, int height)
 {
     AGGImageIO::Save(filename, format, m_rows, m_width, m_height, width, height, m_bgcolor);
 }
 
 
-RS_ByteData* AGGRenderer::Save(const RS_String& format, int width, int height)
+//////////////////////////////////////////////////////////////////////////////
+// Return the rendered image passed in via the imagebuffer (m_rows) as
+// a bytestream in the given image format using the provided colorPalette
+// if given.
+RS_ByteData* AGGRenderer::Save(const RS_String& format, int width, int height,
+                               RS_ColorVector* baseColorPalette)
 {
-    return AGGImageIO::Save(format, m_rows, m_width, m_height, width, height, m_bgcolor);
+    return AGGImageIO::Save(format, m_rows, m_width, m_height, width, height, m_bgcolor, baseColorPalette);
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::Combine(const RS_String& fileIn1, const RS_String& fileIn2, const RS_String& fileOut)
 {
     AGGImageIO::Combine(fileIn1, fileIn2, fileOut);
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::StartMap(RS_MapUIInfo* mapInfo,
                            RS_Bounds&    extents,
                            double        mapScale,
@@ -308,6 +325,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::EndMap()
 {
     // turn off selection mode so the labels draw normal
@@ -321,6 +339,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::StartLayer(RS_LayerUIInfo*      legendInfo,
                              RS_FeatureClassInfo* classInfo)
 {
@@ -330,6 +349,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::EndLayer()
 {
     // clear the layer/feature info
@@ -338,6 +358,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::StartFeature(RS_FeatureReader* /*feature*/,
                                bool              /*initialPass*/,
                                const RS_String*  /*tooltip*/,
@@ -350,6 +371,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::ProcessPolygon(LineBuffer* lb, RS_FillStyle& fill)
 {
     _ASSERT(NULL != lb);
@@ -494,6 +516,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::ProcessPolyline(LineBuffer* lb, RS_LineStroke& lsym)
 {
     _ASSERT(NULL != lb);
@@ -603,6 +626,7 @@
     printf("      width = %6.4f height = %6.4f\n", ext.width(), ext.height());
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::ProcessRaster(unsigned char* data,
                                 int length,
                                 RS_ImageFormat format,
@@ -633,6 +657,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::ProcessMarker(LineBuffer* srclb, RS_MarkerDef& mdef, bool allowOverpost, RS_Bounds* bounds)
 {
     RS_MarkerDef use_mdef = mdef;
@@ -658,6 +683,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::ProcessOneMarker(double x, double y, RS_MarkerDef& mdef, bool allowOverpost, RS_Bounds* bounds)
 {
     RS_InputStream* symbol = NULL;
@@ -1038,6 +1064,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::ProcessLabelGroup(RS_LabelInfo*    labels,
                                     int              nlabels,
                                     const RS_String& text,
@@ -1055,66 +1082,77 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::SetSymbolManager(RS_SymbolManager* manager)
 {
     m_symbolManager = manager;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 RS_MapUIInfo* AGGRenderer::GetMapInfo()
 {
     return m_mapInfo;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 RS_LayerUIInfo* AGGRenderer::GetLayerInfo()
 {
     return m_layerInfo;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 RS_FeatureClassInfo* AGGRenderer::GetFeatureClassInfo()
 {
     return m_fcInfo;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 double AGGRenderer::GetMapScale()
 {
     return m_mapScale;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 double AGGRenderer::GetDrawingScale()
 {
     return m_drawingScale;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 RS_Bounds& AGGRenderer::GetBounds()
 {
     return m_extents;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 double AGGRenderer::GetDpi()
 {
     return m_dpi;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 double AGGRenderer::GetMetersPerUnit()
 {
     return m_metersPerUnit;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 bool AGGRenderer::RequiresClipping()
 {
     return m_bRequiresClipping;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 bool AGGRenderer::RequiresLabelClipping()
 {
     // always the same value as RequiresClipping
@@ -1122,6 +1160,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 bool AGGRenderer::SupportsZ()
 {
     // Z values in feature geometry are ignored
@@ -1129,6 +1168,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 bool AGGRenderer::SupportsTooltips()
 {
     // set to false to disable processing of tooltips
@@ -1136,6 +1176,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 bool AGGRenderer::SupportsHyperlinks()
 {
     // set to false to disable processing of hyperlinks
@@ -1143,12 +1184,14 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 bool AGGRenderer::UseLocalOverposting()
 {
     return m_bLocalOverposting;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // WARNING: caller responsible for deleting resulting line buffer
 LineBuffer* AGGRenderer::ApplyLineStyle(LineBuffer* srcLB, wchar_t* lineStyle, double lineWidthPixels, double drawingScale, double dpi)
 {
@@ -1338,10 +1381,9 @@
 }
 
 
-//-----------------------------------------------------------------------------
+//////////////////////////////////////////////////////////////////////////////
 // scale an input number in meters to a mapping
 // space number given a device or mapping space unit.
-//-----------------------------------------------------------------------------
 double AGGRenderer::_MeterToMapSize(RS_Units unit, double number)
 {
     double scale_factor;
@@ -1355,12 +1397,14 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::SetRenderSelectionMode(bool mode)
 {
     SetRenderSelectionMode(mode, 0x0000FF00);
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::SetRenderSelectionMode(bool mode, int rgba)
 {
     SE_Renderer::SetRenderSelectionMode(mode, rgba);
@@ -1382,6 +1426,7 @@
 //////////////////////////////////////////////////////////////////////////////
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::DrawString(const RS_String& s,
                              double           x,
                              double           y,
@@ -1398,6 +1443,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::DrawString(agg_context*     cxt,
                              const RS_String& s,
                              double           x,
@@ -1693,6 +1739,9 @@
 // SE_Renderer implementation
 /////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::SetPolyClip(LineBuffer* polygon, double bufferWidth)
 {
     c()->bPolyClip = false;
@@ -1801,6 +1850,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // Called when applying a line style on a feature geometry.  Line styles can
 // only be applied to linestring and polygon feature geometry types.
 void AGGRenderer::ProcessLine(SE_ApplyContext* ctx, SE_RenderLineStyle* style)
@@ -1833,6 +1883,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // Called when applying an area style on a feature geometry.  Area styles can
 // can only be applied to polygon feature geometry types.
 void AGGRenderer::ProcessArea(SE_ApplyContext* ctx, SE_RenderAreaStyle* style)
@@ -1884,6 +1935,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::_TransferPoints(agg_context* c, LineBuffer* srcLB, const SE_Matrix* xform, unsigned int* pathids, bool isPolygon)
 {
     if (s_bClampPoints)
@@ -1989,6 +2041,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::_TransferPointsClamped(agg_context* c, LineBuffer* srcLB, const SE_Matrix* xform, unsigned int* pathids, bool isPolygon)
 {
     c->ps.remove_all();
@@ -2133,12 +2186,14 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::DrawScreenPolyline(LineBuffer* srclb, const SE_Matrix* xform, const SE_LineStroke& lineStroke)
 {
     DrawScreenPolyline(c(), srclb, xform, lineStroke);
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // copied from WritePolylines, except it doesn't do to screen transform - we should refactor
 void AGGRenderer::DrawScreenPolyline(agg_context* c, LineBuffer* srclb, const SE_Matrix* xform, const SE_LineStroke& lineStroke)
 {
@@ -2213,12 +2268,14 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::DrawScreenPolygon(LineBuffer* polygon, const SE_Matrix* xform, unsigned int color)
 {
     DrawScreenPolygon(c(), polygon, xform, color);
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::DrawScreenPolygon(agg_context* c, LineBuffer* polygon, const SE_Matrix* xform, unsigned int color)
 {
     if ((color & 0xFF000000) == 0)
@@ -2247,18 +2304,21 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 bool AGGRenderer::YPointsUp()
 {
     return true;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::GetWorldToScreenTransform(SE_Matrix& xform)
 {
     xform = m_xform;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::SetWorldToScreenTransform(SE_Matrix& xform)
 {
     m_xform = xform;
@@ -2266,18 +2326,21 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::WorldToScreenPoint(double& inx, double& iny, double& ox, double& oy)
 {
     m_xform.transform(inx, iny, ox, oy);
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::ScreenToWorldPoint(double& inx, double& iny, double& ox, double& oy)
 {
     m_ixform.transform(inx, iny, ox, oy);
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // returns number of pixels per millimeter device
 double AGGRenderer::GetScreenUnitsPerMillimeterDevice()
 {
@@ -2285,6 +2348,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // returns number of pixels per millimeter world
 double AGGRenderer::GetScreenUnitsPerMillimeterWorld()
 {
@@ -2292,6 +2356,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // screen units are pixels
 double AGGRenderer::GetScreenUnitsPerPixel()
 {
@@ -2299,18 +2364,21 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 RS_FontEngine* AGGRenderer::GetRSFontEngine()
 {
     return this;
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::AddExclusionRegion(RS_F_Point* fpts, int npts)
 {
     m_labeler->AddExclusionRegion(fpts, npts);
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // labeling - this is the entry API for adding SE labels
 // to the label mananger
 void AGGRenderer::ProcessSELabelGroup(SE_LabelInfo*   labels,
@@ -2328,6 +2396,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::DrawScreenRaster(unsigned char* data, int length,
                                    RS_ImageFormat format, int native_width, int native_height,
                                    double x, double y, double w, double h, double angledeg)
@@ -2336,6 +2405,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::DrawScreenRaster(agg_context* cxt, unsigned char* data, int length,
                                    RS_ImageFormat format, int native_width, int native_height,
                                    double x, double y, double w, double h, double angledeg)
@@ -2421,6 +2491,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::DrawScreenRasterTransform(agg_context* cxt, unsigned char* data, int length,
                                             RS_ImageFormat format, int native_width, int native_height,
                                             double x, double y, double w, double h,
@@ -2479,6 +2550,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // Renders the mesh rectangle defined by the point mappings at the four supplied mesh indices
 void AGGRenderer::RenderTransformMeshRectangle(mg_rendering_buffer& src, agg_context* cxt,
                                                RS_ImageFormat format, TransformMesh* transformMesh,
@@ -2502,6 +2574,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // Renders the triangle in the source image defined by the three source points into
 // the triangle in the supplied context defined by the three destination points.
 void AGGRenderer::RenderTransformedTriangle(mg_rendering_buffer& src, agg_context* cxt, RS_ImageFormat format,
@@ -2530,6 +2603,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // Renders the source image to the destination context, using the specified
 // affine transformation matrix.
 void AGGRenderer::RenderWithTransform(mg_rendering_buffer& src, agg_context* cxt,
@@ -2603,6 +2677,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::DrawScreenText(const RS_TextMetrics& tm, RS_TextDef& tdef, double insx, double insy,
                                  RS_F_Point* path, int npts, double param_position)
 {
@@ -2639,6 +2714,7 @@
 //////////////////////////////////////////////////////////////
 
 
+//////////////////////////////////////////////////////////////////////////////
 // Inserts the contents of a given DWF input stream into the current
 // output W2D.  The given coord sys transformation is applied and geometry
 // will be clipped to the RS_Bounds context of the DWFRenderer.
@@ -2764,6 +2840,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::AddW2DContent(RS_InputStream* in, CSysTransformer* xformer, const RS_String& w2dfilter)
 {
     WT_Result result;
@@ -2805,6 +2882,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::SetActions(WT_File& file)
 {
     file.set_stream_open_action (agr_open);
@@ -2886,6 +2964,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // Given an array of points in W2D logical coordinates, this function:
 // 1. Transforms W2D logical coords into their model space using the
 //    W2D file's units structure
@@ -3009,6 +3088,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // This function scales a W2D space related value from source W2D space
 // to destination.  Since the source W2D file can fit into a small piece
 // of the destination DWF or be much larger, we need to take that scaling
@@ -3040,6 +3120,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void AGGRenderer::UpdateSymbolTrans(WT_File& /*file*/, WT_Viewport& viewport)
 {
     _ASSERT(m_xformer);

Modified: sandbox/adsk/2.2gp/Common/Renderers/AGGRenderer.h
===================================================================
--- sandbox/adsk/2.2gp/Common/Renderers/AGGRenderer.h	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Common/Renderers/AGGRenderer.h	2010-07-16 21:14:16 UTC (rev 5035)
@@ -151,7 +151,8 @@
     //
     RENDERERS_API void Save(const RS_String& filename, const RS_String& format);
     RENDERERS_API void Save(const RS_String& filename, const RS_String& format, int width, int height);
-    RENDERERS_API RS_ByteData* Save(const RS_String& format, int width, int height);
+    RENDERERS_API RS_ByteData* Save(const RS_String& format, int width, int height,
+                                    RS_ColorVector* baseColorPalette = NULL);
 
     RENDERERS_API void Combine(const RS_String& fileIn1, const RS_String& fileIn2, const RS_String& fileOut);
     RENDERERS_API void SetWorldToScreenTransform(SE_Matrix& xform);

Modified: sandbox/adsk/2.2gp/Common/Stylization/DefaultStylizer.cpp
===================================================================
--- sandbox/adsk/2.2gp/Common/Stylization/DefaultStylizer.cpp	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Common/Stylization/DefaultStylizer.cpp	2010-07-16 21:14:16 UTC (rev 5035)
@@ -30,13 +30,16 @@
 #include "ExpressionHelper.h"
 
 
+//////////////////////////////////////////////////////////////////////////////
 DefaultStylizer::DefaultStylizer(SE_SymbolManager* sman)
 {
     m_pRasterAdapter = NULL;
+    m_symbolmanager = sman;
     m_styleEngine = new StylizationEngine(sman, &m_lbPool);
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 DefaultStylizer::~DefaultStylizer()
 {
     // free geom adapters -- not strictly needed here but just
@@ -47,6 +50,14 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
+SE_SymbolManager* DefaultStylizer::GetSymbolManager()
+{
+    return m_symbolmanager;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
 void DefaultStylizer::StylizeVectorLayer(MdfModel::VectorLayerDefinition* layer,
                                          Renderer*                        renderer,
                                          RS_FeatureReader*                features,
@@ -218,6 +229,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 int DefaultStylizer::StylizeVLHelper(MdfModel::VectorLayerDefinition* layer,
                                      MdfModel::VectorScaleRange*      scaleRange,
                                      Renderer*                        renderer,
@@ -348,6 +360,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void DefaultStylizer::StylizeGridLayer(MdfModel::GridLayerDefinition* layer,
                                        Renderer*                      renderer,
                                        RS_FeatureReader*              features,
@@ -411,6 +424,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void DefaultStylizer::StylizeDrawingLayer(MdfModel::DrawingLayerDefinition* layer,
                                           Renderer*                         renderer,
                                           RS_InputStream*                   dwfin,
@@ -430,6 +444,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 // WARNING: given pointer to the new stylizer will be destroyed
 // by the stylizer (in its destructor)
 void DefaultStylizer::SetGeometryAdapter(FdoGeometryType type, GeometryAdapter* stylizer)
@@ -443,6 +458,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 GeometryAdapter* DefaultStylizer::FindGeomAdapter(int geomType)
 {
     GeometryAdapter* adapter = m_hGeomStylizers[geomType];
@@ -492,6 +508,7 @@
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 void DefaultStylizer::ClearAdapters()
 {
     std::map<int, GeometryAdapter*>::iterator sgiter = m_hGeomStylizers.begin();

Modified: sandbox/adsk/2.2gp/Common/Stylization/DefaultStylizer.h
===================================================================
--- sandbox/adsk/2.2gp/Common/Stylization/DefaultStylizer.h	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Common/Stylization/DefaultStylizer.h	2010-07-16 21:14:16 UTC (rev 5035)
@@ -25,16 +25,18 @@
 class StylizationEngine;
 class SE_SymbolManager;
 
-//-----------------------------------------------------------------------------
+//////////////////////////////////////////////////////////////////////////////
 // Stylizer used for all types of layers which do not have special
 // Stylizer implementation, which is currently all of them.
-//-----------------------------------------------------------------------------
+//////////////////////////////////////////////////////////////////////////////
 class DefaultStylizer : public Stylizer
 {
 public:
     STYLIZATION_API DefaultStylizer(SE_SymbolManager* sman);
     STYLIZATION_API virtual ~DefaultStylizer();
 
+    STYLIZATION_API SE_SymbolManager* GetSymbolManager();
+
     STYLIZATION_API virtual void StylizeVectorLayer(MdfModel::VectorLayerDefinition* layer,
                                                     Renderer*                        renderer,
                                                     RS_FeatureReader*                features,
@@ -80,6 +82,9 @@
     //composite stylizer
     StylizationEngine* m_styleEngine;
 
+    // keep a handle on the symbolmanager
+    SE_SymbolManager* m_symbolmanager;
+
     SE_BufferPool m_lbPool;
 };
 

Modified: sandbox/adsk/2.2gp/Common/Stylization/RendererStyles.h
===================================================================
--- sandbox/adsk/2.2gp/Common/Stylization/RendererStyles.h	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Common/Stylization/RendererStyles.h	2010-07-16 21:14:16 UTC (rev 5035)
@@ -164,6 +164,7 @@
     RS_OEM               = 255
 };
 
+
 //////////////////////////////////////////////////////////////////////////////
 class RS_Color
 {
@@ -235,6 +236,11 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
+/// RFC60 list of colors used for color quantization
+typedef std::vector<RS_Color> RS_ColorVector;
+
+
+//////////////////////////////////////////////////////////////////////////////
 class RS_LineStroke
 {
 public:

Modified: sandbox/adsk/2.2gp/Server/src/Services/Kml/ServerKmlService.cpp
===================================================================
--- sandbox/adsk/2.2gp/Server/src/Services/Kml/ServerKmlService.cpp	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Server/src/Services/Kml/ServerKmlService.cpp	2010-07-16 21:14:16 UTC (rev 5035)
@@ -15,6 +15,7 @@
 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
+#include "RendererStyles.h"
 #include "MapGuideCommon.h"
 #include "ServerKmlService.h"
 #include "Services/KmlDefs.h"

Modified: sandbox/adsk/2.2gp/Server/src/Services/Mapping/MappingUtil.cpp
===================================================================
--- sandbox/adsk/2.2gp/Server/src/Services/Mapping/MappingUtil.cpp	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Server/src/Services/Mapping/MappingUtil.cpp	2010-07-16 21:14:16 UTC (rev 5035)
@@ -17,19 +17,23 @@
 
 #include "MappingUtil.h"
 
-#include "SAX2Parser.h"
+#include "AGGRenderer.h"
 #include "Bounds.h"
+#include "DefaultStylizer.h"
+#include "Fdo.h"
 #include "Renderer.h"
-#include "AGGRenderer.h"
+#include "SAX2Parser.h"
+#include "SEMgSymbolManager.h"
+#include "SE_StyleVisitor.h"
+#include "SLDSymbols.h"
+#include "StylizationUtil.h"
 #include "Stylizer.h"
 #include "SymbolVisitor.h"
-#include "SLDSymbols.h"
-#include "SE_StyleVisitor.h"
-#include "SEMgSymbolManager.h"
+#include "SymbolDefinition.h"
 #include "TransformCache.h"
-#include "StylizationUtil.h"
-#include "Fdo.h"
 
+#include <algorithm>
+
 //For logging
 #include "ServerManager.h"
 #include "LogManager.h"
@@ -42,6 +46,7 @@
 #endif
 
 
+///////////////////////////////////////////////////////////////////////////////
 MdfModel::MapDefinition* MgMappingUtil::GetMapDefinition(MgResourceService* svcResource, MgResourceIdentifier* resId)
 {
     //get and parse the mapdef
@@ -70,6 +75,7 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 RSMgFeatureReader* MgMappingUtil::ExecuteFeatureQuery(MgFeatureService* svcFeature,
                                                       RS_Bounds& extent,
                                                       MdfModel::VectorLayerDefinition* vl,
@@ -229,6 +235,7 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 RSMgFeatureReader* MgMappingUtil::ExecuteRasterQuery(MgFeatureService* svcFeature,
                                                      RS_Bounds& extent,
                                                      MdfModel::GridLayerDefinition* gl,
@@ -340,6 +347,9 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// This is called by the MgServerRenderingService::RenderMapInternal to
+// render the layers.
 void MgMappingUtil::StylizeLayers(MgResourceService* svcResource,
                                   MgFeatureService* svcFeature,
                                   MgDrawingService* svcDrawing,
@@ -353,7 +363,8 @@
                                   bool expandExtents,
                                   bool checkRefreshFlag,
                                   double scale,
-                                  bool selection)
+                                  bool selection,
+                                  bool extractColors)
 {
     #ifdef _DEBUG
     long dwStart = GetTickCount();
@@ -365,7 +376,7 @@
     TransformCacheMap transformCache;
 
     Ptr<MgStringCollection> layerIds = new MgStringCollection();
-    // Get the layers' resource content in a single request
+    // Get the layers' resource content in a single request by adding them to a collection
     for (int i = layers->GetCount()-1; i >= 0; i--)
     {
         Ptr<MgLayerBase> mapLayer = layers->GetItem(i);
@@ -391,6 +402,8 @@
         Ptr<MgResourceIdentifier> mapLayerId = mapLayer->GetLayerDefinition();
         layerIds->Add(mapLayerId->ToString());
     }
+
+    // request the collection from resource service and add ResourceContent to the individual layers
     if(layerIds->GetCount() != 0)
     {
         Ptr<MgStringCollection> layerContents = svcResource->GetResourceContents(layerIds, NULL);
@@ -409,6 +422,7 @@
         }
     }
 
+    // cycle over the layers and do stylization
     for (int i = layers->GetCount()-1; i >= 0; i--)
     {
         auto_ptr<MdfModel::LayerDefinition> ldf;
@@ -425,7 +439,7 @@
 
         MG_SERVER_MAPPING_SERVICE_TRY()
 
-            //get layer definition
+            // get layer definition using SAX XML Parser
             ldf.reset(MgLayerBase::GetLayerDefinition(mapLayer->GetLayerResourceContent()));
 
             Ptr<MgLayerGroup> group = mapLayer->GetGroup();
@@ -459,7 +473,7 @@
             MdfModel::DrawingLayerDefinition* dl = dynamic_cast<MdfModel::DrawingLayerDefinition*>(ldf.get());
             MdfModel::GridLayerDefinition* gl = dynamic_cast<MdfModel::GridLayerDefinition*>(ldf.get());
 
-            if (vl)
+            if (vl) //############################################################################ vector layer
             {
                 #ifdef _DEBUG
                 long dwLayerStart = GetTickCount();
@@ -546,6 +560,7 @@
 
                     // create the reader we'll use
                     rsReader = ExecuteFeatureQuery(svcFeature, extent, vl, overrideFilter.c_str(), dstCs, layerCs, item);
+                    // create an automatic FdoPtr around the reader
                     FdoPtr<FdoIFeatureReader> fdoReader = (NULL == rsReader) ? NULL : rsReader->GetInternalReader();
 
                     #ifdef _DEBUG
@@ -558,9 +573,21 @@
                         dr->StartLayer(&layerInfo, &fcinfo);
                         ds->StylizeVectorLayer(vl, dr, rsReader, xformer, scale, NULL, NULL);
                         dr->EndLayer();
+
+                        // color extraction for RFC60 only when needed
+                        if (extractColors)
+                        {
+                            #ifdef _DEBUG
+                            printf("  StylizeLayers() //ExtractColors// -Vector- Name:%S  Time:%6.4f (s)\n\n", (mapLayer->GetName()).c_str(), (GetTickCount()-dwLayerStart)/1000.0);
+                            #endif
+                            ExtractColors(map, scaleRange, ds);
+                            #ifdef _DEBUG
+                            printf("  StylizeLayers() ##ExtractColors## -Vector- Name:%S  Time:%6.4f (s)\n\n", (mapLayer->GetName()).c_str(), (GetTickCount()-dwLayerStart)/1000.0);
+                            #endif
+                        }
                     }
                 }
-                else
+                else  // not scaleRange
                 {
                     #ifdef _DEBUG
                     printf("  StylizeLayers() **NOT Stylizing - NO SCALE RANGE** Name:%S\n", (mapLayer->GetName()).c_str());
@@ -571,7 +598,7 @@
                 printf("  StylizeLayers() **LAYEREND** -Vector- Name:%S  Time:%6.4f (s)\n\n", (mapLayer->GetName()).c_str(), (GetTickCount()-dwLayerStart)/1000.0);
                 #endif
             }
-            else if (gl)
+            else if (gl) //############################################################################ grid layer
             {
                 // TODO: FDO RFP - Make FdoPtr's reference counter thread-safe.
                 static ACE_Recursive_Thread_Mutex sg_fdoRfpMutex;
@@ -717,7 +744,7 @@
                 printf("  StylizeLayers() **LAYEREND** -Grid- Name:%S  Time:%6.4f (s)\n\n", (mapLayer->GetName()).c_str(), (GetTickCount()-dwLayerStart)/1000.0);
                 #endif
             }
-            else if (dl) //drawing layer
+            else if (dl) //############################################################################ drawing layer
             {
                 #ifdef _DEBUG
                 long dwLayerStart = GetTickCount();
@@ -779,7 +806,7 @@
                 #ifdef _DEBUG
                 printf("  StylizeLayers() **LAYEREND** -Drawing- Name:%S  Time = %6.4f (s)\n\n", (mapLayer->GetName()).c_str(), (GetTickCount()-dwLayerStart)/1000.0);
                 #endif
-            }
+            } // end layer switch
 
         MG_SERVER_MAPPING_SERVICE_CATCH(L"MgMappingUtil.StylizeLayers");
 
@@ -807,7 +834,7 @@
             STRING stackTrace = exception->GetStackTrace(locale);
             MG_LOG_EXCEPTION_ENTRY(message.c_str(), stackTrace.c_str());
 
-#ifdef _DEBUG
+#if defined(_DEBUG) || defined(_DEBUG_PNG8)
             STRING details = mgException->GetDetails(locale);
 
             wstring err = L"\n %t Error during stylization of layer ";
@@ -818,8 +845,10 @@
             err += L"\n";
             ACE_DEBUG( (LM_DEBUG, err.c_str()) );
 #endif
-        }
-    }
+            // TODO could throw here depending on a serverconfig setting (RFC64)
+//          throw exception;
+        } // if exception
+    } // for all layers
 
     #ifdef _DEBUG
     printf("StylizeLayers() **MAPDONE** Layers:%d  Total Time:%6.4f (s)\n\n", layers->GetCount(), (GetTickCount()-dwStart)/1000.0);
@@ -829,6 +858,7 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 // When rendering a tile, we need to compute the extent used to determine
 // which features to render into it.  Features in adjacent tiles, but not
 // in the current tile, will potentially draw in this tile due to their
@@ -1083,6 +1113,7 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 // draws a given feature type style into an image
 MgByteReader* MgMappingUtil::DrawFTS(MgResourceService* svcResource,
                                      MdfModel::FeatureTypeStyle* fts,
@@ -1125,6 +1156,7 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 // transforms a given extent and returns the new extent in the new cs
 MgEnvelope* MgMappingUtil::TransformExtent(MgEnvelope* extent, MgCoordinateSystemTransform* xform)
 {
@@ -1135,6 +1167,7 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 // returns an MgPolygon from a given envelope
 MgPolygon* MgMappingUtil::GetPolygonFromEnvelope(MgEnvelope* env)
 {
@@ -1155,6 +1188,7 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 void MgMappingUtilExceptionTrap(FdoException* except, int line, wchar_t* file)
 {
     MG_TRY()
@@ -1185,7 +1219,295 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 void MgMappingUtil::InitializeStylizerCallback()
 {
     SetStylizerExceptionCallback(&MgMappingUtilExceptionTrap);
 }
+
+
+///////////////////////////////////////////////////////////////////////////////
+// PURPOSE: Accessor method for the base colors defined in this Layer and
+//          scaleRange.  Used for RFC60.
+// RETURNS: A pointer to the list of colors of the collected colors (maybe
+//          empty but not null)
+///////////////////////////////////////////////////////////////////////////////
+void MgMappingUtil::GetUsedColorsFromScaleRange(ColorStringList& usedColorList,
+                                                MdfModel::VectorScaleRange* scaleRange,
+                                                SE_SymbolManager* sman)
+{
+    // compute new color list by iterating through the featuretypecollection
+    FeatureTypeStyleCollection* pftsColl = scaleRange->GetFeatureTypeStyles();
+    int ftsccount = pftsColl->GetCount();
+    for (int j=0; j<ftsccount; ++j)
+    {
+        FeatureTypeStyle* pfts = pftsColl->GetAt(j);
+
+        // iterate through the rulecollection
+        RuleCollection* ruleColl = pfts->GetRules();
+        int rccount = ruleColl->GetCount();
+        for (int k=0; k<rccount; ++k)
+        {
+            Rule* rule = ruleColl->GetAt(k);
+
+            // get the label which will be the key in the color map
+            Label* label = rule->GetLabel();
+            if (label)
+            {
+                // add colors of txtsymbols
+                TextSymbol* txtsym = label->GetSymbol();
+                if (txtsym)
+                {
+                    // create copies of all strings so we can safely delete the resulting list later
+                    usedColorList.push_back(txtsym->GetForegroundColor().substr());
+                    usedColorList.push_back(txtsym->GetBackgroundColor().substr());
+                }
+            }
+
+            // Do the casting to access the relevant members.  This is bad style
+            // (instead of using the visitor pattern of the MdfModel) but it keeps
+            // it nice and compact and documents the structure better...
+            AreaRule* paRule = dynamic_cast<AreaRule*>(rule);
+            LineRule* plRule = dynamic_cast<LineRule*>(rule);
+            PointRule* ppRule = dynamic_cast<PointRule*>(rule);
+            CompositeRule* pcRule = dynamic_cast<CompositeRule*>(rule);  // used for new stylization
+
+            // AreaRule symbolization...
+            if (paRule != NULL)
+            {
+                AreaSymbolization2D* pasym = paRule->GetSymbolization();
+                if (pasym && pasym->GetFill() != NULL)
+                {
+                    // create copies of all strings so we can safely delete the resulting list later
+                    usedColorList.push_back(pasym->GetFill()->GetForegroundColor().substr());
+                    usedColorList.push_back(pasym->GetFill()->GetBackgroundColor().substr());
+                }
+                if (pasym && pasym->GetEdge() != NULL)
+                    usedColorList.push_back(pasym->GetEdge()->GetColor().substr());
+            }
+
+            // LineRule Symbolization...
+            if (plRule != NULL)
+            {
+                LineSymbolizationCollection* plsymcol = plRule->GetSymbolizations();
+
+                // iterate through the linesymbolizations
+                int lsccount = plsymcol->GetCount();
+                for (int l=0; l < lsccount; l++)
+                {
+                    LineSymbolization2D* plsym = plsymcol->GetAt(l);
+                    if (plsym && plsym->GetStroke() != NULL)
+                        usedColorList.push_back(plsym->GetStroke()->GetColor().substr());
+                }
+            }
+
+            // PointRule Symbolization...
+            if (ppRule != NULL)
+            {
+                PointSymbolization2D* ppsym = ppRule->GetSymbolization();
+                if (ppsym)
+                {
+                    Symbol* sym = ppsym->GetSymbol();
+                    MdfModel::BlockSymbol* blockSymbol = dynamic_cast<MdfModel::BlockSymbol*>(sym);
+                    MdfModel::FontSymbol* fontSymbol = dynamic_cast<MdfModel::FontSymbol*>(sym);
+                    MdfModel::MarkSymbol* markSymbol = dynamic_cast<MdfModel::MarkSymbol*>(sym);
+                    MdfModel::TextSymbol* textSymbol = dynamic_cast<MdfModel::TextSymbol*>(sym);
+                    MdfModel::W2DSymbol* w2dSymbol = dynamic_cast<MdfModel::W2DSymbol*>(sym);
+                    if (blockSymbol != NULL)
+                    {
+                        usedColorList.push_back(blockSymbol->GetBlockColor().substr());
+                        usedColorList.push_back(blockSymbol->GetLayerColor().substr());
+                    }
+                    if (fontSymbol != NULL)
+                    {
+                        usedColorList.push_back(fontSymbol->GetForegroundColor().substr());
+                    }
+                    if (markSymbol != NULL)
+                    {
+                        if (markSymbol->GetEdge() != NULL)
+                            usedColorList.push_back(markSymbol->GetEdge()->GetColor().substr());
+                        if (markSymbol->GetFill() != NULL)
+                        {
+                            usedColorList.push_back(markSymbol->GetFill()->GetForegroundColor().substr());
+                            usedColorList.push_back(markSymbol->GetFill()->GetBackgroundColor().substr());
+                        }
+                    }
+                    if (textSymbol != NULL)
+                    {
+                        usedColorList.push_back(textSymbol->GetForegroundColor().substr());
+                        usedColorList.push_back(textSymbol->GetBackgroundColor().substr());
+                    }
+                    if (w2dSymbol != NULL)
+                    {
+                        usedColorList.push_back(w2dSymbol->GetFillColor().substr());
+                        usedColorList.push_back(w2dSymbol->GetLineColor().substr());
+                        usedColorList.push_back(w2dSymbol->GetTextColor().substr());
+                    }
+                }
+            }
+
+            // CompositeRule Symbolization...
+            if (pcRule != NULL)
+            {
+                CompositeSymbolization* pcsym = pcRule->GetSymbolization();
+                SymbolInstanceCollection* sic = pcsym->GetSymbolCollection();
+                int nInstances = sic->GetCount();
+                for (int i=0; i<nInstances; ++i)
+                {
+                    SymbolInstance* instance = sic->GetAt(i);
+                    // get the symbol definition, either inlined or by reference
+                    SymbolDefinition* symdef = instance->GetSymbolDefinition();
+                    if (symdef) // inline
+                        FindColorInSymDefHelper(usedColorList, symdef);
+                    else
+                    {
+                        // resourceId
+                        const MdfString& symref = instance->GetResourceId(); // symbol reference
+                        if (sman)
+                        {
+                            // if we have a symbolmanager do the lookup
+                            MdfModel::SymbolDefinition* symdef = sman->GetSymbolDefinition(symref.c_str());
+                            FindColorInSymDefHelper(usedColorList, symdef);
+                        }
+                    }
+                } // for sym instances
+            } // for CompositeRule
+        } // for GetRules
+    } // for GetFeatureTypeStyles
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Extract colors from the scalerange, lookup the referenceIds, and store
+// them with the map.
+void MgMappingUtil::ExtractColors(MgMap* map, MdfModel::VectorScaleRange* scaleRange, Stylizer* stylizer)
+{
+    // add the colors from this scaleRange and vectorlayer to the map colors
+    try
+    {
+        DefaultStylizer* ds = dynamic_cast<DefaultStylizer*>(stylizer);
+        SE_SymbolManager* sman = ds? ds->GetSymbolManager() : NULL;
+        // stack based
+        ColorStringList vLayerColors;
+        // parse the scalerange
+        GetUsedColorsFromScaleRange(vLayerColors, scaleRange, sman);
+        map->AddColorsToPalette(vLayerColors);
+    }
+    catch (exception e)
+    {
+        ACE_DEBUG((LM_DEBUG, L"(%t) %w caught in MappingUtil.ExtractColors\n", e.what()));
+        throw e;
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// overloaded helper for SimpleSymbolDefinition
+inline void MgMappingUtil::FindColorInSymDefHelper(ColorStringList& colorList, MdfModel::SimpleSymbolDefinition* symdef)
+{
+    // the visitor for the graphics
+    class GraphicElementVisitorImpl : public MdfModel::IGraphicElementVisitor
+    {
+    public:
+        ColorStringList* colorList;
+        void VisitPath (Path& path)
+        {
+            colorList->push_back(path.GetLineColor().substr());
+            colorList->push_back(path.GetFillColor().substr());
+        };
+        // TODO - other visitors for VisitImage and VisitText to be added here on a needed basis
+        void VisitImage(Image& image) {};
+        void VisitText(Text& text) {};
+    } visitor;
+
+    if (symdef)
+    {
+        MdfModel::LineUsage* lineUsage = symdef->GetLineUsage();
+        if (lineUsage)
+        {
+            MdfModel::Path* path = lineUsage->GetDefaultPath();
+            if (path)
+            {
+                colorList.push_back(path->GetLineColor().substr());
+                colorList.push_back(path->GetFillColor().substr());
+            }
+        }
+
+        MdfModel::GraphicElementCollection* graphElems = symdef->GetGraphics();
+        int gInstances = graphElems->GetCount();
+        for (int i=0; i < gInstances; ++i)
+        {
+            MdfModel::GraphicElement* graphics = graphElems->GetAt(i);
+            if (graphics)
+            {
+                visitor.colorList = &colorList; // use injection to pass reference to list
+                graphics->AcceptVisitor(visitor);
+            }
+        }
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// overloaded helper for CompoundSymbolDefinition
+inline void MgMappingUtil::FindColorInSymDefHelper(ColorStringList& colorList, MdfModel::CompoundSymbolDefinition* symdef)
+{
+    if (symdef)
+    {
+        MdfModel::SimpleSymbolCollection* simSymCol = symdef->GetSymbols();
+        int kInstances = simSymCol->GetCount();
+        for (int i=0; i<kInstances; ++i)
+        {
+            MdfModel::SimpleSymbol* simsym = simSymCol->GetAt(i);
+            if (simsym)
+            {
+                MdfModel::SimpleSymbolDefinition* simplesymdef = simsym->GetSymbolDefinition();
+                if (simplesymdef) // inline
+                    FindColorInSymDefHelper(colorList, simplesymdef);
+                else
+                {
+                    // TODO - resourceId
+                }
+            }
+        }
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// overloaded helper for SymbolDefinition
+inline void MgMappingUtil::FindColorInSymDefHelper(ColorStringList& colorList, MdfModel::SymbolDefinition* symdef)
+{
+    FindColorInSymDefHelper(colorList, dynamic_cast<MdfModel::SimpleSymbolDefinition*>(symdef));
+    FindColorInSymDefHelper(colorList, dynamic_cast<MdfModel::CompoundSymbolDefinition*>(symdef));
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//-------------------------------------------------------
+// RFC60 code for colormapped tiles by UV
+//-------------------------------------------------------
+// We examine the expressions collected from xml definitions of all layers.
+// The color Palette for the renderer is a vector<RS_Color>.  The map object
+// has a list from all color entries found in the most recent layer stylization.
+// TODO - currently they are interpreted as ffffffff 32 bit RGBA string values.
+// Adding expressions and other interpretations could be done here.
+void MgMappingUtil::ParseColorStrings (RS_ColorVector* tileColorPalette, MgMap* map)
+{
+    assert(tileColorPalette);
+    assert(map);
+    ColorStringList& mapColorList = map->GetColorPalette(); // sorted and uniquified
+    if (!mapColorList.empty()) // add them if they are available
+    {
+        ColorStringList::iterator it = mapColorList.begin();
+        for (; it != mapColorList.end(); it++)
+        {
+            // string color reader for 0xAARRGGBB   "%10X" XML color strings
+            // this is parsed and converted using the MgColor(string) ctor which also uses rgba order
+            // but it is in argb order ergo => r=a, g=r, b=g, a=b
+            MgColor c(*it);
+            // set the RS_Color(r,g,b,a) assign the crossed over colors
+            tileColorPalette->push_back(RS_Color(c.GetGreen(), c.GetBlue(), c.GetAlpha(), c.GetRed()));
+        }
+    }
+}

Modified: sandbox/adsk/2.2gp/Server/src/Services/Mapping/MappingUtil.h
===================================================================
--- sandbox/adsk/2.2gp/Server/src/Services/Mapping/MappingUtil.h	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Server/src/Services/Mapping/MappingUtil.h	2010-07-16 21:14:16 UTC (rev 5035)
@@ -34,6 +34,13 @@
 class MgCoordinateSystem;
 class RSMgFeatureReader;
 class TransformCache;
+class SE_SymbolManager;
+namespace MdfModel
+{
+    class SymbolDefinition;
+    class CompoundSymbolDefinition;
+    class SimpleSymbolDefinition;
+}
 
 //Common stylization utility code -- used by both the mapping and rendering services
 class MG_SERVER_MAPPING_API MgMappingUtil
@@ -52,9 +59,10 @@
                               bool expandExtents,
                               bool checkRefreshFlag,
                               double scale,
-                              bool selection = false);
+                              bool selection = false,
+                              bool extractColors = false);
 
-    static RSMgFeatureReader * ExecuteFeatureQuery(MgFeatureService* svcFeature,
+    static RSMgFeatureReader* ExecuteFeatureQuery(MgFeatureService* svcFeature,
                                                  RS_Bounds& extent,
                                                  MdfModel::VectorLayerDefinition* vl,
                                                  const wchar_t* overrideFilter,
@@ -62,7 +70,7 @@
                                                  MgCoordinateSystem* layerCs,
                                                  TransformCache* cache);
 
-    static RSMgFeatureReader * ExecuteRasterQuery(MgFeatureService* svcFeature,
+    static RSMgFeatureReader* ExecuteRasterQuery(MgFeatureService* svcFeature,
                                                 RS_Bounds& extent,
                                                 MdfModel::GridLayerDefinition* gl,
                                                 const wchar_t* overrideFilter,
@@ -80,6 +88,21 @@
 
     static void InitializeStylizerCallback();
     static MgPolygon* GetPolygonFromEnvelope(MgEnvelope* extent);
+
+    // RFC60 addition
+    static void ExtractColors(MgMap* map, MdfModel::VectorScaleRange* scaleRange, Stylizer* stylizer);
+    static void GetUsedColorsFromScaleRange(ColorStringList& usedColorList, MdfModel::VectorScaleRange* scaleRange, SE_SymbolManager* sman);
+
+    // helpers
+    static void FindColorInSymDefHelper(ColorStringList& colorList, MdfModel::SymbolDefinition* symdef);
+    static void FindColorInSymDefHelper(ColorStringList& colorList, MdfModel::CompoundSymbolDefinition* symdef);
+    static void FindColorInSymDefHelper(ColorStringList& colorList, MdfModel::SimpleSymbolDefinition* symdef);
+
+    // Parse the expressions collected from xml definitions of all layers.  The map
+    // object has a list from all color entries found in the most recent layer stylization.
+    // TODO: currently they are interpreted as ffffffff 32 bit RGBA string values.
+    // The color palette passed to the renderer is a std::vector<RS_Color>
+    static void ParseColorStrings(RS_ColorVector* tileColorPalette, MgMap* map);
 };
 
 #endif

Modified: sandbox/adsk/2.2gp/Server/src/Services/Rendering/ServerRenderingService.cpp
===================================================================
--- sandbox/adsk/2.2gp/Server/src/Services/Rendering/ServerRenderingService.cpp	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Server/src/Services/Rendering/ServerRenderingService.cpp	2010-07-16 21:14:16 UTC (rev 5035)
@@ -36,8 +36,15 @@
 static const INT32 FILTER_SELECTABLE = 2;
 static const INT32 FILTER_HASTOOLTIPS = 4;
 
+inline bool hasColorMap (STRING format)
+{
+    return format == L"PNG8" || format == L"GIF";
+}
+
 IMPLEMENT_CREATE_SERVICE(MgServerRenderingService)
 
+
+///////////////////////////////////////////////////////////////////////////////
 // used when we want to process a given number of features
 bool StylizeThatMany(void* data)
 {
@@ -49,6 +56,7 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 MgServerRenderingService::MgServerRenderingService() : MgRenderingService()
 {
     m_pCSFactory = new MgCoordinateSystemFactory();
@@ -111,11 +119,13 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 MgServerRenderingService::~MgServerRenderingService()
 {
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 MgByteReader* MgServerRenderingService::RenderTile(MgMap* map,
                                                    CREFSTRING baseMapLayerGroupName,
                                                    INT32 tileColumn,
@@ -188,6 +198,8 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+/// render a map using all layers from the baseGroup
 MgByteReader* MgServerRenderingService::RenderTile(MgMap* map,
                                                    MgLayerGroup* baseGroup,
                                                    INT32 scaleIndex,
@@ -256,6 +268,8 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// default arg bKeepSelection = true
 MgByteReader* MgServerRenderingService::RenderDynamicOverlay(MgMap* map,
                                                              MgSelection* selection,
                                                              CREFSTRING format)
@@ -265,6 +279,8 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// default arg bKeepSelection = true
 MgByteReader* MgServerRenderingService::RenderDynamicOverlay(MgMap* map,
                                                              MgSelection* selection,
                                                              CREFSTRING format,
@@ -277,6 +293,8 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// called from API (first call of AjaxPgPViewerSampleApplication)
 MgByteReader* MgServerRenderingService::RenderDynamicOverlay(MgMap* map,
                                                              MgSelection* selection,
                                                              MgRenderingOptions* options)
@@ -341,6 +359,8 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// default arg bKeepSelection = true
 MgByteReader* MgServerRenderingService::RenderMap(MgMap* map,
                                                   MgSelection* selection,
                                                   CREFSTRING format)
@@ -350,6 +370,8 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// default arg bClip = false
 MgByteReader* MgServerRenderingService::RenderMap(MgMap* map,
                                                   MgSelection* selection,
                                                   CREFSTRING format,
@@ -359,6 +381,10 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// render complete map around center point in given scale using map's background
+// color and display sizes as default arguments to call the real rendermap method
+// default arg (bKeepSelection = true, bClip = false)
 MgByteReader* MgServerRenderingService::RenderMap(MgMap* map,
                                                   MgSelection* selection,
                                                   CREFSTRING format,
@@ -390,6 +416,8 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// default arg bKeepSelection = true
 MgByteReader* MgServerRenderingService::RenderMap(MgMap* map,
                                                   MgSelection* selection,
                                                   MgEnvelope* extents,
@@ -403,6 +431,9 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// render the provided extent of the map and align aspect ratios to the provided window
+// default arg bKeepSelection = true
 MgByteReader* MgServerRenderingService::RenderMap(MgMap* map,
                                                   MgSelection* selection,
                                                   MgEnvelope* extents,
@@ -497,6 +528,8 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// default argument bKeepSelection = true
 MgByteReader* MgServerRenderingService::RenderMap(MgMap* map,
                                                   MgSelection* selection,
                                                   MgCoordinate* center,
@@ -511,6 +544,8 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// default arguments bClip = false
 MgByteReader* MgServerRenderingService::RenderMap(MgMap* map,
                                                   MgSelection* selection,
                                                   MgCoordinate* center,
@@ -525,6 +560,10 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// render map around center point in given scale
+// default args bKeepSelection = true, bClip = false, backgroundColor = map->backgroundColor,
+// width = map->getDisplayWidth, height = map->getDisplayHeight
 MgByteReader* MgServerRenderingService::RenderMap(MgMap* map,
                                                   MgSelection* selection,
                                                   MgCoordinate* center,
@@ -581,7 +620,7 @@
 }
 
 
-
+///////////////////////////////////////////////////////////////////////////////
 MgFeatureInformation* MgServerRenderingService::QueryFeatures(MgMap* map,
                                                               MgStringCollection* layerNames,
                                                               MgGeometry* geometry,
@@ -593,6 +632,7 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 MgFeatureInformation* MgServerRenderingService::QueryFeatures(MgMap* map,
                                                               MgStringCollection* layerNames,
                                                               MgGeometry* geometry,
@@ -681,6 +721,7 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 MgBatchPropertyCollection* MgServerRenderingService::QueryFeatureProperties(MgMap* map,
                                                                             MgStringCollection* layerNames,
                                                                             MgGeometry* filterGeometry,
@@ -692,6 +733,7 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 MgBatchPropertyCollection* MgServerRenderingService::QueryFeatureProperties(MgMap* map,
                                                                             MgStringCollection* layerNames,
                                                                             MgGeometry* filterGeometry,
@@ -722,6 +764,9 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// pack options into object and forward call (select Selection AND Layers)
+// maybe keepSelection called by RenderTile
 MgByteReader* MgServerRenderingService::RenderMapInternal(MgMap* map,
                                                           MgSelection* selection,
                                                           MgReadOnlyLayerCollection* roLayers,
@@ -740,6 +785,14 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// called from (indirectly):
+//      RenderMap(complete), RenderMap(extent)(roLayers == NULL)
+//      RenderTile (selection == NULL)
+// render the map using from the provided rolayers
+// (this is the baseGroup layers for rendering tiles)
+// render map using provided options object from before
+// this is called for tiles and for dynamic overlays
 MgByteReader* MgServerRenderingService::RenderMapInternal(MgMap* map,
                                                           MgSelection* selection,
                                                           MgReadOnlyLayerCollection* roLayers,
@@ -788,14 +841,18 @@
 
     RS_Color bgcolor(0, 0, 0, 255); //not used -- GDRenderer is already initialized to the correct bgcolor
 
+    STRING format = options->GetImageFormat();
+
     RS_MapUIInfo mapInfo(sessionId, map->GetName(), map->GetObjectId(), srs, units, bgcolor);
 
     // begin map stylization
     dr->StartMap(&mapInfo, b, scale, map->GetDisplayDpi(), map->GetMetersPerUnit(), NULL);
 
+    MG_TRY()
+
         // if no layer collection is supplied, then put all layers in a temporary collection
         Ptr<MgReadOnlyLayerCollection> tempLayers = SAFE_ADDREF(roLayers);
-        if (tempLayers == NULL)
+        if (tempLayers == NULL)  // if called from renderMap not RenderTile
         {
             tempLayers = new MgReadOnlyLayerCollection();
             Ptr<MgLayerCollection> layers = map->GetLayers();
@@ -807,13 +864,14 @@
         }
 
         INT32 behavior = options->GetBehavior();
-        if (behavior & MgRenderingOptions::RenderLayers)
+        if (behavior & MgRenderingOptions::RenderLayers)    // this is for tiles so observer colormaps
         {
             MgMappingUtil::StylizeLayers(m_svcResource, m_svcFeature, m_svcDrawing, m_pCSFactory, map,
-                                         tempLayers, NULL, &ds, dr, dstCs, expandExtents, false, scale);
+                                         tempLayers, NULL, &ds, dr, dstCs, expandExtents, false, scale,
+                                         false, hasColorMap(format));
         }
 
-        // now we need to stylize the selection on top
+        // now we need to stylize the selection on top (this is not for tiles!)
         if (selection && (behavior & MgRenderingOptions::RenderSelection))
         {
             Ptr<MgReadOnlyLayerCollection> selLayers = selection->GetLayers();
@@ -867,7 +925,11 @@
             }
         }
 
+    MG_CATCH(L"MgServerRenderingService.RenderMapInternal")
+
     dr->EndMap();
+
+    MG_THROW()  // to skip a faulty tile we need to rethrow the exception which could be thrown in StylizeLayers
 /*
     //-------------------------------------------------------
     // draw a border around the tile - used for debugging
@@ -894,15 +956,38 @@
     // get a byte representation of the image
     auto_ptr<RS_ByteData> data;
 
-    STRING imageFormat = options->GetImageFormat();
-    // Both AGG and GD expect the format to be an uppercase string
-    STRING format = MgUtil::ToUpper(imageFormat);
+    try
+    {
+        // call the image renderer to create the image
+        if (wcscmp(m_rendererName.c_str(), L"AGG") == 0)
+        {
+            //-------------------------------------------------------
+            /// RFC60 code to correct colormaps by UV
+            //-------------------------------------------------------
+            // we examine the expressions collected from xml definitions of all layers.
+            // the map object has a list from all color entries found in the most recent layer stylization
+            // TODO currently they are interpreted as ffffffff 32 bit RGBA string values.
+            // adding expresssions and other interpretations should be done in ParseColorStrings.
+            // the color Palette for the renderer is a vector<RS_Color>
+            if (hasColorMap(format))
+            {
+                RS_ColorVector tileColorPalette;
+                MgMappingUtil::ParseColorStrings(&tileColorPalette, map);
+//              printf("<<<<<<<<<<<<<<<<<<<<< MgServerRenderingService::ColorPalette->size(): %d\n", tileColorPalette.size());
+                data.reset(((AGGRenderer*)dr)->Save(format, saveWidth, saveHeight, &tileColorPalette));
+            }
+            else
+                data.reset(((AGGRenderer*)dr)->Save(format, saveWidth, saveHeight, NULL));
+        }
+        else
+            data.reset(((GDRenderer*)dr)->Save(format, saveWidth, saveHeight));
+    }
+    catch (exception e)
+    {
+        ACE_DEBUG((LM_DEBUG, L"(%t) %w caught in RenderingService ColorPaletteGeneration\n", e.what()));
+        throw e;
+    }
 
-    if (wcscmp(m_rendererName.c_str(), L"AGG") == 0)
-        data.reset(((AGGRenderer*)dr)->Save(format, saveWidth, saveHeight));
-    else
-        data.reset(((GDRenderer*)dr)->Save(format, saveWidth, saveHeight));
-
     if (NULL != data.get())
     {
         // put this into a byte source
@@ -919,11 +1004,14 @@
 
         ret = bs->GetReader();
     }
+    else
+        throw new MgNullReferenceException(L"MgServerRenderingService.RenderMapInternal", __LINE__, __WFILE__, NULL, L"MgNoDataFromRenderer", NULL);
 
     return ret.Detach();
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 MgByteReader* MgServerRenderingService::RenderMapLegend(MgMap* map,
                                                         INT32 width,
                                                         INT32 height,
@@ -1009,6 +1097,7 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 // A helper function that does most of the work for QueryFeatures
 // and QueryFeatureProperties.  Basically runs a rendering loop with
 // a custom renderer supplied by the caller that accumulates selection
@@ -1367,12 +1456,14 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 void MgServerRenderingService::SetConnectionProperties(MgConnectionProperties*)
 {
     // Do nothing.  No connection properties are required for server-side service objects.
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
 SE_Renderer* MgServerRenderingService::CreateRenderer(int width,
                                                       int height,
                                                       RS_Color& bgColor,

Modified: sandbox/adsk/2.2gp/Server/src/Services/Tile/ServerTileService.cpp
===================================================================
--- sandbox/adsk/2.2gp/Server/src/Services/Tile/ServerTileService.cpp	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Server/src/Services/Tile/ServerTileService.cpp	2010-07-16 21:14:16 UTC (rev 5035)
@@ -117,12 +117,16 @@
     return found;
 }
 
-MgByteReader* MgServerTileService::GetTile(
-    MgResourceIdentifier* mapDefinition,
-    CREFSTRING baseMapLayerGroupName,
-    INT32 tileColumn,
-    INT32 tileRow,
-    INT32 scaleIndex)
+
+///////////////////////////////////////////////////////////////////////////////
+// Create tilename from mapDefinition, scaleIndex, row, and column.
+// Remove lockfile, look for the tile in the cache, if not in cache create
+// lockfile and look for map in mapcache.
+MgByteReader* MgServerTileService::GetTile(MgResourceIdentifier* mapDefinition,
+                                           CREFSTRING baseMapLayerGroupName,
+                                           INT32 tileColumn,
+                                           INT32 tileRow,
+                                           INT32 scaleIndex)
 {
     Ptr<MgByteReader> ret;
     FILE* lockFile = NULL;
@@ -149,26 +153,9 @@
             __LINE__, __WFILE__, &arguments, L"MgInvalidScaleIndex", NULL);
     }
 
-    MgServiceManager* serviceMan = MgServiceManager::GetInstance();
-    assert(NULL != serviceMan);
-
-    // Get the service from service manager
-    Ptr<MgResourceService> resourceService = dynamic_cast<MgResourceService*>(
-        serviceMan->RequestService(MgServiceType::ResourceService));
-    assert(NULL != resourceService);
-
-    if (!resourceService->HasPermission(mapDefinition, MgResourcePermission::ReadOnly))
-    {
-        MG_LOG_AUTHENTICATION_ENTRY(MgResources::PermissionDenied.c_str());
-
-        MgStringCollection arguments;
-        arguments.Add(mapDefinition->ToString());
-
-        throw new MgPermissionDeniedException(
-            L"MgServerTileService.GetTile",
-            __LINE__, __WFILE__, &arguments, L"", NULL);
-    }
-
+    // get the service from our helper method
+    Ptr<MgResourceService> resourceService = GetResourceServiceForMapDef(mapDefinition,
+                                            L"MgServerTileService.GetTile");
     // Generate tile and lock pathnames.
     m_tileCache->GeneratePathnames(mapDefinition, scaleIndex, baseMapLayerGroupName,
         tileColumn, tileRow, tilePathname, lockPathname, false);
@@ -194,9 +181,10 @@
 
         // Protect the serialized MgMap cache with a mutex.  Stream reading is not
         // thread safe so we need to deserialize the map within the mutex to ensure
-        // that a Rewind() is not called in the middle of a Deserialize()
+        // that a Rewind() is not called in the middle of a Deserialize().
+        // Lockfile test and creation is in same protected scope.
         {
-            // Attemp to lock the tile file.
+            // Attempt to lock the tile file.
             ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, NULL));
 
             // Bail out if the tile file has been locked for so long.
@@ -214,7 +202,7 @@
 
             if (NULL != ret)
             {
-                break;
+                break;  // tile was in tileCache .. done.
             }
 
             // Create the lock file and close it right away.
@@ -227,7 +215,7 @@
                 arguments.Add(lockPathname);
 
                 throw new MgFileIoException(L"MgServerTileService.GetTile",
-                    __LINE__, __WFILE__, &arguments, L"MgUnableToOpenTileFile", NULL);
+                    __LINE__, __WFILE__, &arguments, L"MgUnableToOpenLockFile", NULL);
             }
             else
             {
@@ -238,6 +226,10 @@
             if (sm_mapCache.end() != iter)
             {
                 cachedMap = SAFE_ADDREF((*iter).second);
+                cachedMap->Rewind();
+                Ptr<MgStream> stream = new MgStream(cachedMap);
+                map = new MgMap();
+                map->Deserialize(stream);
             }
             else
             {
@@ -254,17 +246,8 @@
                 }
                 sm_mapCache[mapString] = SAFE_ADDREF((MgMemoryStreamHelper*)cachedMap);
             }
+        }   // end of mutex scope
 
-
-            if (!map)
-            {
-                cachedMap->Rewind();
-                Ptr<MgStream> stream = new MgStream(cachedMap);
-                map = new MgMap();
-                map->Deserialize(stream);
-            }
-        }
-
         double scale = map->GetFiniteDisplayScaleAt(scaleIndex);
         map->SetViewScale(scale);
 
@@ -286,6 +269,8 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// look for the tile in the tilecache first
 MgByteReader* MgServerTileService::GetTile(MgMap* map,
                                            CREFSTRING baseMapLayerGroupName,
                                            INT32 tileColumn,
@@ -364,7 +349,7 @@
                 arguments.Add(lockPathname);
 
                 throw new MgFileIoException(L"MgServerTileService.GetTile",
-                    __LINE__, __WFILE__, &arguments, L"MgUnableToOpenTileFile", NULL);
+                    __LINE__, __WFILE__, &arguments, L"MgUnableToOpenLockFile", NULL);
             }
             else
             {
@@ -389,6 +374,9 @@
     return ret.Detach();
 }
 
+
+///////////////////////////////////////////////////////////////////////////////
+// render a tile and store it in the cache
 MgByteReader* MgServerTileService::GetTile(CREFSTRING tilePathname, MgMap* map, INT32 scaleIndex,
     CREFSTRING baseMapLayerGroupName, INT32 tileColumn, INT32 tileRow)
 {
@@ -422,6 +410,9 @@
     return img.Detach();
 }
 
+
+///////////////////////////////////////////////////////////////////////////////
+// take a tile image and store it in the tilecache using lockfiles
 void MgServerTileService::SetTile(MgByteReader* img,
                                   MgMap* map,
                                   INT32 scaleIndex,
@@ -476,7 +467,7 @@
             arguments.Add(lockPathname);
 
             throw new MgFileIoException(L"MgServerTileService.SetTile",
-                __LINE__, __WFILE__, &arguments, L"MgUnableToOpenTileFile", NULL);
+                __LINE__, __WFILE__, &arguments, L"MgUnableToOpenLockFile", NULL);
         }
         else
         {
@@ -498,6 +489,35 @@
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// accessor method for resource service
+MgResourceService* MgServerTileService::GetResourceServiceForMapDef(MgResourceIdentifier* mapDefinition,
+                                                                    CREFSTRING funcName)
+{
+    // get service manager
+    MgServiceManager* serviceMan = MgServiceManager::GetInstance();
+    assert(NULL != serviceMan);
+
+    // Get the service from service manager
+    Ptr<MgResourceService> resourceService = dynamic_cast<MgResourceService*>(
+        serviceMan->RequestService(MgServiceType::ResourceService));
+    assert(NULL != resourceService);
+
+    if (!resourceService->HasPermission(mapDefinition, MgResourcePermission::ReadOnly))
+    {
+        MG_LOG_AUTHENTICATION_ENTRY(MgResources::PermissionDenied.c_str());
+
+        MgStringCollection arguments;
+        arguments.Add(mapDefinition->ToString());
+
+        throw new MgPermissionDeniedException(
+            funcName, __LINE__, __WFILE__, &arguments, L"", NULL);
+    }
+    return resourceService.Detach();
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
 void MgServerTileService::ClearCache(MgMap* map)
 {
     MG_TRY()
@@ -513,6 +533,7 @@
     MG_CATCH_AND_THROW(L"MgServerTileService.ClearCache")
 }
 
+
 ///////////////////////////////////////////////////////////////////////////////
 /// \brief
 /// Handle the Resource Change Notification event.
@@ -571,11 +592,15 @@
     return success;
 }
 
+
+///////////////////////////////////////////////////////////////////////////////
 void MgServerTileService::SetConnectionProperties(MgConnectionProperties*)
 {
     // Do nothing.  No connection properties are required for Server-side service objects.
 }
 
+
+///////////////////////////////////////////////////////////////////////////////
 void MgServerTileService::ClearMapCache(CREFSTRING mapDefinition)
 {
     ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
@@ -612,11 +637,15 @@
     }
 }
 
+
+///////////////////////////////////////////////////////////////////////////////
 INT32 MgServerTileService::GetDefaultTileSizeX()
 {
     return MgTileParameters::tileWidth;
 }
 
+
+///////////////////////////////////////////////////////////////////////////////
 INT32 MgServerTileService::GetDefaultTileSizeY()
 {
     return MgTileParameters::tileHeight;

Modified: sandbox/adsk/2.2gp/Server/src/Services/Tile/ServerTileService.h
===================================================================
--- sandbox/adsk/2.2gp/Server/src/Services/Tile/ServerTileService.h	2010-07-16 12:50:46 UTC (rev 5034)
+++ sandbox/adsk/2.2gp/Server/src/Services/Tile/ServerTileService.h	2010-07-16 21:14:16 UTC (rev 5035)
@@ -69,6 +69,8 @@
 
     void ClearMapCache(CREFSTRING mapName);
 
+    MgResourceService* GetResourceServiceForMapDef(MgResourceIdentifier* mapDefinition, CREFSTRING funcName);
+
     // member data
     Ptr<MgTileCache> m_tileCache;
 



More information about the mapguide-commits mailing list