Back to index

lightning-sunbird  0.9+nobinonly
nsCompressedCharMap.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Brian Stell <bstell@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include <stdio.h>
00040 #include "prmem.h"
00041 #include "nsCRT.h"
00042 #include "nsICharRepresentable.h"
00043 #include "nsCompressedCharMap.h"
00044 
00045 void
00046 FreeCCMap(PRUint16* &aMap)
00047 {
00048   if (!aMap)
00049     return;
00050   PR_Free(aMap - CCMAP_EXTRA);
00051   aMap = nsnull;
00052 }
00053 
00054 PRUint16*
00055 MapToCCMap(PRUint32* aMap)
00056 {
00057   // put the data into a temp map
00058   nsCompressedCharMap ccmapObj;
00059   ccmapObj.SetChars(aMap);
00060 
00061   PRUint16 *ccmap = (PRUint16*)PR_Malloc((CCMAP_EXTRA + ccmapObj.GetSize()) * sizeof(PRUint16));
00062   NS_ASSERTION(ccmap, "failed to alloc new CCMap");
00063 
00064   if (!ccmap)
00065     return nsnull;
00066 
00067   ccmap += CCMAP_EXTRA;
00068   CCMAP_SIZE(ccmap) = ccmapObj.GetSize();
00069   CCMAP_FLAG(ccmap) = CCMAP_NONE_FLAG;
00070 
00071   ccmapObj.FillCCMap(ccmap);
00072 
00073 #ifdef DEBUG
00074   for (int i=0; i<NUM_UNICODE_CHARS; i++) {
00075     PRBool oldb = IS_REPRESENTABLE(aMap, i);
00076     PRBool newb = CCMAP_HAS_CHAR(ccmap, i);
00077     if ((oldb) != (newb)) {
00078       NS_ASSERTION(oldb==newb,"failed to generate map correctly");
00079     }
00080   }
00081 #endif
00082   return ccmap;
00083 }
00084 
00085 PRUint16* CreateEmptyCCMap()
00086 {
00087   PRUint16 *ccmap = (PRUint16*)PR_Malloc((CCMAP_EXTRA + 16) * sizeof(PRUint16));
00088   NS_ASSERTION(ccmap, "failed to alloc new CCMap");
00089 
00090   if (!ccmap)
00091     return nsnull;
00092 
00093   memset(ccmap, '\0', CCMAP_EMPTY_SIZE_PER_INT16 * sizeof(PRUint16)+ CCMAP_EXTRA);
00094   ccmap += CCMAP_EXTRA;
00095   CCMAP_SIZE(ccmap) = CCMAP_EMPTY_SIZE_PER_INT16;
00096   CCMAP_FLAG(ccmap) = CCMAP_NONE_FLAG;
00097   return ccmap;
00098 }
00099 
00100 PRUint16*
00101 MapperToCCMap(nsICharRepresentable *aMapper)
00102 {
00103   PRUint32 map[UCS2_MAP_LEN];
00104   memset(map, 0, sizeof(map));
00105   nsresult res = aMapper->FillInfo(map);
00106   if (NS_FAILED(res))
00107     return nsnull;
00108   PRUint16* ccMap = MapToCCMap(map);
00109 
00110   return ccMap;
00111 }
00112 
00113 PRBool
00114 NextNonEmptyCCMapPage(const PRUint16* aCCMap, PRUint32 *aPageStart)
00115 {
00116   int i, j, l;
00117   int planeend = 0;
00118   int planestart = 0;
00119   unsigned int k;
00120   const PRUint16* ccmap;
00121   PRUint32 pagestart = *aPageStart;
00122 
00123   if(CCMAP_FLAG(aCCMap) & CCMAP_SURROGATE_FLAG) {
00124     // for SURROGATE
00125     planeend = EXTENDED_UNICODE_PLANES;
00126   }
00127 
00128   if(pagestart != CCMAP_BEGIN_AT_START_OF_MAP) {
00129     planestart = CCMAP_PLANE(pagestart);
00130   }
00131 
00132   // checking each plane
00133   for(l=planestart; l<=planeend; l++, pagestart = CCMAP_BEGIN_AT_START_OF_MAP) {
00134 
00135     if(l != 0 && CCMAP_FLAG(aCCMap) & CCMAP_SURROGATE_FLAG) {
00136       // for SURROGATE - get ccmap per plane
00137       ccmap = CCMAP_FOR_PLANE_EXT(aCCMap, l);
00138     } else {
00139       // only BMP
00140       ccmap = aCCMap;
00141     }
00142     //
00143     // Point to the next page
00144     //
00145     unsigned int upper_index;
00146     unsigned int mid_index;
00147 
00148     if (pagestart == CCMAP_BEGIN_AT_START_OF_MAP) {
00149       upper_index = 0;
00150       mid_index   = 0;
00151     } else {
00152       upper_index = CCMAP_UPPER_INDEX(pagestart & 0xffff);
00153       mid_index   = CCMAP_MID_INDEX(pagestart & 0xffff) + 1;
00154     }
00155 
00156     // walk thru the upper pointers
00157     const PRUint16 *upper = &ccmap[0];
00158     for (i=upper_index; i<CCMAP_NUM_UPPER_POINTERS; i++, mid_index=0) {
00159       if (upper[i] == CCMAP_EMPTY_MID) {
00160         continue;
00161       }
00162 
00163       // walk the mid array
00164       const PRUint16 *mid = &ccmap[upper[i]];
00165       for (j=mid_index; j<CCMAP_NUM_MID_POINTERS; j++) {
00166         if (mid[j] == CCMAP_EMPTY_PAGE)
00167           continue;
00168   
00169         // walk the page
00170         const ALU_TYPE *page = (ALU_TYPE*)&ccmap[mid[j]];
00171         for (k=0; k<CCMAP_NUM_ALUS_PER_PAGE; k++) {
00172           if (page[k] != 0) {
00173             PRUint32 base = (i*CCMAP_NUM_UCHARS_PER_MID) + (j*CCMAP_NUM_UCHARS_PER_PAGE);
00174             NS_ASSERTION(base<NUM_UNICODE_CHARS, "invalid page address");
00175             // return exact UCS4 code point, plane number + base
00176             *aPageStart = (((PRUint32)l)<<16)+base;
00177             return PR_TRUE;
00178           }
00179         }
00180       }
00181     }
00182   }
00183   return PR_FALSE;
00184 }
00185 
00186 #define CCMAP_MID_OFFSET(m, i) ((m)[i])
00187 #define CCMAP_PAGE_OFFSET_FROM_MIDOFFSET(m, midoffset, i) ((m)[(i) + (midoffset)])
00188 
00189 /***********************************************************************************
00190  *compare 2 ccmap and see if they are exactly the same
00191  * Here I assume both ccmap is generated by 
00192  * nsCompressedCharMap::SetChars(PRUint32* aMap)
00193  * This funtion rely on current implementation of above function. The that changed, 
00194  * we might need to revisit this implementation. 
00195  ***********************************************************************************/
00196 PRBool IsSameCCMap(PRUint16* ccmap1, PRUint16* ccmap2)
00197 {
00198   PRUint16 len1 = CCMAP_SIZE(ccmap1);
00199   PRUint16 len2 = CCMAP_SIZE(ccmap2);
00200   
00201   if (len1 != len2)
00202     return PR_FALSE;
00203 
00204   if (memcmp(ccmap1, ccmap2, sizeof(PRUint16)*len1))
00205     return PR_FALSE;
00206   return PR_TRUE;
00207 }
00208 
00209 PRUint16*
00210 nsCompressedCharMap::NewCCMap()
00211 {
00212   if (mExtended) {
00213     return MapToCCMapExt(mMap, mExtMap+1, EXTENDED_UNICODE_PLANES);
00214   } else {
00215     PRUint16 *newMap = (PRUint16*)PR_Malloc((CCMAP_EXTRA + mUsedLen) * sizeof(PRUint16));
00216     NS_ASSERTION(newMap, "failed to alloc new CCMap");
00217     if (!newMap)
00218       return nsnull;
00219   
00220     newMap += CCMAP_EXTRA;
00221     CCMAP_SIZE(newMap) = GetSize();
00222     CCMAP_FLAG(newMap) = CCMAP_NONE_FLAG;
00223 
00224     FillCCMap(newMap);
00225     return newMap;
00226   }
00227 }
00228 
00229 PRUint16*
00230 nsCompressedCharMap::FillCCMap(PRUint16* aCCMap)
00231 {
00232   // transfer the data
00233   for (int i=0; i<mUsedLen; i++)
00234     aCCMap[i] = u.mCCMap[i];
00235 
00236   return aCCMap;
00237 }
00238 
00239 nsCompressedCharMap::~nsCompressedCharMap()
00240 {
00241   if(mExtended){
00242     int i;
00243     for (i = 1; i <= EXTENDED_UNICODE_PLANES; ++i) {
00244       if (mExtMap[i]) {
00245         PR_Free(mExtMap[i]);
00246       }
00247     }
00248   }
00249 }
00250 
00251 nsCompressedCharMap::nsCompressedCharMap()
00252 {
00253   // initialize map to have:
00254   //    1 upper pointer array
00255   //    1 empty mid pointer array
00256   //    1 empty page
00257 
00258   int i;
00259   memset(u.mCCMap, 0, sizeof(u.mCCMap));
00260   mUsedLen = 0;
00261   mAllOnesPage = 0;
00262 
00263   // init the upper pointers
00264   PRUint16 *upper = &u.mCCMap[0];
00265   for (i=0; i<CCMAP_NUM_UPPER_POINTERS; i++) {
00266     upper[i] = CCMAP_EMPTY_MID;
00267   }
00268   mUsedLen += CCMAP_NUM_UPPER_POINTERS;
00269 
00270   // init the empty mid
00271   NS_ASSERTION(mUsedLen==CCMAP_EMPTY_MID, "empty mid offset misconfigured");
00272   PRUint16 *mid = &u.mCCMap[CCMAP_EMPTY_MID];
00273   for (i=0; i<CCMAP_NUM_MID_POINTERS; i++) {
00274     mid[i] = CCMAP_EMPTY_PAGE;
00275   }
00276   mUsedLen += CCMAP_NUM_MID_POINTERS;
00277 
00278   // init the empty page
00279   NS_ASSERTION(mUsedLen==CCMAP_EMPTY_PAGE, "empty page offset misconfigured");
00280   // the page was zero'd by the memset above
00281   mUsedLen += CCMAP_NUM_PRUINT16S_PER_PAGE;
00282 
00283   // init extended
00284   mExtended = PR_FALSE;
00285   memset(mExtMap+1, 0, sizeof(PRUint32*) * EXTENDED_UNICODE_PLANES);
00286   memset(mMap, 0, sizeof(mMap));
00287   mExtMap[0] = mMap;
00288 
00289 }
00290 
00291 void
00292 nsCompressedCharMap::SetChar(PRUint32 aChar)
00293 {
00294   if (mExtended) {
00295     PRUint32 plane_num = CCMAP_PLANE(aChar);
00296     NS_ASSERTION(plane_num <= EXTENDED_UNICODE_PLANES,"invalid plane");
00297     if (plane_num <= EXTENDED_UNICODE_PLANES) {
00298       if (mExtMap[plane_num] == 0) {
00299         mExtMap[plane_num] = (PRUint32*)PR_Malloc(sizeof(PRUint32)*UCS2_MAP_LEN);
00300         NS_ASSERTION(mExtMap[plane_num], "failed to alloc new mExtMap");
00301         if (!mExtMap[plane_num]) {
00302           return;
00303         }
00304         memset(mExtMap[plane_num], 0, sizeof(PRUint32)*UCS2_MAP_LEN);
00305       }
00306       SET_REPRESENTABLE(mExtMap[plane_num], aChar & 0xffff);
00307     }
00308   } else {
00309     NS_ASSERTION(aChar <= 0xffff, "extended char is passed");
00310 
00311     unsigned int i;
00312     unsigned int upper_index      = CCMAP_UPPER_INDEX(aChar);
00313     unsigned int mid_index        = CCMAP_MID_INDEX(aChar);
00314 
00315     PRUint16 mid_offset = u.mCCMap[upper_index];
00316     if (mid_offset == CCMAP_EMPTY_MID) {
00317       mid_offset = u.mCCMap[upper_index] = mUsedLen;
00318       mUsedLen += CCMAP_NUM_MID_POINTERS;
00319       NS_ASSERTION(mUsedLen<=CCMAP_MAX_LEN,"length too long");
00320       // init the mid
00321       PRUint16 *mid = &u.mCCMap[mid_offset];
00322       for (i=0; i<CCMAP_NUM_MID_POINTERS; i++) {
00323         NS_ASSERTION(mid[i]==0, "this mid pointer should be unused");
00324         mid[i] = CCMAP_EMPTY_PAGE;
00325       }
00326     }
00327 
00328     PRUint16 page_offset = u.mCCMap[mid_offset+mid_index];
00329     if (page_offset == CCMAP_EMPTY_PAGE) {
00330       page_offset = u.mCCMap[mid_offset+mid_index] = mUsedLen;
00331       mUsedLen += CCMAP_NUM_PRUINT16S_PER_PAGE;
00332       NS_ASSERTION(mUsedLen<=CCMAP_MAX_LEN,"length too long");
00333       // init the page
00334       PRUint16 *page = &u.mCCMap[page_offset];
00335       for (i=0; i<CCMAP_NUM_PRUINT16S_PER_PAGE; i++) {
00336         NS_ASSERTION(page[i]==0, "this page should be unused");
00337         page[i] = 0;
00338       }
00339     }
00340 #undef CCMAP_SET_CHAR
00341 #define CCMAP_SET_CHAR(m,c) (CCMAP_TO_ALU(m,c) |= (CCMAP_POW2(CCMAP_BIT_INDEX(c))))
00342     CCMAP_SET_CHAR(u.mCCMap,aChar);
00343 #undef CCMAP_SET_CHAR
00344     NS_ASSERTION(CCMAP_HAS_CHAR(u.mCCMap,aChar), "failed to set bit");
00345   }
00346 }
00347 
00348 void
00349 nsCompressedCharMap::SetChars(PRUint16 aBase, ALU_TYPE* aPage)
00350 {
00351   unsigned int i;
00352   unsigned int upper_index = CCMAP_UPPER_INDEX(aBase);
00353   unsigned int mid_index   = CCMAP_MID_INDEX(aBase);
00354   NS_ASSERTION((aBase&CCMAP_PAGE_MASK)==0, "invalid page address");
00355 
00356   //
00357   // check of none/all bits set
00358   //
00359   PRUint16 num_none_set = 0;
00360   PRUint16 num_all_set = 0;
00361   for (i=0; i<CCMAP_NUM_ALUS_PER_PAGE; i++) {
00362     if (aPage[i] == 0)
00363       num_none_set++;
00364     else if (aPage[i] == CCMAP_ALU_MASK)
00365       num_all_set++;
00366   }
00367   if (num_none_set == CCMAP_NUM_ALUS_PER_PAGE) {
00368     return;
00369   }
00370 
00371   //
00372   // Alloc mid if necessary
00373   //
00374   PRUint16 mid_offset = u.mCCMap[upper_index];
00375   if (mid_offset == CCMAP_EMPTY_MID) {
00376     mid_offset = u.mCCMap[upper_index] = mUsedLen;
00377     mUsedLen += CCMAP_NUM_MID_POINTERS;
00378     NS_ASSERTION(mUsedLen<=CCMAP_MAX_LEN,"length too long");
00379     // init the mid
00380     PRUint16 *mid = &u.mCCMap[mid_offset];
00381     for (i=0; i<CCMAP_NUM_MID_POINTERS; i++) {
00382       NS_ASSERTION(mid[i]==0, "this mid pointer should be unused");
00383       mid[i] = CCMAP_EMPTY_PAGE;
00384     }
00385   }
00386 
00387   //
00388   // if all bits set share an "all bits set" page
00389   //
00390   if (num_all_set == CCMAP_NUM_ALUS_PER_PAGE) {
00391     if (mAllOnesPage == 0) {
00392       mAllOnesPage = mUsedLen;
00393       mUsedLen += CCMAP_NUM_PRUINT16S_PER_PAGE;
00394       NS_ASSERTION(mUsedLen<=CCMAP_MAX_LEN,"length too long");
00395       ALU_TYPE *all_ones_page = (ALU_TYPE*)&u.mCCMap[mAllOnesPage];
00396       for (i=0; i<CCMAP_NUM_ALUS_PER_PAGE; i++) {
00397         NS_ASSERTION(all_ones_page[i]==0, "this page should be unused");
00398         all_ones_page[i] = CCMAP_ALU_MASK;
00399       }
00400     }
00401     u.mCCMap[mid_offset+mid_index] = mAllOnesPage;
00402     return;
00403   }
00404 
00405   //
00406   // Alloc page if necessary
00407   //
00408   PRUint16 page_offset = u.mCCMap[mid_offset+mid_index];
00409   if (page_offset == CCMAP_EMPTY_PAGE) {
00410     page_offset = u.mCCMap[mid_offset+mid_index] = mUsedLen;
00411     mUsedLen += CCMAP_NUM_PRUINT16S_PER_PAGE;
00412     NS_ASSERTION(mUsedLen<=CCMAP_MAX_LEN,"length too long");
00413   }
00414 
00415   // copy the page data
00416   ALU_TYPE *page = (ALU_TYPE*)&u.mCCMap[page_offset];
00417   for (i=0; i<CCMAP_NUM_ALUS_PER_PAGE; i++) {
00418     NS_ASSERTION(page[i]==0, "this page should be unused");
00419     page[i] = aPage[i];
00420   }
00421 }
00422 
00423 void
00424 nsCompressedCharMap::SetChars(PRUint16* aCCMap)
00425 {
00426   int i, j;
00427   if(mExtended){
00428     PRUint32 page = CCMAP_BEGIN_AT_START_OF_MAP;
00429     while (NextNonEmptyCCMapPage(aCCMap, &page)) {
00430       PRUint32 pagechar = page;
00431       for (i=0; i<(CCMAP_BITS_PER_PAGE/8); i++) {
00432         for (j=0; j<8; j++) {
00433           if (CCMAP_HAS_CHAR_EXT(aCCMap, pagechar)) {
00434             SetChar(pagechar);
00435           }
00436           pagechar++;
00437         }
00438       }
00439     }
00440   } else {
00441     //
00442     // Copy the input CCMap
00443     //
00444     // walk thru the upper pointers
00445     PRUint16 *upper = &aCCMap[0];
00446     for (i=0; i<CCMAP_NUM_UPPER_POINTERS; i++) {
00447       if (upper[i] == CCMAP_EMPTY_MID)
00448         continue;
00449 
00450       // walk the mid array
00451       PRUint16 *mid = &aCCMap[upper[i]];
00452       for (j=0; j<CCMAP_NUM_MID_POINTERS; j++) {
00453         if (mid[j] == CCMAP_EMPTY_PAGE)
00454           continue;
00455 
00456         PRUint32 base = (i*CCMAP_NUM_UCHARS_PER_MID) + (j*CCMAP_NUM_UCHARS_PER_PAGE);
00457         NS_ASSERTION(base<NUM_UNICODE_CHARS, "invalid page address");
00458         ALU_TYPE *page = (ALU_TYPE*)&aCCMap[mid[j]];
00459         SetChars((PRUint16)base, page);
00460       }
00461     }
00462   }
00463 }
00464 
00465 void
00466 nsCompressedCharMap::SetChars(PRUint32* aMap)
00467 {
00468   PRUint32* frommap_page;
00469   frommap_page = aMap;
00470   PRUint16 base = 0;
00471 
00472   for (int i=0; i<CCMAP_TOTAL_PAGES; i++) {
00473 
00474 #if (CCMAP_BITS_PER_ALU == CCMAP_BITS_PER_PRUINT32)
00475     SetChars(base, (ALU_TYPE*)frommap_page);
00476     frommap_page += CCMAP_PRUINT32S_PER_PAGE;
00477 
00478 #elif (CCMAP_BITS_PER_ALU > CCMAP_BITS_PER_PRUINT32)
00479     int j, k = CCMAP_BITS_PER_PRUINT32;
00480     ALU_TYPE page[CCMAP_NUM_ALUS_PER_PAGE];
00481     ALU_TYPE *p = page;
00482     for (j=0; j<CCMAP_ALUS_PER_PAGE; j++) {
00483       ALU_TYPE alu_val = 0;
00484       ALU_TYPE tmp;
00485       for (k=0; k<CCMAP_PRUINT32S_PER_ALU; k++) {
00486         tmp = *frommap_page;
00487         tmp <<= (k*CCMAP_BITS_PER_PRUINT32);
00488         //alu_val |= (*frommap_page)<<(k*CCMAP_BITS_PER_PRUINT32);
00489         alu_val |= tmp;
00490         frommap_page++;
00491       }
00492       *p++ = alu_val;
00493     }
00494     SetChars(base, page);
00495 #elif (CCMAP_BITS_PER_ALU < CCMAP_BITS_PER_PRUINT32)
00496     int j, k;
00497     ALU_TYPE page[CCMAP_NUM_ALUS_PER_PAGE];
00498     int v = CCMAP_PRUINT32S_PER_PAGE;
00499     ALU_TYPE *p = page;
00500     for (j=0; j<CCMAP_PRUINT32S_PER_PAGE; j++) {
00501       PRUint32 pruint32_val = *frommap_page++;
00502       for (k=0; k<CCMAP_ALUS_PER_PRUINT32; k++) {
00503         *p++ = pruint32_val & CCMAP_ALU_MASK;
00504         pruint32_val >>= CCMAP_BITS_PER_ALU; 
00505       }
00506     }
00507     SetChars(base, page);
00508 #endif
00509 
00510     base += CCMAP_NUM_UCHARS_PER_PAGE;
00511   }
00512 }
00513 
00514 #ifdef DEBUG
00515 void
00516 printCCMap(PRUint16* aCCMap)
00517 {
00518   PRUint32 page = CCMAP_BEGIN_AT_START_OF_MAP;
00519   while (NextNonEmptyCCMapPage(aCCMap, &page)) {
00520     //FONT_SCAN_PRINTF(("page starting at 0x%04x has chars", page));
00521     int i;
00522     PRUint32 pagechar = page;
00523   
00524     printf("CCMap:0x%04lx=", (long)page);
00525     for (i=0; i<(CCMAP_BITS_PER_PAGE/8); i++) {
00526       unsigned char val = 0;
00527       for (int j=0; j<8; j++) {
00528         if (CCMAP_HAS_CHAR(aCCMap, pagechar)) {
00529           val |= 1 << j;
00530         }
00531         pagechar++;
00532       }
00533       printf("%02x", val);
00534     }
00535     printf("\n");
00536   }
00537 }
00538 #endif
00539 
00540 // Non-BMP unicode support extension, create ccmap for both BMP and extended planes 
00541 PRUint16*
00542 MapToCCMapExt(PRUint32* aBmpPlaneMap, PRUint32** aOtherPlaneMaps, PRUint32 aOtherPlaneNum)
00543 {
00544   nsCompressedCharMap* otherPlaneObj[EXTENDED_UNICODE_PLANES];
00545   PRUint32 totalSize;
00546   PRUint16 i;
00547   PRUint32 *planeCCMapOffsets;
00548   PRUint32 currOffset;
00549 
00550   NS_ASSERTION(aOtherPlaneNum <= EXTENDED_UNICODE_PLANES, "illegal argument value");
00551   if (aOtherPlaneNum > EXTENDED_UNICODE_PLANES)
00552     return nsnull;
00553 
00554   // Put the data into a temp map
00555   nsCompressedCharMap bmpCcmapObj;
00556   bmpCcmapObj.SetChars(aBmpPlaneMap);
00557 
00558   // Add bmp size
00559   totalSize = bmpCcmapObj.GetSize();
00560 
00561   // Add bmp length field
00562   totalSize += CCMAP_EXTRA;
00563   
00564   // Add Plane array 
00565   totalSize += EXTENDED_UNICODE_PLANES * sizeof(PRUint32)/sizeof(PRUint16);
00566 
00567   // Add an empty plane ccmap
00568   // A totally empty plane ccmap can be represented by 16 *(PRUint16)0. 
00569   totalSize += CCMAP_EMPTY_SIZE_PER_INT16;
00570 
00571   // Create ccmap for other planes
00572   for (i = 0; i < aOtherPlaneNum; i++) {
00573     if (aOtherPlaneMaps[i]) {
00574       otherPlaneObj[i] = new nsCompressedCharMap();
00575       NS_ASSERTION(otherPlaneObj, "unable to create new nsCompressedCharMap");
00576       if(otherPlaneObj) {
00577         otherPlaneObj[i]->SetChars(aOtherPlaneMaps[i]);
00578         totalSize += otherPlaneObj[i]->GetSize();
00579       }
00580     } else {
00581       otherPlaneObj[i] = nsnull;
00582     }
00583   }
00584 
00585   PRUint16 *ccmap = (PRUint16*)PR_Malloc(totalSize * sizeof(PRUint16));
00586   NS_ASSERTION(ccmap, "failed to alloc new CCMap");
00587 
00588   if (!ccmap)
00589     return nsnull;
00590 
00591   // Assign BMP ccmap size
00592   ccmap += CCMAP_EXTRA;
00593   CCMAP_SIZE(ccmap) = bmpCcmapObj.GetSize();
00594   CCMAP_FLAG(ccmap) = CCMAP_SURROGATE_FLAG;
00595 
00596   // Fill bmp plane ccmap 
00597   bmpCcmapObj.FillCCMap(ccmap);
00598 
00599   // Get pointer for plane ccmap offset array
00600   currOffset = bmpCcmapObj.GetSize();
00601   planeCCMapOffsets = (PRUint32*)(ccmap+currOffset);
00602   currOffset += sizeof(PRUint32)/sizeof(PRUint16)*EXTENDED_UNICODE_PLANES;
00603 
00604   // Put a empty ccmap there 
00605   memset(ccmap+currOffset, '\0', sizeof(PRUint16)*16);
00606   PRUint32 emptyCCMapOffset = currOffset;
00607   currOffset += CCMAP_EMPTY_SIZE_PER_INT16;
00608 
00609   // Now fill all rest of the planes' ccmap and put off in array
00610   for (i = 0; i <aOtherPlaneNum; i++) {
00611     if (aOtherPlaneMaps[i] && otherPlaneObj[i]) {
00612       *(planeCCMapOffsets+i) = currOffset;
00613       otherPlaneObj[i]->FillCCMap(ccmap+currOffset);
00614       currOffset += otherPlaneObj[i]->GetSize();
00615     }
00616     else 
00617       *(planeCCMapOffsets+i) = emptyCCMapOffset;
00618   }
00619   for (; i < EXTENDED_UNICODE_PLANES; i++) {
00620     *(planeCCMapOffsets+i) = emptyCCMapOffset;
00621   }
00622 
00623   // remove all nsCompressedCharMap objects allocated 
00624   for (i = 0; i < aOtherPlaneNum; i++) {
00625     if (otherPlaneObj[i]) 
00626       delete otherPlaneObj[i];
00627   }
00628 
00629 #ifdef DEBUG
00630   PRUint32 k, h, l, plane, offset;
00631   PRBool oldb;
00632   PRBool newb;
00633 
00634   // testing for BMP plane
00635   for (k=0; k<NUM_UNICODE_CHARS; k++) {
00636     oldb = IS_REPRESENTABLE(aBmpPlaneMap, k);
00637     newb = CCMAP_HAS_CHAR_EXT(ccmap, k);
00638     NS_ASSERTION(oldb==newb,"failed to generate map correctly");
00639   }
00640 
00641   //testing for extension plane 
00642   for (k = 0x10000; k < 0x100000; k++) {
00643     plane = k/0x10000;
00644     if (plane > aOtherPlaneNum)
00645       break;
00646     if (aOtherPlaneMaps[plane-1])
00647       oldb = IS_REPRESENTABLE(aOtherPlaneMaps[plane-1], k&0xffff);
00648     else
00649       oldb = 0;
00650     newb = CCMAP_HAS_CHAR_EXT(ccmap, k);
00651     NS_ASSERTION(oldb==newb, "failed to generate extension map correctly");
00652   }
00653 
00654   
00655   // testing for non-BMP plane
00656     for (h = 0; h < 0x400; h++) {
00657       for (l = 0; l < 0x400; l++) {
00658         plane = h >> 6;
00659         offset = (h*0x400 + l) & 0xffff;
00660         if (aOtherPlaneMaps[plane])
00661           oldb = IS_REPRESENTABLE(aOtherPlaneMaps[plane], offset);
00662         else
00663           oldb = 0;
00664         newb = CCMAP_HAS_CHAR_EXT2(ccmap, h+0xd800, l+0xdc00);
00665         NS_ASSERTION(oldb==newb, "failed to generate extension map correctly");
00666       }
00667     }
00668 #endif
00669 
00670   return ccmap;
00671 }