From 4a4b2f6c1e500d892e0aa5189fbfd2827c1b85b5 Mon Sep 17 00:00:00 2001 From: "shanjian%netscape.com" Date: Fri, 30 Nov 2001 00:41:20 +0000 Subject: [PATCH] #support unicode beyond BMP plane in Compressed charmap r=bstell, sr=brendan --- gfx/public/nsCompressedCharMap.h | 72 ++++++- gfx/src/nsCompressedCharMap.cpp | 179 ++++++++++++++---- gfx/src/shared/nsCompressedCharMap.cpp | 179 ++++++++++++++---- gfx/src/shared/nsCompressedCharMap.h | 72 ++++++- intl/unicharutil/util/nsCompressedCharMap.cpp | 179 ++++++++++++++---- intl/unicharutil/util/nsCompressedCharMap.h | 72 ++++++- 6 files changed, 633 insertions(+), 120 deletions(-) diff --git a/gfx/public/nsCompressedCharMap.h b/gfx/public/nsCompressedCharMap.h index ee18c65e8458..b3dfb3958392 100644 --- a/gfx/public/nsCompressedCharMap.h +++ b/gfx/public/nsCompressedCharMap.h @@ -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 diff --git a/gfx/src/nsCompressedCharMap.cpp b/gfx/src/nsCompressedCharMap.cpp index 5ccf2429abca..1dc989488a44 100644 --- a/gfx/src/nsCompressedCharMap.cpp +++ b/gfx/src/nsCompressedCharMap.cpp @@ -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 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 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 > 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; +} diff --git a/gfx/src/shared/nsCompressedCharMap.cpp b/gfx/src/shared/nsCompressedCharMap.cpp index 5ccf2429abca..1dc989488a44 100644 --- a/gfx/src/shared/nsCompressedCharMap.cpp +++ b/gfx/src/shared/nsCompressedCharMap.cpp @@ -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 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 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 > 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; +} diff --git a/gfx/src/shared/nsCompressedCharMap.h b/gfx/src/shared/nsCompressedCharMap.h index ee18c65e8458..b3dfb3958392 100644 --- a/gfx/src/shared/nsCompressedCharMap.h +++ b/gfx/src/shared/nsCompressedCharMap.h @@ -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 diff --git a/intl/unicharutil/util/nsCompressedCharMap.cpp b/intl/unicharutil/util/nsCompressedCharMap.cpp index 5ccf2429abca..1dc989488a44 100644 --- a/intl/unicharutil/util/nsCompressedCharMap.cpp +++ b/intl/unicharutil/util/nsCompressedCharMap.cpp @@ -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 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 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 > 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; +} diff --git a/intl/unicharutil/util/nsCompressedCharMap.h b/intl/unicharutil/util/nsCompressedCharMap.h index ee18c65e8458..b3dfb3958392 100644 --- a/intl/unicharutil/util/nsCompressedCharMap.h +++ b/intl/unicharutil/util/nsCompressedCharMap.h @@ -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