#support unicode beyond BMP plane in Compressed charmap

r=bstell,  sr=brendan
This commit is contained in:
shanjian%netscape.com 2001-11-30 00:41:20 +00:00
Родитель ed39cb8438
Коммит 4a4b2f6c1e
6 изменённых файлов: 633 добавлений и 120 удалений

Просмотреть файл

@ -69,6 +69,10 @@ extern PRUint16* MapperToCCMap(nsICharRepresentable *aMapper);
extern void FreeCCMap(PRUint16* &aMap);
extern PRBool IsSameCCMap(PRUint16* ccmap1, PRUint16* ccmap2);
// surrogate support extension
extern PRUint16*
MapToCCMapExt(PRUint32* aBmpPlaneMap, PRUint32** aOtherPlaneMaps, PRUint32 aOtherPlaneNum);
//
// nsCompressedCharMap
//
@ -97,7 +101,8 @@ public:
nsCompressedCharMap();
PRUint16* NewCCMap();
void FreeCCMap(PRUint16*);
PRUint16* FillCCMap(PRUint16* aCCMap);
PRUint16 GetSize() {return mUsedLen;};
void SetChar(PRUint16);
void SetChars(PRUint16*);
void SetChars(PRUint16, ALU_TYPE*);
@ -172,6 +177,7 @@ protected:
// One minor note: for a completely empty map it is actually
// possible to fold the upper, empty mid, and empty page
// on top of each other and make a map of only 32 bytes.
#define CCMAP_EMPTY_SIZE_PER_INT16 16
// offsets to the empty mid and empty page
#define CCMAP_EMPTY_MID CCMAP_NUM_UPPER_POINTERS
@ -183,9 +189,50 @@ protected:
// the actual needed size and simply copy over the data.
//
//
// Compressed Char map surrogate extension
//
// The design goal of surrogate support extension is to keep efficiency
// and compatibility of existing compressed charmap operations. Most of
// existing operation are untouched. For BMP support, very little memory
// overhead (4 bytes) is added. Runtime efficiency of BMP support is
// unchanged.
//
// structure of extended charmap:
// ccmap flag 1 PRUint16 , indication if this is extended one or not
// bmp ccmap size 1 PRUint16 , the size of BMP ccmap,
// BMP ccmap size varies,
// plane index 16 PRUint32, use to index ccmap for non-BMP plane
// empty ccmap 16 PRUint16, a total empty ccmap
// non-BMP ccmaps size varies, other non-empty, non-BMP ccmap
//
// Changes to basic ccmap
// 2 PRUint16 are added in the very beginning. One is used to descript the size
// of the ccmap, the other is used as a flag. But these 2 fields are indexed
// negatively so that all other operation remain unchanged to keep efficiency.
// ccmap memory allocation is moved from nsCompressedCharMap::NewCCMap to
// MapToCCMap.
//
// Extended ccmap
// A 16*PRUint32 array was put at the end of basic ccmap, each PRUint32 either
// pointed to the empty ccmap or a independent plane ccmap. Directly after this
// array is a empty ccmap. All planes that has no character will share this ccmap.
// All non-empty plane will have a ccmap.
// "MapToCCMapExt" is added to created an extended ccmap, each plane ccmap is
// created the same as basic one, but without 2 additional fields.
// "HasGlyphExt" is used to access extended ccmap, it first need to locate the
// plane ccmap, and then operated the same way as "HasGlyph".
//
// Compatibility between old and new one
// Because extended ccmap includes an exactly identical basic ccmap in its head,
// basic ccmap operation (HasGlyph) can be applied on extended ccmap without
// problem.
// Because basic ccmap now has a flag to indicate if it is a extended one,
// Extended ccmap operation (HasGlyphExt) can check the flag before it does
// extended ccmap specific operation. So HasGlyphExt can be applied to basic ccmap
// too.
//
// Page bits
//
#define CCMAP_BITS_PER_PAGE_LOG2 8
@ -264,4 +311,23 @@ protected:
// unset the bit
#define CCMAP_UNSET_CHAR(m,c) (CCMAP_TO_ALU(m,c) &= ~(CCMAP_POW2(CCMAP_BIT_INDEX(c))))
#define CCMAP_SIZE(m) (*((m)-1))
#define CCMAP_FLAG(m) (*((m)-2))
#define CCMAP_EXTRA (sizeof(ALU_TYPE)/sizeof(PRUint16)>2? sizeof(ALU_TYPE)/sizeof(PRUint16): 2)
#define CCMAP_SURROGATE_FLAG 0X0001
#define CCMAP_NONE_FLAG 0x0000
// non-bmp unicode support extension
// get plane number from ccmap, bmp excluded, so plane 1's number is 0.
#define CCMAP_PLANE(h) (((PRUint16)(h) - (PRUint16)0xd800) >> 6)
// scalar value inside the plane
#define CCMAP_INPLANE_OFFSET(h, l) (((((PRUint16)(h) - (PRUint16)0xd800) & 0x3f) << 10) + ((PRUint16)(l) - (PRUint16)0xdc00))
// get ccmap for that plane
#define CCMAP_FOR_PLANE_EXT(m, i) ((m) + ((PRUint32*)((m) + CCMAP_SIZE(m)))[i])
// test the bit for surrogate pair
#define CCMAP_HAS_CHAR_EXT(m, h, l) (CCMAP_FLAG(m)&CCMAP_SURROGATE_FLAG && CCMAP_HAS_CHAR(CCMAP_FOR_PLANE_EXT((m), CCMAP_PLANE(h)), CCMAP_INPLANE_OFFSET(h, l)))
#endif // NSCOMPRESSEDCHARMAP_H

Просмотреть файл

@ -47,7 +47,7 @@ FreeCCMap(PRUint16* &aMap)
{
if (!aMap)
return;
PR_Free(aMap);
PR_Free(aMap - CCMAP_EXTRA);
aMap = nsnull;
}
@ -58,8 +58,17 @@ MapToCCMap(PRUint32* aMap)
nsCompressedCharMap ccmapObj;
ccmapObj.SetChars(aMap);
// make a copy of the map
PRUint16* ccmap = ccmapObj.NewCCMap();
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++) {
@ -75,8 +84,17 @@ MapToCCMap(PRUint32* aMap)
PRUint16* CreateEmptyCCMap()
{
nsCompressedCharMap ccmapObj;
return ccmapObj.NewCCMap();
PRUint16 *ccmap = (PRUint16*)PR_Malloc(CCMAP_EXTRA + 16 * sizeof(PRUint16));
NS_ASSERTION(ccmap, "failed to alloc new CCMap");
if (!ccmap)
return nsnull;
memset(ccmap, '\0', CCMAP_EMPTY_SIZE_PER_INT16 * sizeof(PRUint16)+ CCMAP_EXTRA);
ccmap += CCMAP_EXTRA;
CCMAP_SIZE(ccmap) = CCMAP_EMPTY_SIZE_PER_INT16;
CCMAP_FLAG(ccmap) = CCMAP_NONE_FLAG;
return ccmap;
}
PRUint16*
@ -104,37 +122,14 @@ MapperToCCMap(nsICharRepresentable *aMapper)
***********************************************************************************/
PRBool IsSameCCMap(PRUint16* ccmap1, PRUint16* ccmap2)
{
PRUint16 i, tmp;
PRUint16 maxMidOffset = CCMAP_EMPTY_MID;
PRUint16 maxOffset = 0;
//find out the midOffset which itself has the largest offset among all midOffset
for (i = 0; i < CCMAP_NUM_UPPER_POINTERS; i++) {
tmp = CCMAP_MID_OFFSET(ccmap1, i);
if ( tmp > maxMidOffset)
maxMidOffset = tmp;
}
//find out the larget page offset among maxMidOffset
for (i = 0; i < CCMAP_NUM_MID_POINTERS; i++) {
tmp = CCMAP_PAGE_OFFSET_FROM_MIDOFFSET(ccmap1, maxMidOffset, i);
if (tmp > maxOffset)
maxOffset = tmp;
}
//if the page offset is allocated later than maxMidOffset, add page size
if (maxOffset)
maxOffset += CCMAP_NUM_PRUINT16S_PER_PAGE;
else
maxOffset = maxMidOffset;
//now maxOffset is the size of ccmap1, though ccmap2 might be smaller than
//ccmap1, the following comparison is still safe. That is because it will
//return false before the limit of ccmap2 is reached.
for (i = 0; i < maxOffset; i++)
if (ccmap1[i] != ccmap2[i])
return PR_FALSE;
PRUint16 len1 = CCMAP_SIZE(ccmap1);
PRUint16 len2 = CCMAP_SIZE(ccmap2);
if (len1 != len2)
return PR_FALSE;
if (memcmp(ccmap1, ccmap2, sizeof(PRUint16)*len1))
return PR_FALSE;
return PR_TRUE;
}
@ -145,12 +140,18 @@ nsCompressedCharMap::NewCCMap()
NS_ASSERTION(newMap, "failed to alloc new CCMap");
if (!newMap)
return nsnull;
FillCCMap(newMap);
return newMap;
}
PRUint16*
nsCompressedCharMap::FillCCMap(PRUint16* aCCMap)
{
// transfer the data
for (int i=0; i<mUsedLen; i++)
newMap[i] = u.mCCMap[i];
aCCMap[i] = u.mCCMap[i];
return newMap;
return aCCMap;
}
nsCompressedCharMap::nsCompressedCharMap()
@ -349,3 +350,107 @@ nsCompressedCharMap::SetChars(PRUint32* aMap)
}
}
#define EXTENDED_UNICODE_PLANES 16
// Non-BMP unicode support extension, create ccmap for both BMP and extended planes
PRUint16*
MapToCCMapExt(PRUint32* aBmpPlaneMap, PRUint32** aOtherPlaneMaps, PRUint32 aOtherPlaneNum)
{
nsCompressedCharMap otherPlaneObj[16];
PRUint32 totalSize;
PRUint16 i;
PRUint32 *planeCCMapOffsets;
PRUint32 currOffset;
NS_ASSERTION(aOtherPlaneNum <= EXTENDED_UNICODE_PLANES, "illegal argument value");
if (aOtherPlaneNum > EXTENDED_UNICODE_PLANES)
return nsnull;
// Put the data into a temp map
nsCompressedCharMap bmpCcmapObj;
bmpCcmapObj.SetChars(aBmpPlaneMap);
// Add bmp size
totalSize = bmpCcmapObj.GetSize();
// Add bmp length field
totalSize += CCMAP_EXTRA;
// Add Plane array
totalSize += EXTENDED_UNICODE_PLANES * sizeof(PRUint32)/sizeof(PRUint16);
// Add an empty plane ccmap
// A totally empty plane ccmap can be represented by 16 *(PRUint16)0.
totalSize += CCMAP_EMPTY_SIZE_PER_INT16;
// Create ccmap for other planes
for (i = 0; i < aOtherPlaneNum; i++) {
if (aOtherPlaneMaps[i]) {
otherPlaneObj[i].SetChars(aOtherPlaneMaps[i]);
totalSize += otherPlaneObj[i].GetSize();
}
}
PRUint16 *ccmap = (PRUint16*)PR_Malloc(totalSize * sizeof(PRUint16));
NS_ASSERTION(ccmap, "failed to alloc new CCMap");
if (!ccmap)
return nsnull;
// Assign BMP ccmap size
ccmap += CCMAP_EXTRA;
CCMAP_SIZE(ccmap) = bmpCcmapObj.GetSize();
CCMAP_FLAG(ccmap) = CCMAP_SURROGATE_FLAG;
// Fill bmp plane ccmap
bmpCcmapObj.FillCCMap(ccmap);
// Get pointer for plane ccmap offset array
currOffset = bmpCcmapObj.GetSize();
planeCCMapOffsets = (PRUint32*)(ccmap+currOffset);
currOffset += sizeof(PRUint32)/sizeof(PRUint16)*EXTENDED_UNICODE_PLANES;
// Put a empty ccmap there
memset(ccmap+currOffset, '\0', sizeof(PRUint16)*16);
PRUint32 emptyCCMapOffset = currOffset;
currOffset += CCMAP_EMPTY_SIZE_PER_INT16;
// Now fill all rest of the planes' ccmap and put off in array
for (i = 0; i <aOtherPlaneNum; i++) {
if (aOtherPlaneMaps[i]) {
*(planeCCMapOffsets+i) = currOffset;
otherPlaneObj[i].FillCCMap(ccmap+currOffset);
currOffset += otherPlaneObj[i].GetSize();
}
else
*(planeCCMapOffsets+i) = emptyCCMapOffset;
}
for (; i < EXTENDED_UNICODE_PLANES; i++) {
*(planeCCMapOffsets+i) = emptyCCMapOffset;
}
#ifdef DEBUG
PRUint32 k, h, l, plane, offset;
PRBool oldb;
PRBool newb;
// testing for BMP plane
for (k=0; k<NUM_UNICODE_CHARS; k++) {
oldb = IS_REPRESENTABLE(aBmpPlaneMap, k);
newb = CCMAP_HAS_CHAR(ccmap, k);
NS_ASSERTION(oldb==newb,"failed to generate map correctly");
}
// testing for non-BMP plane
for (h = 0; h < 0x400; h++) {
for (l = 0; l < 0x400; l++) {
plane = h >> 6;
offset = (h*0x400 + l) & 0xffff;
oldb = IS_REPRESENTABLE(aOtherPlaneMaps[plane], offset);
newb = CCMAP_HAS_CHAR_EXT(ccmap, h+0xd800, l+0xdc00);
NS_ASSERTION(oldb==newb, "failed to generate extension map correctly");
}
}
#endif
return ccmap;
}

Просмотреть файл

@ -47,7 +47,7 @@ FreeCCMap(PRUint16* &aMap)
{
if (!aMap)
return;
PR_Free(aMap);
PR_Free(aMap - CCMAP_EXTRA);
aMap = nsnull;
}
@ -58,8 +58,17 @@ MapToCCMap(PRUint32* aMap)
nsCompressedCharMap ccmapObj;
ccmapObj.SetChars(aMap);
// make a copy of the map
PRUint16* ccmap = ccmapObj.NewCCMap();
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++) {
@ -75,8 +84,17 @@ MapToCCMap(PRUint32* aMap)
PRUint16* CreateEmptyCCMap()
{
nsCompressedCharMap ccmapObj;
return ccmapObj.NewCCMap();
PRUint16 *ccmap = (PRUint16*)PR_Malloc(CCMAP_EXTRA + 16 * sizeof(PRUint16));
NS_ASSERTION(ccmap, "failed to alloc new CCMap");
if (!ccmap)
return nsnull;
memset(ccmap, '\0', CCMAP_EMPTY_SIZE_PER_INT16 * sizeof(PRUint16)+ CCMAP_EXTRA);
ccmap += CCMAP_EXTRA;
CCMAP_SIZE(ccmap) = CCMAP_EMPTY_SIZE_PER_INT16;
CCMAP_FLAG(ccmap) = CCMAP_NONE_FLAG;
return ccmap;
}
PRUint16*
@ -104,37 +122,14 @@ MapperToCCMap(nsICharRepresentable *aMapper)
***********************************************************************************/
PRBool IsSameCCMap(PRUint16* ccmap1, PRUint16* ccmap2)
{
PRUint16 i, tmp;
PRUint16 maxMidOffset = CCMAP_EMPTY_MID;
PRUint16 maxOffset = 0;
//find out the midOffset which itself has the largest offset among all midOffset
for (i = 0; i < CCMAP_NUM_UPPER_POINTERS; i++) {
tmp = CCMAP_MID_OFFSET(ccmap1, i);
if ( tmp > maxMidOffset)
maxMidOffset = tmp;
}
//find out the larget page offset among maxMidOffset
for (i = 0; i < CCMAP_NUM_MID_POINTERS; i++) {
tmp = CCMAP_PAGE_OFFSET_FROM_MIDOFFSET(ccmap1, maxMidOffset, i);
if (tmp > maxOffset)
maxOffset = tmp;
}
//if the page offset is allocated later than maxMidOffset, add page size
if (maxOffset)
maxOffset += CCMAP_NUM_PRUINT16S_PER_PAGE;
else
maxOffset = maxMidOffset;
//now maxOffset is the size of ccmap1, though ccmap2 might be smaller than
//ccmap1, the following comparison is still safe. That is because it will
//return false before the limit of ccmap2 is reached.
for (i = 0; i < maxOffset; i++)
if (ccmap1[i] != ccmap2[i])
return PR_FALSE;
PRUint16 len1 = CCMAP_SIZE(ccmap1);
PRUint16 len2 = CCMAP_SIZE(ccmap2);
if (len1 != len2)
return PR_FALSE;
if (memcmp(ccmap1, ccmap2, sizeof(PRUint16)*len1))
return PR_FALSE;
return PR_TRUE;
}
@ -145,12 +140,18 @@ nsCompressedCharMap::NewCCMap()
NS_ASSERTION(newMap, "failed to alloc new CCMap");
if (!newMap)
return nsnull;
FillCCMap(newMap);
return newMap;
}
PRUint16*
nsCompressedCharMap::FillCCMap(PRUint16* aCCMap)
{
// transfer the data
for (int i=0; i<mUsedLen; i++)
newMap[i] = u.mCCMap[i];
aCCMap[i] = u.mCCMap[i];
return newMap;
return aCCMap;
}
nsCompressedCharMap::nsCompressedCharMap()
@ -349,3 +350,107 @@ nsCompressedCharMap::SetChars(PRUint32* aMap)
}
}
#define EXTENDED_UNICODE_PLANES 16
// Non-BMP unicode support extension, create ccmap for both BMP and extended planes
PRUint16*
MapToCCMapExt(PRUint32* aBmpPlaneMap, PRUint32** aOtherPlaneMaps, PRUint32 aOtherPlaneNum)
{
nsCompressedCharMap otherPlaneObj[16];
PRUint32 totalSize;
PRUint16 i;
PRUint32 *planeCCMapOffsets;
PRUint32 currOffset;
NS_ASSERTION(aOtherPlaneNum <= EXTENDED_UNICODE_PLANES, "illegal argument value");
if (aOtherPlaneNum > EXTENDED_UNICODE_PLANES)
return nsnull;
// Put the data into a temp map
nsCompressedCharMap bmpCcmapObj;
bmpCcmapObj.SetChars(aBmpPlaneMap);
// Add bmp size
totalSize = bmpCcmapObj.GetSize();
// Add bmp length field
totalSize += CCMAP_EXTRA;
// Add Plane array
totalSize += EXTENDED_UNICODE_PLANES * sizeof(PRUint32)/sizeof(PRUint16);
// Add an empty plane ccmap
// A totally empty plane ccmap can be represented by 16 *(PRUint16)0.
totalSize += CCMAP_EMPTY_SIZE_PER_INT16;
// Create ccmap for other planes
for (i = 0; i < aOtherPlaneNum; i++) {
if (aOtherPlaneMaps[i]) {
otherPlaneObj[i].SetChars(aOtherPlaneMaps[i]);
totalSize += otherPlaneObj[i].GetSize();
}
}
PRUint16 *ccmap = (PRUint16*)PR_Malloc(totalSize * sizeof(PRUint16));
NS_ASSERTION(ccmap, "failed to alloc new CCMap");
if (!ccmap)
return nsnull;
// Assign BMP ccmap size
ccmap += CCMAP_EXTRA;
CCMAP_SIZE(ccmap) = bmpCcmapObj.GetSize();
CCMAP_FLAG(ccmap) = CCMAP_SURROGATE_FLAG;
// Fill bmp plane ccmap
bmpCcmapObj.FillCCMap(ccmap);
// Get pointer for plane ccmap offset array
currOffset = bmpCcmapObj.GetSize();
planeCCMapOffsets = (PRUint32*)(ccmap+currOffset);
currOffset += sizeof(PRUint32)/sizeof(PRUint16)*EXTENDED_UNICODE_PLANES;
// Put a empty ccmap there
memset(ccmap+currOffset, '\0', sizeof(PRUint16)*16);
PRUint32 emptyCCMapOffset = currOffset;
currOffset += CCMAP_EMPTY_SIZE_PER_INT16;
// Now fill all rest of the planes' ccmap and put off in array
for (i = 0; i <aOtherPlaneNum; i++) {
if (aOtherPlaneMaps[i]) {
*(planeCCMapOffsets+i) = currOffset;
otherPlaneObj[i].FillCCMap(ccmap+currOffset);
currOffset += otherPlaneObj[i].GetSize();
}
else
*(planeCCMapOffsets+i) = emptyCCMapOffset;
}
for (; i < EXTENDED_UNICODE_PLANES; i++) {
*(planeCCMapOffsets+i) = emptyCCMapOffset;
}
#ifdef DEBUG
PRUint32 k, h, l, plane, offset;
PRBool oldb;
PRBool newb;
// testing for BMP plane
for (k=0; k<NUM_UNICODE_CHARS; k++) {
oldb = IS_REPRESENTABLE(aBmpPlaneMap, k);
newb = CCMAP_HAS_CHAR(ccmap, k);
NS_ASSERTION(oldb==newb,"failed to generate map correctly");
}
// testing for non-BMP plane
for (h = 0; h < 0x400; h++) {
for (l = 0; l < 0x400; l++) {
plane = h >> 6;
offset = (h*0x400 + l) & 0xffff;
oldb = IS_REPRESENTABLE(aOtherPlaneMaps[plane], offset);
newb = CCMAP_HAS_CHAR_EXT(ccmap, h+0xd800, l+0xdc00);
NS_ASSERTION(oldb==newb, "failed to generate extension map correctly");
}
}
#endif
return ccmap;
}

Просмотреть файл

@ -69,6 +69,10 @@ extern PRUint16* MapperToCCMap(nsICharRepresentable *aMapper);
extern void FreeCCMap(PRUint16* &aMap);
extern PRBool IsSameCCMap(PRUint16* ccmap1, PRUint16* ccmap2);
// surrogate support extension
extern PRUint16*
MapToCCMapExt(PRUint32* aBmpPlaneMap, PRUint32** aOtherPlaneMaps, PRUint32 aOtherPlaneNum);
//
// nsCompressedCharMap
//
@ -97,7 +101,8 @@ public:
nsCompressedCharMap();
PRUint16* NewCCMap();
void FreeCCMap(PRUint16*);
PRUint16* FillCCMap(PRUint16* aCCMap);
PRUint16 GetSize() {return mUsedLen;};
void SetChar(PRUint16);
void SetChars(PRUint16*);
void SetChars(PRUint16, ALU_TYPE*);
@ -172,6 +177,7 @@ protected:
// One minor note: for a completely empty map it is actually
// possible to fold the upper, empty mid, and empty page
// on top of each other and make a map of only 32 bytes.
#define CCMAP_EMPTY_SIZE_PER_INT16 16
// offsets to the empty mid and empty page
#define CCMAP_EMPTY_MID CCMAP_NUM_UPPER_POINTERS
@ -183,9 +189,50 @@ protected:
// the actual needed size and simply copy over the data.
//
//
// Compressed Char map surrogate extension
//
// The design goal of surrogate support extension is to keep efficiency
// and compatibility of existing compressed charmap operations. Most of
// existing operation are untouched. For BMP support, very little memory
// overhead (4 bytes) is added. Runtime efficiency of BMP support is
// unchanged.
//
// structure of extended charmap:
// ccmap flag 1 PRUint16 , indication if this is extended one or not
// bmp ccmap size 1 PRUint16 , the size of BMP ccmap,
// BMP ccmap size varies,
// plane index 16 PRUint32, use to index ccmap for non-BMP plane
// empty ccmap 16 PRUint16, a total empty ccmap
// non-BMP ccmaps size varies, other non-empty, non-BMP ccmap
//
// Changes to basic ccmap
// 2 PRUint16 are added in the very beginning. One is used to descript the size
// of the ccmap, the other is used as a flag. But these 2 fields are indexed
// negatively so that all other operation remain unchanged to keep efficiency.
// ccmap memory allocation is moved from nsCompressedCharMap::NewCCMap to
// MapToCCMap.
//
// Extended ccmap
// A 16*PRUint32 array was put at the end of basic ccmap, each PRUint32 either
// pointed to the empty ccmap or a independent plane ccmap. Directly after this
// array is a empty ccmap. All planes that has no character will share this ccmap.
// All non-empty plane will have a ccmap.
// "MapToCCMapExt" is added to created an extended ccmap, each plane ccmap is
// created the same as basic one, but without 2 additional fields.
// "HasGlyphExt" is used to access extended ccmap, it first need to locate the
// plane ccmap, and then operated the same way as "HasGlyph".
//
// Compatibility between old and new one
// Because extended ccmap includes an exactly identical basic ccmap in its head,
// basic ccmap operation (HasGlyph) can be applied on extended ccmap without
// problem.
// Because basic ccmap now has a flag to indicate if it is a extended one,
// Extended ccmap operation (HasGlyphExt) can check the flag before it does
// extended ccmap specific operation. So HasGlyphExt can be applied to basic ccmap
// too.
//
// Page bits
//
#define CCMAP_BITS_PER_PAGE_LOG2 8
@ -264,4 +311,23 @@ protected:
// unset the bit
#define CCMAP_UNSET_CHAR(m,c) (CCMAP_TO_ALU(m,c) &= ~(CCMAP_POW2(CCMAP_BIT_INDEX(c))))
#define CCMAP_SIZE(m) (*((m)-1))
#define CCMAP_FLAG(m) (*((m)-2))
#define CCMAP_EXTRA (sizeof(ALU_TYPE)/sizeof(PRUint16)>2? sizeof(ALU_TYPE)/sizeof(PRUint16): 2)
#define CCMAP_SURROGATE_FLAG 0X0001
#define CCMAP_NONE_FLAG 0x0000
// non-bmp unicode support extension
// get plane number from ccmap, bmp excluded, so plane 1's number is 0.
#define CCMAP_PLANE(h) (((PRUint16)(h) - (PRUint16)0xd800) >> 6)
// scalar value inside the plane
#define CCMAP_INPLANE_OFFSET(h, l) (((((PRUint16)(h) - (PRUint16)0xd800) & 0x3f) << 10) + ((PRUint16)(l) - (PRUint16)0xdc00))
// get ccmap for that plane
#define CCMAP_FOR_PLANE_EXT(m, i) ((m) + ((PRUint32*)((m) + CCMAP_SIZE(m)))[i])
// test the bit for surrogate pair
#define CCMAP_HAS_CHAR_EXT(m, h, l) (CCMAP_FLAG(m)&CCMAP_SURROGATE_FLAG && CCMAP_HAS_CHAR(CCMAP_FOR_PLANE_EXT((m), CCMAP_PLANE(h)), CCMAP_INPLANE_OFFSET(h, l)))
#endif // NSCOMPRESSEDCHARMAP_H

Просмотреть файл

@ -47,7 +47,7 @@ FreeCCMap(PRUint16* &aMap)
{
if (!aMap)
return;
PR_Free(aMap);
PR_Free(aMap - CCMAP_EXTRA);
aMap = nsnull;
}
@ -58,8 +58,17 @@ MapToCCMap(PRUint32* aMap)
nsCompressedCharMap ccmapObj;
ccmapObj.SetChars(aMap);
// make a copy of the map
PRUint16* ccmap = ccmapObj.NewCCMap();
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++) {
@ -75,8 +84,17 @@ MapToCCMap(PRUint32* aMap)
PRUint16* CreateEmptyCCMap()
{
nsCompressedCharMap ccmapObj;
return ccmapObj.NewCCMap();
PRUint16 *ccmap = (PRUint16*)PR_Malloc(CCMAP_EXTRA + 16 * sizeof(PRUint16));
NS_ASSERTION(ccmap, "failed to alloc new CCMap");
if (!ccmap)
return nsnull;
memset(ccmap, '\0', CCMAP_EMPTY_SIZE_PER_INT16 * sizeof(PRUint16)+ CCMAP_EXTRA);
ccmap += CCMAP_EXTRA;
CCMAP_SIZE(ccmap) = CCMAP_EMPTY_SIZE_PER_INT16;
CCMAP_FLAG(ccmap) = CCMAP_NONE_FLAG;
return ccmap;
}
PRUint16*
@ -104,37 +122,14 @@ MapperToCCMap(nsICharRepresentable *aMapper)
***********************************************************************************/
PRBool IsSameCCMap(PRUint16* ccmap1, PRUint16* ccmap2)
{
PRUint16 i, tmp;
PRUint16 maxMidOffset = CCMAP_EMPTY_MID;
PRUint16 maxOffset = 0;
//find out the midOffset which itself has the largest offset among all midOffset
for (i = 0; i < CCMAP_NUM_UPPER_POINTERS; i++) {
tmp = CCMAP_MID_OFFSET(ccmap1, i);
if ( tmp > maxMidOffset)
maxMidOffset = tmp;
}
//find out the larget page offset among maxMidOffset
for (i = 0; i < CCMAP_NUM_MID_POINTERS; i++) {
tmp = CCMAP_PAGE_OFFSET_FROM_MIDOFFSET(ccmap1, maxMidOffset, i);
if (tmp > maxOffset)
maxOffset = tmp;
}
//if the page offset is allocated later than maxMidOffset, add page size
if (maxOffset)
maxOffset += CCMAP_NUM_PRUINT16S_PER_PAGE;
else
maxOffset = maxMidOffset;
//now maxOffset is the size of ccmap1, though ccmap2 might be smaller than
//ccmap1, the following comparison is still safe. That is because it will
//return false before the limit of ccmap2 is reached.
for (i = 0; i < maxOffset; i++)
if (ccmap1[i] != ccmap2[i])
return PR_FALSE;
PRUint16 len1 = CCMAP_SIZE(ccmap1);
PRUint16 len2 = CCMAP_SIZE(ccmap2);
if (len1 != len2)
return PR_FALSE;
if (memcmp(ccmap1, ccmap2, sizeof(PRUint16)*len1))
return PR_FALSE;
return PR_TRUE;
}
@ -145,12 +140,18 @@ nsCompressedCharMap::NewCCMap()
NS_ASSERTION(newMap, "failed to alloc new CCMap");
if (!newMap)
return nsnull;
FillCCMap(newMap);
return newMap;
}
PRUint16*
nsCompressedCharMap::FillCCMap(PRUint16* aCCMap)
{
// transfer the data
for (int i=0; i<mUsedLen; i++)
newMap[i] = u.mCCMap[i];
aCCMap[i] = u.mCCMap[i];
return newMap;
return aCCMap;
}
nsCompressedCharMap::nsCompressedCharMap()
@ -349,3 +350,107 @@ nsCompressedCharMap::SetChars(PRUint32* aMap)
}
}
#define EXTENDED_UNICODE_PLANES 16
// Non-BMP unicode support extension, create ccmap for both BMP and extended planes
PRUint16*
MapToCCMapExt(PRUint32* aBmpPlaneMap, PRUint32** aOtherPlaneMaps, PRUint32 aOtherPlaneNum)
{
nsCompressedCharMap otherPlaneObj[16];
PRUint32 totalSize;
PRUint16 i;
PRUint32 *planeCCMapOffsets;
PRUint32 currOffset;
NS_ASSERTION(aOtherPlaneNum <= EXTENDED_UNICODE_PLANES, "illegal argument value");
if (aOtherPlaneNum > EXTENDED_UNICODE_PLANES)
return nsnull;
// Put the data into a temp map
nsCompressedCharMap bmpCcmapObj;
bmpCcmapObj.SetChars(aBmpPlaneMap);
// Add bmp size
totalSize = bmpCcmapObj.GetSize();
// Add bmp length field
totalSize += CCMAP_EXTRA;
// Add Plane array
totalSize += EXTENDED_UNICODE_PLANES * sizeof(PRUint32)/sizeof(PRUint16);
// Add an empty plane ccmap
// A totally empty plane ccmap can be represented by 16 *(PRUint16)0.
totalSize += CCMAP_EMPTY_SIZE_PER_INT16;
// Create ccmap for other planes
for (i = 0; i < aOtherPlaneNum; i++) {
if (aOtherPlaneMaps[i]) {
otherPlaneObj[i].SetChars(aOtherPlaneMaps[i]);
totalSize += otherPlaneObj[i].GetSize();
}
}
PRUint16 *ccmap = (PRUint16*)PR_Malloc(totalSize * sizeof(PRUint16));
NS_ASSERTION(ccmap, "failed to alloc new CCMap");
if (!ccmap)
return nsnull;
// Assign BMP ccmap size
ccmap += CCMAP_EXTRA;
CCMAP_SIZE(ccmap) = bmpCcmapObj.GetSize();
CCMAP_FLAG(ccmap) = CCMAP_SURROGATE_FLAG;
// Fill bmp plane ccmap
bmpCcmapObj.FillCCMap(ccmap);
// Get pointer for plane ccmap offset array
currOffset = bmpCcmapObj.GetSize();
planeCCMapOffsets = (PRUint32*)(ccmap+currOffset);
currOffset += sizeof(PRUint32)/sizeof(PRUint16)*EXTENDED_UNICODE_PLANES;
// Put a empty ccmap there
memset(ccmap+currOffset, '\0', sizeof(PRUint16)*16);
PRUint32 emptyCCMapOffset = currOffset;
currOffset += CCMAP_EMPTY_SIZE_PER_INT16;
// Now fill all rest of the planes' ccmap and put off in array
for (i = 0; i <aOtherPlaneNum; i++) {
if (aOtherPlaneMaps[i]) {
*(planeCCMapOffsets+i) = currOffset;
otherPlaneObj[i].FillCCMap(ccmap+currOffset);
currOffset += otherPlaneObj[i].GetSize();
}
else
*(planeCCMapOffsets+i) = emptyCCMapOffset;
}
for (; i < EXTENDED_UNICODE_PLANES; i++) {
*(planeCCMapOffsets+i) = emptyCCMapOffset;
}
#ifdef DEBUG
PRUint32 k, h, l, plane, offset;
PRBool oldb;
PRBool newb;
// testing for BMP plane
for (k=0; k<NUM_UNICODE_CHARS; k++) {
oldb = IS_REPRESENTABLE(aBmpPlaneMap, k);
newb = CCMAP_HAS_CHAR(ccmap, k);
NS_ASSERTION(oldb==newb,"failed to generate map correctly");
}
// testing for non-BMP plane
for (h = 0; h < 0x400; h++) {
for (l = 0; l < 0x400; l++) {
plane = h >> 6;
offset = (h*0x400 + l) & 0xffff;
oldb = IS_REPRESENTABLE(aOtherPlaneMaps[plane], offset);
newb = CCMAP_HAS_CHAR_EXT(ccmap, h+0xd800, l+0xdc00);
NS_ASSERTION(oldb==newb, "failed to generate extension map correctly");
}
}
#endif
return ccmap;
}

Просмотреть файл

@ -69,6 +69,10 @@ extern PRUint16* MapperToCCMap(nsICharRepresentable *aMapper);
extern void FreeCCMap(PRUint16* &aMap);
extern PRBool IsSameCCMap(PRUint16* ccmap1, PRUint16* ccmap2);
// surrogate support extension
extern PRUint16*
MapToCCMapExt(PRUint32* aBmpPlaneMap, PRUint32** aOtherPlaneMaps, PRUint32 aOtherPlaneNum);
//
// nsCompressedCharMap
//
@ -97,7 +101,8 @@ public:
nsCompressedCharMap();
PRUint16* NewCCMap();
void FreeCCMap(PRUint16*);
PRUint16* FillCCMap(PRUint16* aCCMap);
PRUint16 GetSize() {return mUsedLen;};
void SetChar(PRUint16);
void SetChars(PRUint16*);
void SetChars(PRUint16, ALU_TYPE*);
@ -172,6 +177,7 @@ protected:
// One minor note: for a completely empty map it is actually
// possible to fold the upper, empty mid, and empty page
// on top of each other and make a map of only 32 bytes.
#define CCMAP_EMPTY_SIZE_PER_INT16 16
// offsets to the empty mid and empty page
#define CCMAP_EMPTY_MID CCMAP_NUM_UPPER_POINTERS
@ -183,9 +189,50 @@ protected:
// the actual needed size and simply copy over the data.
//
//
// Compressed Char map surrogate extension
//
// The design goal of surrogate support extension is to keep efficiency
// and compatibility of existing compressed charmap operations. Most of
// existing operation are untouched. For BMP support, very little memory
// overhead (4 bytes) is added. Runtime efficiency of BMP support is
// unchanged.
//
// structure of extended charmap:
// ccmap flag 1 PRUint16 , indication if this is extended one or not
// bmp ccmap size 1 PRUint16 , the size of BMP ccmap,
// BMP ccmap size varies,
// plane index 16 PRUint32, use to index ccmap for non-BMP plane
// empty ccmap 16 PRUint16, a total empty ccmap
// non-BMP ccmaps size varies, other non-empty, non-BMP ccmap
//
// Changes to basic ccmap
// 2 PRUint16 are added in the very beginning. One is used to descript the size
// of the ccmap, the other is used as a flag. But these 2 fields are indexed
// negatively so that all other operation remain unchanged to keep efficiency.
// ccmap memory allocation is moved from nsCompressedCharMap::NewCCMap to
// MapToCCMap.
//
// Extended ccmap
// A 16*PRUint32 array was put at the end of basic ccmap, each PRUint32 either
// pointed to the empty ccmap or a independent plane ccmap. Directly after this
// array is a empty ccmap. All planes that has no character will share this ccmap.
// All non-empty plane will have a ccmap.
// "MapToCCMapExt" is added to created an extended ccmap, each plane ccmap is
// created the same as basic one, but without 2 additional fields.
// "HasGlyphExt" is used to access extended ccmap, it first need to locate the
// plane ccmap, and then operated the same way as "HasGlyph".
//
// Compatibility between old and new one
// Because extended ccmap includes an exactly identical basic ccmap in its head,
// basic ccmap operation (HasGlyph) can be applied on extended ccmap without
// problem.
// Because basic ccmap now has a flag to indicate if it is a extended one,
// Extended ccmap operation (HasGlyphExt) can check the flag before it does
// extended ccmap specific operation. So HasGlyphExt can be applied to basic ccmap
// too.
//
// Page bits
//
#define CCMAP_BITS_PER_PAGE_LOG2 8
@ -264,4 +311,23 @@ protected:
// unset the bit
#define CCMAP_UNSET_CHAR(m,c) (CCMAP_TO_ALU(m,c) &= ~(CCMAP_POW2(CCMAP_BIT_INDEX(c))))
#define CCMAP_SIZE(m) (*((m)-1))
#define CCMAP_FLAG(m) (*((m)-2))
#define CCMAP_EXTRA (sizeof(ALU_TYPE)/sizeof(PRUint16)>2? sizeof(ALU_TYPE)/sizeof(PRUint16): 2)
#define CCMAP_SURROGATE_FLAG 0X0001
#define CCMAP_NONE_FLAG 0x0000
// non-bmp unicode support extension
// get plane number from ccmap, bmp excluded, so plane 1's number is 0.
#define CCMAP_PLANE(h) (((PRUint16)(h) - (PRUint16)0xd800) >> 6)
// scalar value inside the plane
#define CCMAP_INPLANE_OFFSET(h, l) (((((PRUint16)(h) - (PRUint16)0xd800) & 0x3f) << 10) + ((PRUint16)(l) - (PRUint16)0xdc00))
// get ccmap for that plane
#define CCMAP_FOR_PLANE_EXT(m, i) ((m) + ((PRUint32*)((m) + CCMAP_SIZE(m)))[i])
// test the bit for surrogate pair
#define CCMAP_HAS_CHAR_EXT(m, h, l) (CCMAP_FLAG(m)&CCMAP_SURROGATE_FLAG && CCMAP_HAS_CHAR(CCMAP_FOR_PLANE_EXT((m), CCMAP_PLANE(h)), CCMAP_INPLANE_OFFSET(h, l)))
#endif // NSCOMPRESSEDCHARMAP_H