bug 221666 : remove redundant copy of nsCompressedCharMap.* (moved to intl/unicharutil) (r=smontagu, sr=rbs)

This commit is contained in:
jshin%mailaps.org 2003-11-09 18:44:11 +00:00
Родитель 047697c114
Коммит 591290d910
4 изменённых файлов: 0 добавлений и 1973 удалений

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

@ -1,355 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Stell <bstell@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef NSCOMPRESSEDCHARMAP_H
#define NSCOMPRESSEDCHARMAP_H
#include "prtypes.h"
#include "nsICharRepresentable.h"
#define ALU_SIZE PR_BITS_PER_LONG
//#define ALU_SIZE 16
//#define ALU_SIZE 32
//#define ALU_SIZE 64
#if (ALU_SIZE==32)
# define ALU_TYPE PRUint32
# define CCMAP_POW2(n) (1L<<(n))
# define CCMAP_BITS_PER_ALU_LOG2 5
#elif (ALU_SIZE==64)
# define ALU_TYPE PRUint64
# define CCMAP_POW2(n) (1L<<(n))
# define CCMAP_BITS_PER_ALU_LOG2 6
#else
# define ALU_TYPE PRUint16
# define CCMAP_POW2(n) (1<<(n))
# define CCMAP_BITS_PER_ALU_LOG2 4
#endif
class nsICharRepresentable;
extern PRUint16* CreateEmptyCCMap();
extern PRUint16* MapToCCMap(PRUint32* aMap);
extern PRUint16* MapperToCCMap(nsICharRepresentable *aMapper);
extern void FreeCCMap(PRUint16* &aMap);
extern PRBool NextNonEmptyCCMapPage(const PRUint16 *, PRUint32 *);
extern PRBool IsSameCCMap(PRUint16* ccmap1, PRUint16* ccmap2);
#ifdef DEBUG
void printCCMap(PRUint16* aCCMap);
#endif
// surrogate support extension
extern PRUint16*
MapToCCMapExt(PRUint32* aBmpPlaneMap, PRUint32** aOtherPlaneMaps, PRUint32 aOtherPlaneNum);
//
// nsCompressedCharMap
//
// A Compressed Char Map (CCMap) saves memory by folding all
// the empty portions of the map on top of each other.
//
// Building a Compressed Char Map (CCMap) is more complex than
// accessing it. We use the nsCompressedCharMap object to
// build the CCMap. Once nsCompressedCharMap has built the CCMap
// we get a copy of the CCMap and discard the nsCompressedCharMap
// object. The CCMap is an array of PRUint16 and is accessed by
// a macro.
//
// See "Character Map Compression" below for a discussion of
// what the array looks like.
//
// The maximum size a CCMap:
// (16 upper pointers) + (16 empty mid pointers) +
// (16 empty page) + (16*16 max mid pointers) +
// (256*16 max pages) = 4400 PRUint16
#define CCMAP_MAX_LEN (16+16+16+256+4096)
// non-bmp unicode support extension
#define EXTENDED_UNICODE_PLANES 16
class nsCompressedCharMap {
public:
nsCompressedCharMap();
~nsCompressedCharMap();
PRUint16* NewCCMap();
PRUint16* FillCCMap(PRUint16* aCCMap);
PRUint16 GetSize() {return mUsedLen;};
void SetChar(PRUint32);
void SetChars(PRUint16*);
void SetChars(PRUint16, ALU_TYPE*);
void SetChars(PRUint32*);
void Extend() {mExtended = PR_TRUE;} // enable surrogate area
protected:
union {
PRUint16 mCCMap[CCMAP_MAX_LEN];
ALU_TYPE used_for_align; // do not use; only here to cause
// alignment
} u;
PRUint16 mUsedLen; // in PRUint16
PRUint16 mAllOnesPage;
PRBool mExtended;
// for surrogate support
PRUint32* mExtMap[EXTENDED_UNICODE_PLANES+1];
PRUint32 mMap[UCS2_MAP_LEN];
};
//
// Character Map Compression
//
// Each font requires its own 8k charmap. On a system with 200
// fonts this would take: 200 * 8K = 1600K memory.
//
// Since most char maps are mostly empty a significant amount
// of memory can be saved by not allocating the unused sections.
//
// If the map has one or more levels of indirection then the
// the empty sections of the map can all be folded to a single
// common empty element. In this way only the non-empty sections
// need space. Because the empty sections actually point to a
// common empty section every entry in the map can be valid
// without requiring actually allocating space.
// Some larger CJK fonts have large sections where every bit
// is set. In the same way that the empty sections are folded
// onto one "empty page", the sections where all bits are set are
// folded on to one "all bits set page" .
//
// Break up the Unicode range bits 0x0000 - 0xFFFF
// into 3 bit ranges:
//
// upper bits: bit15 - bit12
// mid bits: bit11 - bit8
// page bits: bit7 - bit0
//
// within a page, (assumming a 4 byte ALU)
// bits 7-5 select one of the 8 longs
// bits 4-0 select one of the 32 bits within the long
//
// There is exactly one upper "pointers" array.
//
// The upper pointers each point to a mid array. If there are no chars
// in an upper pointer's block that pointer points to the empty mid.
// Thus all upper pointers are "valid" even if they do not have space
// allocated; eg: the accessor macro does not need to test if the
// pointer is zero.
//
// Each mid pointer in the mid array points to a page. If there are no
// chars in a mid pointer's page that pointer points to the empty page.
// Thus all mid pointers are "valid" even if they do not have space
// allocated; eg: the accessor macro does not need to test if the
// pointer is zero.
//
// Since the array will be less than 5K PRUint16 the "pointers" can
// be implemented as 2 byte offsets from the base instead of
// real pointers.
//
// the format of the CCMap is
// the upper pointers (16 PRUint16)
// the empty mid pointers (16 PRUint16)
// the empty page (16 PRUint16)
// non-empty mid pointers and pages as needed
// 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
#define CCMAP_EMPTY_PAGE CCMAP_EMPTY_MID+CCMAP_NUM_MID_POINTERS
//
// Because the table is offset based the code can build the table in a
// temp space (max table size on the stack) and then do one alloc of
// 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 include an exactly identical basic ccmap in its head,
// basic ccmap operation (HasGlyph) can be applied on extended ccmap without
// problem.
// Because basic ccmap is now have 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
#define CCMAP_BITS_PER_PAGE CCMAP_POW2(CCMAP_BITS_PER_PAGE_LOG2)
#define CCMAP_BIT_INDEX(c) ((c) & PR_BITMASK(CCMAP_BITS_PER_ALU_LOG2))
#define CCMAP_ALU_INDEX(c) (((c)>>CCMAP_BITS_PER_ALU_LOG2) \
& PR_BITMASK(CCMAP_BITS_PER_PAGE_LOG2 - CCMAP_BITS_PER_ALU_LOG2))
#define CCMAP_PAGE_MASK PR_BITMASK(CCMAP_BITS_PER_PAGE_LOG2)
#define CCMAP_NUM_PRUINT16S_PER_PAGE \
(CCMAP_BITS_PER_PAGE/CCMAP_BITS_PER_PRUINT16)
// one bit per char
#define CCMAP_NUM_ALUS_PER_PAGE (CCMAP_BITS_PER_PAGE/CCMAP_BITS_PER_ALU)
#define CCMAP_NUM_UCHARS_PER_PAGE CCMAP_BITS_PER_PAGE
//
// Mid bits
//
#define CCMAP_BITS_PER_MID_LOG2 4
#define CCMAP_MID_INDEX(c) \
(((c)>>CCMAP_BITS_PER_PAGE_LOG2) & PR_BITMASK(CCMAP_BITS_PER_MID_LOG2))
#define CCMAP_NUM_MID_POINTERS CCMAP_POW2(CCMAP_BITS_PER_MID_LOG2)
#define CCMAP_NUM_UCHARS_PER_MID \
CCMAP_POW2(CCMAP_BITS_PER_MID_LOG2+CCMAP_BITS_PER_PAGE_LOG2)
//
// Upper bits
//
#define CCMAP_BITS_PER_UPPER_LOG2 4
#define CCMAP_UPPER_INDEX(c) \
(((c)>>(CCMAP_BITS_PER_MID_LOG2+CCMAP_BITS_PER_PAGE_LOG2)) \
& PR_BITMASK(CCMAP_BITS_PER_UPPER_LOG2))
#define CCMAP_NUM_UPPER_POINTERS CCMAP_POW2(CCMAP_BITS_PER_UPPER_LOG2)
//
// Misc
//
#define CCMAP_BITS_PER_PRUINT16_LOG2 4
#define CCMAP_BITS_PER_PRUINT32_LOG2 5
#define CCMAP_BITS_PER_PRUINT16 CCMAP_POW2(CCMAP_BITS_PER_PRUINT16_LOG2)
#define CCMAP_BITS_PER_PRUINT32 CCMAP_POW2(CCMAP_BITS_PER_PRUINT32_LOG2)
#define CCMAP_BITS_PER_ALU CCMAP_POW2(CCMAP_BITS_PER_ALU_LOG2)
#define CCMAP_ALUS_PER_PRUINT32 (CCMAP_BITS_PER_PRUINT32/CCMAP_BITS_PER_ALU)
#define CCMAP_PRUINT32S_PER_ALU (CCMAP_BITS_PER_ALU/CCMAP_BITS_PER_PRUINT32)
#define CCMAP_PRUINT32S_PER_PAGE (CCMAP_BITS_PER_PAGE/CCMAP_BITS_PER_PRUINT32)
#define CCMAP_ALU_MASK PR_BITMASK(CCMAP_BITS_PER_ALU)
#define CCMAP_ALUS_PER_PAGE CCMAP_POW2(CCMAP_BITS_PER_PAGE_LOG2 \
- CCMAP_BITS_PER_ALU_LOG2)
#define NUM_UNICODE_CHARS CCMAP_POW2(CCMAP_BITS_PER_UPPER_LOG2 \
+CCMAP_BITS_PER_MID_LOG2 \
+CCMAP_BITS_PER_PAGE_LOG2)
#define CCMAP_TOTAL_PAGES CCMAP_POW2(CCMAP_BITS_PER_UPPER_LOG2 \
+CCMAP_BITS_PER_MID_LOG2)
#define CCMAP_BEGIN_AT_START_OF_MAP 0xFFFFFFFF
//
// Finally, build up the macro to test the bit for a given char
//
// offset from base to mid array
#define CCMAP_TO_MID(m,c) ((m)[CCMAP_UPPER_INDEX(c)])
// offset from base to page
#define CCMAP_TO_PAGE(m,c) ((m)[CCMAP_TO_MID((m),(c)) + CCMAP_MID_INDEX(c)])
// offset from base to alu
#define CCMAP_TO_ALU(m,c) \
(*((ALU_TYPE*)(&((m)[CCMAP_TO_PAGE((m),(c))])) + CCMAP_ALU_INDEX(c)))
// test the bit
#define CCMAP_HAS_CHAR(m,c) (((CCMAP_TO_ALU(m,c))>>CCMAP_BIT_INDEX(c)) & 1)
// 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
// get plane number from ccmap, bmp excluded, so plane 1's number is 0.
#define CCMAP_PLANE_FROM_SURROGATE(h) ((((PRUint16)(h) - (PRUint16)0xd800) >> 6) + 1)
// same as above, but get plane number from a ucs4 char
#define CCMAP_PLANE(u) ((((PRUint32)(u))>>16))
// 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)-1])
// test the bit for surrogate pair
#define CCMAP_HAS_CHAR_EXT2(m, h, l) (CCMAP_FLAG(m) & CCMAP_SURROGATE_FLAG && \
CCMAP_HAS_CHAR(CCMAP_FOR_PLANE_EXT((m), CCMAP_PLANE_FROM_SURROGATE(h)), CCMAP_INPLANE_OFFSET(h, l)))
// test the bit for a character in UCS4
#define CCMAP_HAS_CHAR_EXT(m, ucs4) (((ucs4)&0xffff0000) ? \
(CCMAP_FLAG(m) & CCMAP_SURROGATE_FLAG) && CCMAP_HAS_CHAR(CCMAP_FOR_PLANE_EXT((m), CCMAP_PLANE(ucs4)), (ucs4) & 0xffff) : \
CCMAP_HAS_CHAR(m, (PRUnichar)(ucs4)) )
#endif // NSCOMPRESSEDCHARMAP_H

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

@ -1,671 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Stell <bstell@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "prmem.h"
#include "nsCRT.h"
#include "nsICharRepresentable.h"
#include "nsCompressedCharMap.h"
void
FreeCCMap(PRUint16* &aMap)
{
if (!aMap)
return;
PR_Free(aMap - CCMAP_EXTRA);
aMap = nsnull;
}
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;
}
PRUint16* CreateEmptyCCMap()
{
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*
MapperToCCMap(nsICharRepresentable *aMapper)
{
PRUint32 map[UCS2_MAP_LEN];
memset(map, 0, sizeof(map));
nsresult res = aMapper->FillInfo(map);
if (NS_FAILED(res))
return nsnull;
PRUint16* ccMap = MapToCCMap(map);
return ccMap;
}
PRBool
NextNonEmptyCCMapPage(const PRUint16* aCCMap, PRUint32 *aPageStart)
{
int i, j, l;
int planeend = 0;
int planestart = 0;
unsigned int k;
const PRUint16* ccmap;
PRUint32 pagestart = *aPageStart;
if(CCMAP_FLAG(aCCMap) & CCMAP_SURROGATE_FLAG) {
// for SURROGATE
planeend = EXTENDED_UNICODE_PLANES;
}
if(pagestart != CCMAP_BEGIN_AT_START_OF_MAP) {
planestart = CCMAP_PLANE(pagestart);
}
// checking each plane
for(l=planestart; l<=planeend; l++, pagestart = CCMAP_BEGIN_AT_START_OF_MAP) {
if(l != 0 && CCMAP_FLAG(aCCMap) & CCMAP_SURROGATE_FLAG) {
// for SURROGATE - get ccmap per plane
ccmap = CCMAP_FOR_PLANE_EXT(aCCMap, l);
} else {
// only BMP
ccmap = aCCMap;
}
//
// Point to the next page
//
unsigned int upper_index;
unsigned int mid_index;
if (pagestart == CCMAP_BEGIN_AT_START_OF_MAP) {
upper_index = 0;
mid_index = 0;
} else {
upper_index = CCMAP_UPPER_INDEX(pagestart & 0xffff);
mid_index = CCMAP_MID_INDEX(pagestart & 0xffff) + 1;
}
// walk thru the upper pointers
const PRUint16 *upper = &ccmap[0];
for (i=upper_index; i<CCMAP_NUM_UPPER_POINTERS; i++, mid_index=0) {
if (upper[i] == CCMAP_EMPTY_MID) {
continue;
}
// walk the mid array
const PRUint16 *mid = &ccmap[upper[i]];
for (j=mid_index; j<CCMAP_NUM_MID_POINTERS; j++) {
if (mid[j] == CCMAP_EMPTY_PAGE)
continue;
// walk the page
const ALU_TYPE *page = (ALU_TYPE*)&ccmap[mid[j]];
for (k=0; k<CCMAP_NUM_ALUS_PER_PAGE; k++) {
if (page[k] != 0) {
PRUint32 base = (i*CCMAP_NUM_UCHARS_PER_MID) + (j*CCMAP_NUM_UCHARS_PER_PAGE);
NS_ASSERTION(base<NUM_UNICODE_CHARS, "invalid page address");
// return exact UCS4 code point, plane number + base
*aPageStart = (((PRUint32)l)<<16)+base;
return PR_TRUE;
}
}
}
}
}
return PR_FALSE;
}
#define CCMAP_MID_OFFSET(m, i) ((m)[i])
#define CCMAP_PAGE_OFFSET_FROM_MIDOFFSET(m, midoffset, i) ((m)[(i) + (midoffset)])
/***********************************************************************************
*compare 2 ccmap and see if they are exactly the same
* Here I assume both ccmap is generated by
* nsCompressedCharMap::SetChars(PRUint32* aMap)
* This funtion rely on current implementation of above function. The that changed,
* we might need to revisit this implementation.
***********************************************************************************/
PRBool IsSameCCMap(PRUint16* ccmap1, PRUint16* ccmap2)
{
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;
}
PRUint16*
nsCompressedCharMap::NewCCMap()
{
if (mExtended) {
return MapToCCMapExt(mMap, mExtMap+1, EXTENDED_UNICODE_PLANES);
} else {
PRUint16 *newMap = (PRUint16*)PR_Malloc((CCMAP_EXTRA + mUsedLen) * sizeof(PRUint16));
NS_ASSERTION(newMap, "failed to alloc new CCMap");
if (!newMap)
return nsnull;
newMap += CCMAP_EXTRA;
CCMAP_SIZE(newMap) = GetSize();
CCMAP_FLAG(newMap) = CCMAP_NONE_FLAG;
FillCCMap(newMap);
return newMap;
}
}
PRUint16*
nsCompressedCharMap::FillCCMap(PRUint16* aCCMap)
{
// transfer the data
for (int i=0; i<mUsedLen; i++)
aCCMap[i] = u.mCCMap[i];
return aCCMap;
}
nsCompressedCharMap::~nsCompressedCharMap()
{
if(mExtended){
int i;
for (i = 1; i <= EXTENDED_UNICODE_PLANES; ++i) {
if (mExtMap[i]) {
PR_Free(mExtMap[i]);
}
}
}
}
nsCompressedCharMap::nsCompressedCharMap()
{
// initialize map to have:
// 1 upper pointer array
// 1 empty mid pointer array
// 1 empty page
int i;
memset(u.mCCMap, 0, sizeof(u.mCCMap));
mUsedLen = 0;
mAllOnesPage = 0;
// init the upper pointers
PRUint16 *upper = &u.mCCMap[0];
for (i=0; i<CCMAP_NUM_UPPER_POINTERS; i++) {
upper[i] = CCMAP_EMPTY_MID;
}
mUsedLen += CCMAP_NUM_UPPER_POINTERS;
// init the empty mid
NS_ASSERTION(mUsedLen==CCMAP_EMPTY_MID, "empty mid offset misconfigured");
PRUint16 *mid = &u.mCCMap[CCMAP_EMPTY_MID];
for (i=0; i<CCMAP_NUM_MID_POINTERS; i++) {
mid[i] = CCMAP_EMPTY_PAGE;
}
mUsedLen += CCMAP_NUM_MID_POINTERS;
// init the empty page
NS_ASSERTION(mUsedLen==CCMAP_EMPTY_PAGE, "empty page offset misconfigured");
// the page was zero'd by the memset above
mUsedLen += CCMAP_NUM_PRUINT16S_PER_PAGE;
// init extended
mExtended = PR_FALSE;
memset(mExtMap+1, 0, sizeof(PRUint32*) * EXTENDED_UNICODE_PLANES);
memset(mMap, 0, sizeof(mMap));
mExtMap[0] = mMap;
}
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");
}
}
void
nsCompressedCharMap::SetChars(PRUint16 aBase, ALU_TYPE* aPage)
{
unsigned int i;
unsigned int upper_index = CCMAP_UPPER_INDEX(aBase);
unsigned int mid_index = CCMAP_MID_INDEX(aBase);
NS_ASSERTION((aBase&CCMAP_PAGE_MASK)==0, "invalid page address");
//
// check of none/all bits set
//
PRUint16 num_none_set = 0;
PRUint16 num_all_set = 0;
for (i=0; i<CCMAP_NUM_ALUS_PER_PAGE; i++) {
if (aPage[i] == 0)
num_none_set++;
else if (aPage[i] == CCMAP_ALU_MASK)
num_all_set++;
}
if (num_none_set == CCMAP_NUM_ALUS_PER_PAGE) {
return;
}
//
// Alloc mid if necessary
//
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;
}
}
//
// if all bits set share an "all bits set" page
//
if (num_all_set == CCMAP_NUM_ALUS_PER_PAGE) {
if (mAllOnesPage == 0) {
mAllOnesPage = mUsedLen;
mUsedLen += CCMAP_NUM_PRUINT16S_PER_PAGE;
NS_ASSERTION(mUsedLen<=CCMAP_MAX_LEN,"length too long");
ALU_TYPE *all_ones_page = (ALU_TYPE*)&u.mCCMap[mAllOnesPage];
for (i=0; i<CCMAP_NUM_ALUS_PER_PAGE; i++) {
NS_ASSERTION(all_ones_page[i]==0, "this page should be unused");
all_ones_page[i] = CCMAP_ALU_MASK;
}
}
u.mCCMap[mid_offset+mid_index] = mAllOnesPage;
return;
}
//
// Alloc page if necessary
//
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");
}
// copy the page data
ALU_TYPE *page = (ALU_TYPE*)&u.mCCMap[page_offset];
for (i=0; i<CCMAP_NUM_ALUS_PER_PAGE; i++) {
NS_ASSERTION(page[i]==0, "this page should be unused");
page[i] = aPage[i];
}
}
void
nsCompressedCharMap::SetChars(PRUint16* aCCMap)
{
int i, j;
if(mExtended){
PRUint32 page = CCMAP_BEGIN_AT_START_OF_MAP;
while (NextNonEmptyCCMapPage(aCCMap, &page)) {
PRUint32 pagechar = page;
for (i=0; i<(CCMAP_BITS_PER_PAGE/8); i++) {
for (j=0; j<8; j++) {
if (CCMAP_HAS_CHAR_EXT(aCCMap, pagechar)) {
SetChar(pagechar);
}
pagechar++;
}
}
}
} else {
//
// Copy the input CCMap
//
// walk thru the upper pointers
PRUint16 *upper = &aCCMap[0];
for (i=0; i<CCMAP_NUM_UPPER_POINTERS; i++) {
if (upper[i] == CCMAP_EMPTY_MID)
continue;
// walk the mid array
PRUint16 *mid = &aCCMap[upper[i]];
for (j=0; j<CCMAP_NUM_MID_POINTERS; j++) {
if (mid[j] == CCMAP_EMPTY_PAGE)
continue;
PRUint32 base = (i*CCMAP_NUM_UCHARS_PER_MID) + (j*CCMAP_NUM_UCHARS_PER_PAGE);
NS_ASSERTION(base<NUM_UNICODE_CHARS, "invalid page address");
ALU_TYPE *page = (ALU_TYPE*)&aCCMap[mid[j]];
SetChars((PRUint16)base, page);
}
}
}
}
void
nsCompressedCharMap::SetChars(PRUint32* aMap)
{
PRUint32* frommap_page;
frommap_page = aMap;
PRUint16 base = 0;
for (int i=0; i<CCMAP_TOTAL_PAGES; i++) {
#if (CCMAP_BITS_PER_ALU == CCMAP_BITS_PER_PRUINT32)
SetChars(base, (ALU_TYPE*)frommap_page);
frommap_page += CCMAP_PRUINT32S_PER_PAGE;
#elif (CCMAP_BITS_PER_ALU > CCMAP_BITS_PER_PRUINT32)
int j, k = CCMAP_BITS_PER_PRUINT32;
ALU_TYPE page[CCMAP_NUM_ALUS_PER_PAGE];
ALU_TYPE *p = page;
for (j=0; j<CCMAP_ALUS_PER_PAGE; j++) {
ALU_TYPE alu_val = 0;
ALU_TYPE tmp;
for (k=0; k<CCMAP_PRUINT32S_PER_ALU; k++) {
tmp = *frommap_page;
tmp <<= (k*CCMAP_BITS_PER_PRUINT32);
//alu_val |= (*frommap_page)<<(k*CCMAP_BITS_PER_PRUINT32);
alu_val |= tmp;
frommap_page++;
}
*p++ = alu_val;
}
SetChars(base, page);
#elif (CCMAP_BITS_PER_ALU < CCMAP_BITS_PER_PRUINT32)
int j, k;
ALU_TYPE page[CCMAP_NUM_ALUS_PER_PAGE];
int v = CCMAP_PRUINT32S_PER_PAGE;
ALU_TYPE *p = page;
for (j=0; j<CCMAP_PRUINT32S_PER_PAGE; j++) {
PRUint32 pruint32_val = *frommap_page++;
for (k=0; k<CCMAP_ALUS_PER_PRUINT32; k++) {
*p++ = pruint32_val & CCMAP_ALU_MASK;
pruint32_val >>= CCMAP_BITS_PER_ALU;
}
}
SetChars(base, page);
#endif
base += CCMAP_NUM_UCHARS_PER_PAGE;
}
}
#ifdef DEBUG
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");
}
}
#endif
// Non-BMP unicode support extension, create ccmap for both BMP and extended planes
PRUint16*
MapToCCMapExt(PRUint32* aBmpPlaneMap, PRUint32** aOtherPlaneMaps, PRUint32 aOtherPlaneNum)
{
nsCompressedCharMap* otherPlaneObj[EXTENDED_UNICODE_PLANES];
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] = new nsCompressedCharMap();
NS_ASSERTION(otherPlaneObj, "unable to create new nsCompressedCharMap");
if(otherPlaneObj) {
otherPlaneObj[i]->SetChars(aOtherPlaneMaps[i]);
totalSize += otherPlaneObj[i]->GetSize();
}
} else {
otherPlaneObj[i] = nsnull;
}
}
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] && otherPlaneObj[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;
}
// remove all nsCompressedCharMap objects allocated
for (i = 0; i < aOtherPlaneNum; i++) {
if (otherPlaneObj[i])
delete otherPlaneObj[i];
}
#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_EXT(ccmap, k);
NS_ASSERTION(oldb==newb,"failed to generate map correctly");
}
//testing for extension plane
for (k = 0x10000; k < 0x100000; k++) {
plane = k/0x10000;
if (plane > aOtherPlaneNum)
break;
if (aOtherPlaneMaps[plane-1])
oldb = IS_REPRESENTABLE(aOtherPlaneMaps[plane-1], k&0xffff);
else
oldb = 0;
newb = CCMAP_HAS_CHAR_EXT(ccmap, k);
NS_ASSERTION(oldb==newb, "failed to generate extension 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;
if (aOtherPlaneMaps[plane])
oldb = IS_REPRESENTABLE(aOtherPlaneMaps[plane], offset);
else
oldb = 0;
newb = CCMAP_HAS_CHAR_EXT2(ccmap, h+0xd800, l+0xdc00);
NS_ASSERTION(oldb==newb, "failed to generate extension map correctly");
}
}
#endif
return ccmap;
}

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

@ -1,592 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Stell <bstell@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "prmem.h"
#include "nsCompressedCharMap.h"
#include "nsCRT.h"
#include "nsICharRepresentable.h"
void
FreeCCMap(PRUint16* &aMap)
{
if (!aMap)
return;
PR_Free(aMap - CCMAP_EXTRA);
aMap = nsnull;
}
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;
}
PRUint16* CreateEmptyCCMap()
{
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*
MapperToCCMap(nsICharRepresentable *aMapper)
{
PRUint32 map[UCS2_MAP_LEN];
memset(map, 0, sizeof(map));
nsresult res = aMapper->FillInfo(map);
if (NS_FAILED(res))
return nsnull;
PRUint16* ccMap = MapToCCMap(map);
return ccMap;
}
PRBool
NextNonEmptyCCMapPage(PRUint16* aCCMap, PRUint16 *aPageStart)
{
int i, j;
unsigned int k;
//
// Point to the next page
//
unsigned int upper_index;
unsigned int mid_index;
if (*aPageStart == CCMAP_BEGIN_AT_START_OF_MAP) {
upper_index = 0;
mid_index = 0;
}
else {
upper_index = CCMAP_UPPER_INDEX(*aPageStart);
mid_index = CCMAP_MID_INDEX(*aPageStart) + 1;
}
// walk thru the upper pointers
PRUint16 *upper = &aCCMap[0];
for (i=upper_index; i<CCMAP_NUM_UPPER_POINTERS; i++, mid_index=0) {
if (upper[i] == CCMAP_EMPTY_MID) {
continue;
}
// walk the mid array
PRUint16 *mid = &aCCMap[upper[i]];
for (j=mid_index; j<CCMAP_NUM_MID_POINTERS; j++) {
if (mid[j] == CCMAP_EMPTY_PAGE)
continue;
// walk the page
ALU_TYPE *page = (ALU_TYPE*)&aCCMap[mid[j]];
for (k=0; k<CCMAP_NUM_ALUS_PER_PAGE; k++) {
if (page[k] != 0) {
PRUint32 base = (i*CCMAP_NUM_UCHARS_PER_MID) + (j*CCMAP_NUM_UCHARS_PER_PAGE);
NS_ASSERTION(base<NUM_UNICODE_CHARS, "invalid page address");
*aPageStart = (PRUint16)base;
return PR_TRUE;
}
}
}
}
return PR_FALSE;
}
#define CCMAP_MID_OFFSET(m, i) ((m)[i])
#define CCMAP_PAGE_OFFSET_FROM_MIDOFFSET(m, midoffset, i) ((m)[(i) + (midoffset)])
/***********************************************************************************
*compare 2 ccmap and see if they are exactly the same
* Here I assume both ccmap is generated by
* nsCompressedCharMap::SetChars(PRUint32* aMap)
* This funtion rely on current implementation of above function. The that changed,
* we might need to revisit this implementation.
***********************************************************************************/
PRBool IsSameCCMap(PRUint16* ccmap1, PRUint16* ccmap2)
{
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;
}
PRUint16*
nsCompressedCharMap::NewCCMap()
{
PRUint16 *newMap = (PRUint16*)PR_Malloc((CCMAP_EXTRA + mUsedLen) * sizeof(PRUint16));
NS_ASSERTION(newMap, "failed to alloc new CCMap");
if (!newMap)
return nsnull;
newMap += CCMAP_EXTRA;
CCMAP_SIZE(newMap) = GetSize();
CCMAP_FLAG(newMap) = CCMAP_NONE_FLAG;
FillCCMap(newMap);
return newMap;
}
PRUint16*
nsCompressedCharMap::FillCCMap(PRUint16* aCCMap)
{
// transfer the data
for (int i=0; i<mUsedLen; i++)
aCCMap[i] = u.mCCMap[i];
return aCCMap;
}
nsCompressedCharMap::nsCompressedCharMap()
{
// initialize map to have:
// 1 upper pointer array
// 1 empty mid pointer array
// 1 empty page
int i;
memset(u.mCCMap, 0, sizeof(u.mCCMap));
mUsedLen = 0;
mAllOnesPage = 0;
// init the upper pointers
PRUint16 *upper = &u.mCCMap[0];
for (i=0; i<CCMAP_NUM_UPPER_POINTERS; i++) {
upper[i] = CCMAP_EMPTY_MID;
}
mUsedLen += CCMAP_NUM_UPPER_POINTERS;
// init the empty mid
NS_ASSERTION(mUsedLen==CCMAP_EMPTY_MID, "empty mid offset misconfigured");
PRUint16 *mid = &u.mCCMap[CCMAP_EMPTY_MID];
for (i=0; i<CCMAP_NUM_MID_POINTERS; i++) {
mid[i] = CCMAP_EMPTY_PAGE;
}
mUsedLen += CCMAP_NUM_MID_POINTERS;
// init the empty page
NS_ASSERTION(mUsedLen==CCMAP_EMPTY_PAGE, "empty page offset misconfigured");
// the page was zero'd by the memset above
mUsedLen += CCMAP_NUM_PRUINT16S_PER_PAGE;
}
void
nsCompressedCharMap::SetChar(PRUint16 aChar)
{
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");
}
void
nsCompressedCharMap::SetChars(PRUint16 aBase, ALU_TYPE* aPage)
{
unsigned int i;
unsigned int upper_index = CCMAP_UPPER_INDEX(aBase);
unsigned int mid_index = CCMAP_MID_INDEX(aBase);
NS_ASSERTION((aBase&CCMAP_PAGE_MASK)==0, "invalid page address");
//
// check of none/all bits set
//
PRUint16 num_none_set = 0;
PRUint16 num_all_set = 0;
for (i=0; i<CCMAP_NUM_ALUS_PER_PAGE; i++) {
if (aPage[i] == 0)
num_none_set++;
else if (aPage[i] == CCMAP_ALU_MASK)
num_all_set++;
}
if (num_none_set == CCMAP_NUM_ALUS_PER_PAGE) {
return;
}
//
// Alloc mid if necessary
//
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;
}
}
//
// if all bits set share an "all bits set" page
//
if (num_all_set == CCMAP_NUM_ALUS_PER_PAGE) {
if (mAllOnesPage == 0) {
mAllOnesPage = mUsedLen;
mUsedLen += CCMAP_NUM_PRUINT16S_PER_PAGE;
NS_ASSERTION(mUsedLen<=CCMAP_MAX_LEN,"length too long");
ALU_TYPE *all_ones_page = (ALU_TYPE*)&u.mCCMap[mAllOnesPage];
for (i=0; i<CCMAP_NUM_ALUS_PER_PAGE; i++) {
NS_ASSERTION(all_ones_page[i]==0, "this page should be unused");
all_ones_page[i] = CCMAP_ALU_MASK;
}
}
u.mCCMap[mid_offset+mid_index] = mAllOnesPage;
return;
}
//
// Alloc page if necessary
//
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");
}
// copy the page data
ALU_TYPE *page = (ALU_TYPE*)&u.mCCMap[page_offset];
for (i=0; i<CCMAP_NUM_ALUS_PER_PAGE; i++) {
NS_ASSERTION(page[i]==0, "this page should be unused");
page[i] = aPage[i];
}
}
void
nsCompressedCharMap::SetChars(PRUint16* aCCMap)
{
int i, j;
//
// Copy the input CCMap
//
// walk thru the upper pointers
PRUint16 *upper = &aCCMap[0];
for (i=0; i<CCMAP_NUM_UPPER_POINTERS; i++) {
if (upper[i] == CCMAP_EMPTY_MID)
continue;
// walk the mid array
PRUint16 *mid = &aCCMap[upper[i]];
for (j=0; j<CCMAP_NUM_MID_POINTERS; j++) {
if (mid[j] == CCMAP_EMPTY_PAGE)
continue;
PRUint32 base = (i*CCMAP_NUM_UCHARS_PER_MID) + (j*CCMAP_NUM_UCHARS_PER_PAGE);
NS_ASSERTION(base<NUM_UNICODE_CHARS, "invalid page address");
ALU_TYPE *page = (ALU_TYPE*)&aCCMap[mid[j]];
SetChars((PRUint16)base, page);
}
}
}
void
nsCompressedCharMap::SetChars(PRUint32* aMap)
{
PRUint32* frommap_page;
frommap_page = aMap;
PRUint16 base = 0;
for (int i=0; i<CCMAP_TOTAL_PAGES; i++) {
#if (CCMAP_BITS_PER_ALU == CCMAP_BITS_PER_PRUINT32)
SetChars(base, (ALU_TYPE*)frommap_page);
frommap_page += CCMAP_PRUINT32S_PER_PAGE;
#elif (CCMAP_BITS_PER_ALU > CCMAP_BITS_PER_PRUINT32)
int j, k = CCMAP_BITS_PER_PRUINT32;
ALU_TYPE page[CCMAP_NUM_ALUS_PER_PAGE];
ALU_TYPE *p = page;
for (j=0; j<CCMAP_ALUS_PER_PAGE; j++) {
ALU_TYPE alu_val = 0;
ALU_TYPE tmp;
for (k=0; k<CCMAP_PRUINT32S_PER_ALU; k++) {
tmp = *frommap_page;
tmp <<= (k*CCMAP_BITS_PER_PRUINT32);
//alu_val |= (*frommap_page)<<(k*CCMAP_BITS_PER_PRUINT32);
alu_val |= tmp;
frommap_page++;
}
*p++ = alu_val;
}
SetChars(base, page);
#elif (CCMAP_BITS_PER_ALU < CCMAP_BITS_PER_PRUINT32)
int j, k;
ALU_TYPE page[CCMAP_NUM_ALUS_PER_PAGE];
int v = CCMAP_PRUINT32S_PER_PAGE;
ALU_TYPE *p = page;
for (j=0; j<CCMAP_PRUINT32S_PER_PAGE; j++) {
PRUint32 pruint32_val = *frommap_page++;
for (k=0; k<CCMAP_ALUS_PER_PRUINT32; k++) {
*p++ = pruint32_val & CCMAP_ALU_MASK;
pruint32_val >>= CCMAP_BITS_PER_ALU;
}
}
SetChars(base, page);
#endif
base += CCMAP_NUM_UCHARS_PER_PAGE;
}
}
#ifdef DEBUG
void
printCCMap(PRUint16* aCCMap)
{
PRUint16 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");
}
}
#endif
// Non-BMP unicode support extension, create ccmap for both BMP and extended planes
PRUint16*
MapToCCMapExt(PRUint32* aBmpPlaneMap, PRUint32** aOtherPlaneMaps, PRUint32 aOtherPlaneNum)
{
nsCompressedCharMap* otherPlaneObj[EXTENDED_UNICODE_PLANES];
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] = new nsCompressedCharMap();
NS_ASSERTION(otherPlaneObj, "unable to create new nsCompressedCharMap");
if(otherPlaneObj) {
otherPlaneObj[i]->SetChars(aOtherPlaneMaps[i]);
totalSize += otherPlaneObj[i]->GetSize();
}
} else {
otherPlaneObj[i] = nsnull;
}
}
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] && otherPlaneObj[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;
}
// remove all nsCompressedCharMap objects allocated
for (i = 0; i < aOtherPlaneNum; i++) {
if (otherPlaneObj[i])
delete otherPlaneObj[i];
}
#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_EXT(ccmap, k);
NS_ASSERTION(oldb==newb,"failed to generate map correctly");
}
//testing for extension plane
for (k = 0x10000; k < 0x100000; k++) {
plane = k/0x10000;
if (plane > aOtherPlaneNum)
break;
if (aOtherPlaneMaps[plane-1])
oldb = IS_REPRESENTABLE(aOtherPlaneMaps[plane-1], k&0xffff);
else
oldb = 0;
newb = CCMAP_HAS_CHAR_EXT(ccmap, k);
NS_ASSERTION(oldb==newb, "failed to generate extension 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;
if (aOtherPlaneMaps[plane])
oldb = IS_REPRESENTABLE(aOtherPlaneMaps[plane], offset);
else
oldb = 0;
newb = CCMAP_HAS_CHAR_EXT2(ccmap, h+0xd800, l+0xdc00);
NS_ASSERTION(oldb==newb, "failed to generate extension map correctly");
}
}
#endif
return ccmap;
}

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

@ -1,355 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Stell <bstell@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef NSCOMPRESSEDCHARMAP_H
#define NSCOMPRESSEDCHARMAP_H
#include "prtypes.h"
#include "nsICharRepresentable.h"
#define ALU_SIZE PR_BITS_PER_LONG
//#define ALU_SIZE 16
//#define ALU_SIZE 32
//#define ALU_SIZE 64
#if (ALU_SIZE==32)
# define ALU_TYPE PRUint32
# define CCMAP_POW2(n) (1L<<(n))
# define CCMAP_BITS_PER_ALU_LOG2 5
#elif (ALU_SIZE==64)
# define ALU_TYPE PRUint64
# define CCMAP_POW2(n) (1L<<(n))
# define CCMAP_BITS_PER_ALU_LOG2 6
#else
# define ALU_TYPE PRUint16
# define CCMAP_POW2(n) (1<<(n))
# define CCMAP_BITS_PER_ALU_LOG2 4
#endif
class nsICharRepresentable;
extern PRUint16* CreateEmptyCCMap();
extern PRUint16* MapToCCMap(PRUint32* aMap);
extern PRUint16* MapperToCCMap(nsICharRepresentable *aMapper);
extern void FreeCCMap(PRUint16* &aMap);
extern PRBool NextNonEmptyCCMapPage(const PRUint16 *, PRUint32 *);
extern PRBool IsSameCCMap(PRUint16* ccmap1, PRUint16* ccmap2);
#ifdef DEBUG
void printCCMap(PRUint16* aCCMap);
#endif
// surrogate support extension
extern PRUint16*
MapToCCMapExt(PRUint32* aBmpPlaneMap, PRUint32** aOtherPlaneMaps, PRUint32 aOtherPlaneNum);
//
// nsCompressedCharMap
//
// A Compressed Char Map (CCMap) saves memory by folding all
// the empty portions of the map on top of each other.
//
// Building a Compressed Char Map (CCMap) is more complex than
// accessing it. We use the nsCompressedCharMap object to
// build the CCMap. Once nsCompressedCharMap has built the CCMap
// we get a copy of the CCMap and discard the nsCompressedCharMap
// object. The CCMap is an array of PRUint16 and is accessed by
// a macro.
//
// See "Character Map Compression" below for a discussion of
// what the array looks like.
//
// The maximum size a CCMap:
// (16 upper pointers) + (16 empty mid pointers) +
// (16 empty page) + (16*16 max mid pointers) +
// (256*16 max pages) = 4400 PRUint16
#define CCMAP_MAX_LEN (16+16+16+256+4096)
// non-bmp unicode support extension
#define EXTENDED_UNICODE_PLANES 16
class nsCompressedCharMap {
public:
nsCompressedCharMap();
~nsCompressedCharMap();
PRUint16* NewCCMap();
PRUint16* FillCCMap(PRUint16* aCCMap);
PRUint16 GetSize() {return mUsedLen;};
void SetChar(PRUint32);
void SetChars(PRUint16*);
void SetChars(PRUint16, ALU_TYPE*);
void SetChars(PRUint32*);
void Extend() {mExtended = PR_TRUE;} // enable surrogate area
protected:
union {
PRUint16 mCCMap[CCMAP_MAX_LEN];
ALU_TYPE used_for_align; // do not use; only here to cause
// alignment
} u;
PRUint16 mUsedLen; // in PRUint16
PRUint16 mAllOnesPage;
PRBool mExtended;
// for surrogate support
PRUint32* mExtMap[EXTENDED_UNICODE_PLANES+1];
PRUint32 mMap[UCS2_MAP_LEN];
};
//
// Character Map Compression
//
// Each font requires its own 8k charmap. On a system with 200
// fonts this would take: 200 * 8K = 1600K memory.
//
// Since most char maps are mostly empty a significant amount
// of memory can be saved by not allocating the unused sections.
//
// If the map has one or more levels of indirection then the
// the empty sections of the map can all be folded to a single
// common empty element. In this way only the non-empty sections
// need space. Because the empty sections actually point to a
// common empty section every entry in the map can be valid
// without requiring actually allocating space.
// Some larger CJK fonts have large sections where every bit
// is set. In the same way that the empty sections are folded
// onto one "empty page", the sections where all bits are set are
// folded on to one "all bits set page" .
//
// Break up the Unicode range bits 0x0000 - 0xFFFF
// into 3 bit ranges:
//
// upper bits: bit15 - bit12
// mid bits: bit11 - bit8
// page bits: bit7 - bit0
//
// within a page, (assumming a 4 byte ALU)
// bits 7-5 select one of the 8 longs
// bits 4-0 select one of the 32 bits within the long
//
// There is exactly one upper "pointers" array.
//
// The upper pointers each point to a mid array. If there are no chars
// in an upper pointer's block that pointer points to the empty mid.
// Thus all upper pointers are "valid" even if they do not have space
// allocated; eg: the accessor macro does not need to test if the
// pointer is zero.
//
// Each mid pointer in the mid array points to a page. If there are no
// chars in a mid pointer's page that pointer points to the empty page.
// Thus all mid pointers are "valid" even if they do not have space
// allocated; eg: the accessor macro does not need to test if the
// pointer is zero.
//
// Since the array will be less than 5K PRUint16 the "pointers" can
// be implemented as 2 byte offsets from the base instead of
// real pointers.
//
// the format of the CCMap is
// the upper pointers (16 PRUint16)
// the empty mid pointers (16 PRUint16)
// the empty page (16 PRUint16)
// non-empty mid pointers and pages as needed
// 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
#define CCMAP_EMPTY_PAGE CCMAP_EMPTY_MID+CCMAP_NUM_MID_POINTERS
//
// Because the table is offset based the code can build the table in a
// temp space (max table size on the stack) and then do one alloc of
// 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 include an exactly identical basic ccmap in its head,
// basic ccmap operation (HasGlyph) can be applied on extended ccmap without
// problem.
// Because basic ccmap is now have 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
#define CCMAP_BITS_PER_PAGE CCMAP_POW2(CCMAP_BITS_PER_PAGE_LOG2)
#define CCMAP_BIT_INDEX(c) ((c) & PR_BITMASK(CCMAP_BITS_PER_ALU_LOG2))
#define CCMAP_ALU_INDEX(c) (((c)>>CCMAP_BITS_PER_ALU_LOG2) \
& PR_BITMASK(CCMAP_BITS_PER_PAGE_LOG2 - CCMAP_BITS_PER_ALU_LOG2))
#define CCMAP_PAGE_MASK PR_BITMASK(CCMAP_BITS_PER_PAGE_LOG2)
#define CCMAP_NUM_PRUINT16S_PER_PAGE \
(CCMAP_BITS_PER_PAGE/CCMAP_BITS_PER_PRUINT16)
// one bit per char
#define CCMAP_NUM_ALUS_PER_PAGE (CCMAP_BITS_PER_PAGE/CCMAP_BITS_PER_ALU)
#define CCMAP_NUM_UCHARS_PER_PAGE CCMAP_BITS_PER_PAGE
//
// Mid bits
//
#define CCMAP_BITS_PER_MID_LOG2 4
#define CCMAP_MID_INDEX(c) \
(((c)>>CCMAP_BITS_PER_PAGE_LOG2) & PR_BITMASK(CCMAP_BITS_PER_MID_LOG2))
#define CCMAP_NUM_MID_POINTERS CCMAP_POW2(CCMAP_BITS_PER_MID_LOG2)
#define CCMAP_NUM_UCHARS_PER_MID \
CCMAP_POW2(CCMAP_BITS_PER_MID_LOG2+CCMAP_BITS_PER_PAGE_LOG2)
//
// Upper bits
//
#define CCMAP_BITS_PER_UPPER_LOG2 4
#define CCMAP_UPPER_INDEX(c) \
(((c)>>(CCMAP_BITS_PER_MID_LOG2+CCMAP_BITS_PER_PAGE_LOG2)) \
& PR_BITMASK(CCMAP_BITS_PER_UPPER_LOG2))
#define CCMAP_NUM_UPPER_POINTERS CCMAP_POW2(CCMAP_BITS_PER_UPPER_LOG2)
//
// Misc
//
#define CCMAP_BITS_PER_PRUINT16_LOG2 4
#define CCMAP_BITS_PER_PRUINT32_LOG2 5
#define CCMAP_BITS_PER_PRUINT16 CCMAP_POW2(CCMAP_BITS_PER_PRUINT16_LOG2)
#define CCMAP_BITS_PER_PRUINT32 CCMAP_POW2(CCMAP_BITS_PER_PRUINT32_LOG2)
#define CCMAP_BITS_PER_ALU CCMAP_POW2(CCMAP_BITS_PER_ALU_LOG2)
#define CCMAP_ALUS_PER_PRUINT32 (CCMAP_BITS_PER_PRUINT32/CCMAP_BITS_PER_ALU)
#define CCMAP_PRUINT32S_PER_ALU (CCMAP_BITS_PER_ALU/CCMAP_BITS_PER_PRUINT32)
#define CCMAP_PRUINT32S_PER_PAGE (CCMAP_BITS_PER_PAGE/CCMAP_BITS_PER_PRUINT32)
#define CCMAP_ALU_MASK PR_BITMASK(CCMAP_BITS_PER_ALU)
#define CCMAP_ALUS_PER_PAGE CCMAP_POW2(CCMAP_BITS_PER_PAGE_LOG2 \
- CCMAP_BITS_PER_ALU_LOG2)
#define NUM_UNICODE_CHARS CCMAP_POW2(CCMAP_BITS_PER_UPPER_LOG2 \
+CCMAP_BITS_PER_MID_LOG2 \
+CCMAP_BITS_PER_PAGE_LOG2)
#define CCMAP_TOTAL_PAGES CCMAP_POW2(CCMAP_BITS_PER_UPPER_LOG2 \
+CCMAP_BITS_PER_MID_LOG2)
#define CCMAP_BEGIN_AT_START_OF_MAP 0xFFFFFFFF
//
// Finally, build up the macro to test the bit for a given char
//
// offset from base to mid array
#define CCMAP_TO_MID(m,c) ((m)[CCMAP_UPPER_INDEX(c)])
// offset from base to page
#define CCMAP_TO_PAGE(m,c) ((m)[CCMAP_TO_MID((m),(c)) + CCMAP_MID_INDEX(c)])
// offset from base to alu
#define CCMAP_TO_ALU(m,c) \
(*((ALU_TYPE*)(&((m)[CCMAP_TO_PAGE((m),(c))])) + CCMAP_ALU_INDEX(c)))
// test the bit
#define CCMAP_HAS_CHAR(m,c) (((CCMAP_TO_ALU(m,c))>>CCMAP_BIT_INDEX(c)) & 1)
// 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
// get plane number from ccmap, bmp excluded, so plane 1's number is 0.
#define CCMAP_PLANE_FROM_SURROGATE(h) ((((PRUint16)(h) - (PRUint16)0xd800) >> 6) + 1)
// same as above, but get plane number from a ucs4 char
#define CCMAP_PLANE(u) ((((PRUint32)(u))>>16))
// 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)-1])
// test the bit for surrogate pair
#define CCMAP_HAS_CHAR_EXT2(m, h, l) (CCMAP_FLAG(m) & CCMAP_SURROGATE_FLAG && \
CCMAP_HAS_CHAR(CCMAP_FOR_PLANE_EXT((m), CCMAP_PLANE_FROM_SURROGATE(h)), CCMAP_INPLANE_OFFSET(h, l)))
// test the bit for a character in UCS4
#define CCMAP_HAS_CHAR_EXT(m, ucs4) (((ucs4)&0xffff0000) ? \
(CCMAP_FLAG(m) & CCMAP_SURROGATE_FLAG) && CCMAP_HAS_CHAR(CCMAP_FOR_PLANE_EXT((m), CCMAP_PLANE(ucs4)), (ucs4) & 0xffff) : \
CCMAP_HAS_CHAR(m, (PRUnichar)(ucs4)) )
#endif // NSCOMPRESSEDCHARMAP_H