PRUint16*
MapToCCMap(PRUint32* aMap)
{
  // put the data into a temp map
  nsCompressedCharMap ccmapObj;
  ccmapObj.SetChars(aMap);

  PRUint16 *ccmap = (PRUint16*)PR_Malloc((CCMAP_EXTRA + ccmapObj.GetSize()) * sizeof(PRUint16));
  NS_ASSERTION(ccmap, "failed to alloc new CCMap");

  if (!ccmap)
    return nsnull;

  ccmap += CCMAP_EXTRA;
  CCMAP_SIZE(ccmap) = ccmapObj.GetSize();
  CCMAP_FLAG(ccmap) = CCMAP_NONE_FLAG;

  ccmapObj.FillCCMap(ccmap);

#ifdef DEBUG
  for (int i=0; i<NUM_UNICODE_CHARS; i++) {
    PRBool oldb = IS_REPRESENTABLE(aMap, i);
    PRBool newb = CCMAP_HAS_CHAR(ccmap, i);
    if ((oldb) != (newb)) {
      NS_ASSERTION(oldb==newb,"failed to generate map correctly");
    }
  }
#endif
  return ccmap;
}
void
nsCompressedCharMap::SetChar(PRUint32 aChar)
{
  if (mExtended) {
    PRUint32 plane_num = CCMAP_PLANE(aChar);
    NS_ASSERTION(plane_num <= EXTENDED_UNICODE_PLANES,"invalid plane");
    if (plane_num <= EXTENDED_UNICODE_PLANES) {
      if (mExtMap[plane_num] == 0) {
        mExtMap[plane_num] = (PRUint32*)PR_Malloc(sizeof(PRUint32)*UCS2_MAP_LEN);
        NS_ASSERTION(mExtMap[plane_num], "failed to alloc new mExtMap");
        if (!mExtMap[plane_num]) {
          return;
        }
        memset(mExtMap[plane_num], 0, sizeof(PRUint32)*UCS2_MAP_LEN);
      }
      SET_REPRESENTABLE(mExtMap[plane_num], aChar & 0xffff);
    }
  } else {
    NS_ASSERTION(aChar <= 0xffff, "extended char is passed");

    unsigned int i;
    unsigned int upper_index      = CCMAP_UPPER_INDEX(aChar);
    unsigned int mid_index        = CCMAP_MID_INDEX(aChar);

    PRUint16 mid_offset = u.mCCMap[upper_index];
    if (mid_offset == CCMAP_EMPTY_MID) {
      mid_offset = u.mCCMap[upper_index] = mUsedLen;
      mUsedLen += CCMAP_NUM_MID_POINTERS;
      NS_ASSERTION(mUsedLen<=CCMAP_MAX_LEN,"length too long");
      // init the mid
      PRUint16 *mid = &u.mCCMap[mid_offset];
      for (i=0; i<CCMAP_NUM_MID_POINTERS; i++) {
        NS_ASSERTION(mid[i]==0, "this mid pointer should be unused");
        mid[i] = CCMAP_EMPTY_PAGE;
      }
    }

    PRUint16 page_offset = u.mCCMap[mid_offset+mid_index];
    if (page_offset == CCMAP_EMPTY_PAGE) {
      page_offset = u.mCCMap[mid_offset+mid_index] = mUsedLen;
      mUsedLen += CCMAP_NUM_PRUINT16S_PER_PAGE;
      NS_ASSERTION(mUsedLen<=CCMAP_MAX_LEN,"length too long");
      // init the page
      PRUint16 *page = &u.mCCMap[page_offset];
      for (i=0; i<CCMAP_NUM_PRUINT16S_PER_PAGE; i++) {
        NS_ASSERTION(page[i]==0, "this page should be unused");
        page[i] = 0;
      }
    }
#undef CCMAP_SET_CHAR
#define CCMAP_SET_CHAR(m,c) (CCMAP_TO_ALU(m,c) |= (CCMAP_POW2(CCMAP_BIT_INDEX(c))))
    CCMAP_SET_CHAR(u.mCCMap,aChar);
#undef CCMAP_SET_CHAR
    NS_ASSERTION(CCMAP_HAS_CHAR(u.mCCMap,aChar), "failed to set bit");
  }
}
short nsUnicodeFontMappingMac::GetFontID(PRUnichar aChar) {
    // initialize to bogus values
    short firstSymbolicFont = BAD_FONT_NUM, firstNonSymbolicFont = BAD_FONT_NUM;
    PRInt32 firstSymbolicFontIndex = -1;
    
    // Trap invisible chars
    if (CCMAP_HAS_CHAR_EXT(gIgnorableCCMapExt, aChar)) {
      return IGNORABLE_FONT_NUM;
    }

    // find the first symbolic font that has a glyph for aChar
    // and if there is one, remember it's index in the font list
    for(PRInt32 i = 0; i < mFontList.Count(); i++)
    {
        nsUnicodeFontMappingEntry* entry = (nsUnicodeFontMappingEntry*) mFontList[i];
        PRUint16 *ccmap = entry->GetCCMap();
        if(ccmap && CCMAP_HAS_CHAR(ccmap, aChar))
        {
            firstSymbolicFontIndex = i;
            firstSymbolicFont = entry->GetFontNum();
            break;
        }
    }

    // find the first non-symbolic font that has a glyph for aChar
	nsUnicodeBlock block = GetBlock(aChar);
	if(block < kUnicodeBlockFixedScriptMax) 
	{
		firstNonSymbolicFont = mScriptFallbackFontIDs[gUtil->BlockToScript(block)];
		
		// if there was no symbolic font we don't need to loop through the list again
        if(firstSymbolicFont == BAD_FONT_NUM)
            return firstNonSymbolicFont;
        
        // find the index of the first non symbolic font in the list and return the 
        // first font (symbolic or non symbolic) in the list that has a glyph for this char
        for(PRInt32 i = 0; i < mFontList.Count(); i++)
        {
            nsUnicodeFontMappingEntry* entry = (nsUnicodeFontMappingEntry*) mFontList[i];
            if(entry->GetFontNum() == firstNonSymbolicFont)
            {
                return (firstSymbolicFontIndex < i ? firstSymbolicFont : firstNonSymbolicFont);
            }
        }
        return firstNonSymbolicFont;
	}
	
    return (firstSymbolicFont != BAD_FONT_NUM ? firstSymbolicFont : 
		mScriptFallbackFontIDs[ mPrivBlockToScript[ block - kUnicodeBlockFixedScriptMax] ]);
}
void
printCCMap(PRUint16* aCCMap)
{
  PRUint32 page = CCMAP_BEGIN_AT_START_OF_MAP;
  while (NextNonEmptyCCMapPage(aCCMap, &page)) {
    //FONT_SCAN_PRINTF(("page starting at 0x%04x has chars", page));
    int i;
    PRUint32 pagechar = page;
  
    printf("CCMap:0x%04lx=", (long)page);
    for (i=0; i<(CCMAP_BITS_PER_PAGE/8); i++) {
      unsigned char val = 0;
      for (int j=0; j<8; j++) {
        if (CCMAP_HAS_CHAR(aCCMap, pagechar)) {
          val |= 1 << j;
        }
        pagechar++;
      }
      printf("%02x", val);
    }
    printf("\n");
  }
}