Back to index

lightning-sunbird  0.9+nobinonly
nsUnicodeFontMappingMac.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include <Script.h>
00039 #include "nsDeviceContextMac.h"
00040 #include "plhash.h"
00041 #include "nsCRT.h"
00042 
00043 #include "nsUnicodeFontMappingMac.h"
00044 #include "nsUnicodeFontMappingCache.h"
00045 #include "nsUnicodeMappingUtil.h"
00046 #include "nsIUnicodeEncoder.h"
00047 #include "nsCompressedCharMap.h"
00048 #include "nsMacUnicodeFontInfo.h"
00049 
00050 #include <UnicodeConverter.h>
00051 
00052 //------------------------------------------------------------------------
00053 #include "ignorable.x-ccmap"
00054 DEFINE_X_CCMAP(gIgnorableCCMapExt, /* nothing */);
00055 
00056 //------------------------------------------------------------------------
00057 static UnicodeToTextInfo gConverters[32] = { 
00058        nsnull, nsnull, nsnull, nsnull, nsnull, nsnull, nsnull, nsnull,
00059        nsnull, nsnull, nsnull, nsnull, nsnull, nsnull, nsnull, nsnull,
00060        nsnull, nsnull, nsnull, nsnull, nsnull, nsnull, nsnull, nsnull,
00061        nsnull, nsnull, nsnull, nsnull, nsnull, nsnull, nsnull, nsnull
00062 };
00063 //------------------------------------------------------------------------
00064 static UnicodeToTextInfo
00065 GetConverterByScript(ScriptCode sc)
00066 {
00067   // because the Mac QuickDraw BIDI support are quite different from other platform
00068   // we try not to use them and use the XP BIDI feature
00069   // those text will be drawn by ATSUI intead one character at a time
00070   if ((sc == smArabic) || (sc == smHebrew))
00071      return nsnull;
00072   NS_PRECONDITION(sc < 32, "illegal script id");
00073   if(sc >= 32)
00074     return nsnull;
00075   if (gConverters[sc] != nsnull) {
00076     return gConverters[sc];
00077   }
00078   OSStatus err = noErr;
00079     
00080   //
00081   TextEncoding scriptEncoding;
00082   err = ::UpgradeScriptInfoToTextEncoding(sc, kTextLanguageDontCare, kTextRegionDontCare, nsnull, &scriptEncoding);
00083   if ( noErr == err ) 
00084          err = ::CreateUnicodeToTextInfoByEncoding(scriptEncoding, &gConverters[sc] );
00085 
00086   if (noErr != err) 
00087     gConverters[sc] = nsnull;
00088   return gConverters[sc];
00089 }
00090 
00091 
00092 class nsUnicodeFontMappingEntry
00093 {
00094 public:
00095     nsUnicodeFontMappingEntry(
00096         nsIUnicodeEncoder *aConverter, 
00097         PRUint16 *aCCMap, 
00098         short aFontNum,
00099         ScriptCode aScript)
00100     : mConverter(aConverter),
00101       mCCMap(aCCMap),
00102       mFontNum(aFontNum),
00103       mScript(aScript)
00104     {
00105         NS_ASSERTION(aConverter || aScript != BAD_SCRIPT, "internal error");
00106     }
00107 
00108     PRBool Convert(
00109         const PRUnichar *aString, 
00110         ByteCount aStringLength, 
00111         char *aBuffer, 
00112         ByteCount aBufferLength,
00113         ByteCount& oActualLength,
00114         ByteCount& oBytesRead,
00115         OptionBits opts)
00116     {
00117         if(mConverter)
00118         {
00119             oActualLength = aBufferLength;
00120             if(NS_SUCCEEDED(mConverter->Convert(aString, (PRInt32*) &aStringLength, aBuffer, 
00121                 (PRInt32*) &oActualLength)) && oActualLength)
00122             {
00123                 oBytesRead = 2 * aStringLength;
00124                 return PR_TRUE;
00125             }
00126             return PR_FALSE;
00127         }
00128 
00129         UnicodeToTextInfo converter = GetConverterByScript(mScript);
00130         if(converter)
00131         {
00132             OSStatus err = ::ConvertFromUnicodeToText(converter, 2 * aStringLength,
00133                 (ConstUniCharArrayPtr) aString,
00134                 opts, 0, NULL, 0, NULL,
00135                 aBufferLength, &oBytesRead, &oActualLength,
00136                 (LogicalAddress) aBuffer);
00137     
00138             return (oActualLength > 0 ? PR_TRUE : PR_FALSE);
00139         }
00140         return PR_FALSE;
00141     }
00142 
00143     PRUint16* GetCCMap()
00144     {
00145         return mCCMap;
00146     }
00147 
00148     short GetFontNum()
00149     {
00150         return mFontNum; 
00151     }
00152 
00153 private:
00154     nsCOMPtr<nsIUnicodeEncoder> mConverter;
00155     PRUint16                    *mCCMap; // we don't own this buffer, so don't free it
00156     short                       mFontNum;
00157     ScriptCode                  mScript;
00158 };
00159 
00160 
00161 //--------------------------------------------------------------------------
00162 
00163 static void FillVarBlockToScript( PRInt8 script, PRInt8 *aMap)
00164 {
00165        if(BAD_SCRIPT == aMap[kBasicLatin - kUnicodeBlockFixedScriptMax])
00166               aMap[kBasicLatin - kUnicodeBlockFixedScriptMax] = script;
00167        if(BAD_SCRIPT == aMap[kOthers - kUnicodeBlockFixedScriptMax])
00168               aMap[kOthers - kUnicodeBlockFixedScriptMax] = script;
00169        switch( script )
00170        {
00171               case smRoman: 
00172               case smCentralEuroRoman: 
00173               case smVietnamese: 
00174                      if(BAD_SCRIPT == aMap[kLatin - kUnicodeBlockFixedScriptMax])
00175                             aMap[kLatin - kUnicodeBlockFixedScriptMax] = script;
00176                      break;
00177               case smTradChinese:
00178                      if(BAD_SCRIPT == aMap[kCJKMisc - kUnicodeBlockFixedScriptMax])
00179                             aMap[kCJKMisc - kUnicodeBlockFixedScriptMax] = script;
00180                      if(BAD_SCRIPT == aMap[kCJKIdeographs - kUnicodeBlockFixedScriptMax])
00181                             aMap[kCJKIdeographs - kUnicodeBlockFixedScriptMax] = script;
00182                      break;
00183               case smKorean:
00184               case smJapanese:
00185               case smSimpChinese:
00186                      if(BAD_SCRIPT == aMap[kCJKMisc - kUnicodeBlockFixedScriptMax])
00187                             aMap[kCJKMisc - kUnicodeBlockFixedScriptMax] = script;
00188                      if(BAD_SCRIPT == aMap[kCJKIdeographs - kUnicodeBlockFixedScriptMax])
00189                             aMap[kCJKIdeographs - kUnicodeBlockFixedScriptMax] = script;
00190                      if(BAD_SCRIPT == aMap[kHiraganaKatakana - kUnicodeBlockFixedScriptMax])
00191                             aMap[kHiraganaKatakana - kUnicodeBlockFixedScriptMax] = script;
00192                      break;               
00193        };
00194 }
00195 
00196 struct MyFontEnumData {
00197     MyFontEnumData(nsIDeviceContext* aDC, nsUnicodeFontMappingMac* fontMapping)  : mContext(aDC) {
00198        mFontMapping = fontMapping;
00199     };
00200     nsIDeviceContext* mContext;
00201        nsUnicodeFontMappingMac* mFontMapping;
00202 };
00203 //--------------------------------------------------------------------------
00204 
00205 PRBool nsUnicodeFontMappingMac::FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
00206 {
00207   MyFontEnumData* data = (MyFontEnumData*)aData;
00208   nsUnicodeMappingUtil * info = nsUnicodeMappingUtil::GetSingleton();
00209   NS_PRECONDITION(info != nsnull, "out of memory");
00210   if (aGeneric)
00211   {
00212        if(nsnull == info)
00213               return PR_FALSE;
00214     nsGenericFontNameType type = info->MapGenericFontNameType(aFamily);
00215 
00216        if( type != kUknownGenericFontName) {
00217            for(ScriptCode script = 0; script < 32 ; script++)
00218               {
00219                      const nsString* fontName =  info->GenericFontNameForScript(script,type);
00220                      if(nsnull != fontName) {
00221                          short fontNum;
00222                             nsDeviceContextMac::GetMacFontNumber(*fontName, fontNum);
00223 
00224         if(0 != fontNum)
00225         {
00226             nsUnicodeFontMappingEntry* entry = new nsUnicodeFontMappingEntry(nsnull, nsnull, fontNum, script);
00227             if (entry)
00228                 data->mFontMapping->mFontList.AppendElement(entry);
00229 
00230             if (BAD_FONT_NUM == data->mFontMapping->mScriptFallbackFontIDs[ script ])
00231               data->mFontMapping->mScriptFallbackFontIDs[ script ] = fontNum;
00232             // since this is a generic font name, it won't impact the order of script we used
00233         }
00234                      }
00235               }
00236        }
00237   }
00238   else
00239   {
00240     nsAutoString realFace;
00241     PRBool  aliased;
00242     data->mContext->GetLocalFontName(aFamily, realFace, aliased);
00243     if (aliased || (NS_OK == data->mContext->CheckFontExistence(realFace)))
00244     {
00245            short fontNum;
00246               nsDeviceContextMac::GetMacFontNumber(realFace, fontNum);
00247               
00248               if(0 != fontNum) {
00249             nsCOMPtr<nsIUnicodeEncoder> converter;
00250             PRUint16 *ccmap = nsnull;
00251 
00252             // if this fails, aConverter & aCCMap will be nsnull
00253             nsMacUnicodeFontInfo::GetConverterAndCCMap(realFace, getter_AddRefs(converter), &ccmap);
00254 
00255             ScriptCode script = (converter ? BAD_SCRIPT : ::FontToScript(fontNum));
00256 
00257             nsUnicodeFontMappingEntry* entry = new nsUnicodeFontMappingEntry(converter, ccmap, fontNum, script);
00258             if(entry)
00259                 data->mFontMapping->mFontList.AppendElement(entry);
00260             
00261             // only fill in this information for non-symbolic fonts
00262             if(!converter)
00263             {    
00264                 if(BAD_FONT_NUM == data->mFontMapping->mScriptFallbackFontIDs[ script ]) 
00265                     data->mFontMapping->mScriptFallbackFontIDs[ script ] = fontNum;
00266                 FillVarBlockToScript( script, data->mFontMapping->mPrivBlockToScript);
00267             }
00268               }
00269        }
00270   }
00271   return PR_TRUE;
00272 }
00273 
00274 PRBool nsUnicodeFontMappingMac::ConvertUnicodeToGlyphs(short aFontNum, 
00275     const PRUnichar* aString, ByteCount aStringLength,
00276     char *aBuffer, ByteCount aBufferLength, ByteCount& oActualLength,
00277     ByteCount& oBytesRead, OptionBits opts)
00278 {
00279     for(PRInt32 i = 0; i < mFontList.Count(); i++)
00280     {
00281         nsUnicodeFontMappingEntry* entry = (nsUnicodeFontMappingEntry*) mFontList[i];
00282         if(aFontNum == entry->GetFontNum())
00283             return entry->Convert(aString, aStringLength, aBuffer, aBufferLength,
00284                 oActualLength, oBytesRead, opts);
00285     }
00286     return PR_FALSE;
00287 }
00288 
00289 
00290 //--------------------------------------------------------------------------
00291 nsUnicodeMappingUtil *nsUnicodeFontMappingMac::gUtil = nsnull;
00292 
00293 //--------------------------------------------------------------------------
00294 
00295 void nsUnicodeFontMappingMac::InitByFontFamily(nsFont* aFont, nsIDeviceContext *aDeviceContext) 
00296 {
00297     MyFontEnumData fontData(aDeviceContext, this);
00298     aFont->EnumerateFamilies(nsUnicodeFontMappingMac::FontEnumCallback, &fontData);
00299 }
00300 //--------------------------------------------------------------------------
00301 
00302 void nsUnicodeFontMappingMac::processOneLangRegion(const char* aLanguage, const char* aRegion )
00303 {
00304        if ((! nsCRT::strcmp(aLanguage,"zh")) &&
00305            ((! nsCRT::strcmp(aRegion,"TW")) || (! nsCRT::strcmp(aRegion,"HK"))))
00306        {
00307               FillVarBlockToScript(smTradChinese, mPrivBlockToScript);
00308        } 
00309        else if(! nsCRT::strcmp(aLanguage,"zh"))
00310        {
00311               FillVarBlockToScript(smSimpChinese, mPrivBlockToScript);
00312        } 
00313        else if(! nsCRT::strcmp(aLanguage,"ko"))
00314        {
00315               FillVarBlockToScript(smKorean, mPrivBlockToScript);
00316        }
00317        else if(! nsCRT::strcmp(aLanguage,"ja"))
00318        {
00319               FillVarBlockToScript(smJapanese, mPrivBlockToScript);
00320        }
00321 }
00322 //--------------------------------------------------------------------------
00323 PRBool nsUnicodeFontMappingMac::ScriptMapInitComplete()
00324 {
00325        PRInt32 i;
00326        for(i = kUnicodeBlockFixedScriptMax ; i < kUnicodeBlockSize; i++) {
00327           if(BAD_SCRIPT == mPrivBlockToScript[i - kUnicodeBlockFixedScriptMax])
00328                      return PR_FALSE;
00329        }
00330        return PR_TRUE;
00331 }
00332 //--------------------------------------------------------------------------
00333 
00334 const PRUnichar kA = PRUnichar('A');
00335 const PRUnichar kZ = PRUnichar('Z');
00336 const PRUnichar ka = PRUnichar('a');
00337 const PRUnichar kz = PRUnichar('z');
00338 const PRUnichar kComma = PRUnichar(',');
00339 const PRUnichar kUnderline = PRUnichar('_');
00340 const PRUnichar kSpace = PRUnichar(' ');
00341 const PRUnichar kNullCh       = PRUnichar('\0');
00342 //--------------------------------------------------------------------------
00343 
00344 void nsUnicodeFontMappingMac::InitByLANG(const nsString& aLANG)
00345 {
00346        // do not countinue if there are no difference to look at the lang tag
00347        if( ScriptMapInitComplete() )
00348               return;
00349        const PRUnichar *p = aLANG.get();
00350        PRUint32 len = aLANG.Length();
00351        char language[3];
00352        char region[3];
00353        language[2] = region[2]= '\0';;
00354        language[0]= language[1] = region[0]= region[1] = ' ';
00355        PRUint32 state = 0;
00356        
00357        for(PRUint32 i = 0; (state != -1) && (i < len); i++, p++)
00358        {
00359               switch (state) {
00360                      case 0:
00361                             if(( ka <= *p) && (*p <= kz )) {
00362                                    language[state++] = (char)*p;
00363                             } else if( kSpace == *p) {
00364                                    state = 0;
00365                             } else {
00366                                    state = -1;
00367                             }
00368                             break;
00369                      case 1:
00370                             if(( ka <= *p) && (*p <= kz )) {
00371                                    language[state++] = (char)*p;
00372                             } else {
00373                                    state = -1;
00374                             }
00375                             break;
00376                      case 2:
00377                             if(kComma == *p) {
00378                                    processOneLangRegion(language, region);
00379                                    return;
00380                             } else if(kUnderline == *p) {
00381                                    state = 3;
00382                             } else {
00383                                    state = -1;
00384                             }
00385                             break;
00386                      case 3:
00387                      case 4:
00388                             if(( kA <= *p) && (*p <= kZ )) {
00389                                    region[state - 3] = (char)*p;
00390                                    state++;
00391                             } else {
00392                                    state = -1;
00393                             }
00394                             break;
00395                      case 5:
00396                             if(kComma == *p) {
00397                                    processOneLangRegion(language, region);
00398                                    return;
00399                             } else {
00400                                    state = -1;
00401                             }
00402                             break;
00403               };
00404        }
00405        if((2 == state) || (5 == state)) {
00406               processOneLangRegion(language, region);
00407        }
00408 }
00409 //--------------------------------------------------------------------------
00410 void nsUnicodeFontMappingMac::InitByLangGroup(const nsString& aLangGroup)
00411 {
00412        // do not continue if there are no difference to look at the document Charset
00413        if( ScriptMapInitComplete() )
00414               return;
00415        if(aLangGroup.LowerCaseEqualsLiteral("x-western"))
00416        {
00417               FillVarBlockToScript(smRoman, mPrivBlockToScript);             
00418        } else if(aLangGroup.LowerCaseEqualsLiteral("zh-cn"))
00419        {
00420               FillVarBlockToScript(smSimpChinese, mPrivBlockToScript);
00421        } else if(aLangGroup.LowerCaseEqualsLiteral("ko"))
00422        {
00423               FillVarBlockToScript(smKorean, mPrivBlockToScript);
00424        } else if(aLangGroup.LowerCaseEqualsLiteral("zh-tw") ||
00425               aLangGroup.LowerCaseEqualsLiteral("zh-hk"))
00426        {
00427               FillVarBlockToScript(smTradChinese, mPrivBlockToScript);
00428        } else if(aLangGroup.LowerCaseEqualsLiteral("ja"))
00429        {
00430               FillVarBlockToScript(smJapanese, mPrivBlockToScript);
00431        }
00432 }
00433 //--------------------------------------------------------------------------
00434 
00435 void nsUnicodeFontMappingMac::InitDefaultScriptFonts()
00436 {
00437        for(PRInt32 i = 0 ; i < smPseudoTotalScripts; i++)
00438        {
00439               // copy from global mapping
00440           if(BAD_FONT_NUM == mScriptFallbackFontIDs[i])
00441                      mScriptFallbackFontIDs[i] = gUtil->ScriptFont(i);
00442     }
00443        for(PRInt32 k = kUnicodeBlockFixedScriptMax ; k < kUnicodeBlockSize; k++)
00444        {
00445               // copy from global mapping
00446            if(BAD_SCRIPT == mPrivBlockToScript[k - kUnicodeBlockFixedScriptMax])
00447                      mPrivBlockToScript[k - kUnicodeBlockFixedScriptMax] = gUtil->BlockToScript((nsUnicodeBlock) k);
00448     }
00449 }
00450 //--------------------------------------------------------------------------
00451 
00452 nsUnicodeFontMappingMac::nsUnicodeFontMappingMac(
00453        nsFont* aFont, nsIDeviceContext *aDeviceContext, 
00454        const nsString& aLangGroup, const nsString& aLANG) 
00455 {
00456   PRInt32 i;
00457   if (!gUtil)
00458     gUtil = nsUnicodeMappingUtil::GetSingleton();
00459        for(i = kUnicodeBlockFixedScriptMax ; i < kUnicodeBlockSize; i++)
00460           mPrivBlockToScript[i - kUnicodeBlockFixedScriptMax] = BAD_SCRIPT;
00461        for(i = 0 ; i < smPseudoTotalScripts; i++)
00462           mScriptFallbackFontIDs[i] = BAD_FONT_NUM;
00463           
00464        InitByFontFamily(aFont, aDeviceContext);
00465        InitByLANG(aLANG);
00466        InitByLangGroup(aLangGroup);
00467        InitDefaultScriptFonts();
00468 }
00469 //--------------------------------------------------------------------------
00470 
00471 nsUnicodeFontMappingMac::~nsUnicodeFontMappingMac()
00472 {
00473     for(PRInt32 i = 0; i < mFontList.Count(); i++)
00474     {
00475         nsUnicodeFontMappingEntry* entry = (nsUnicodeFontMappingEntry*) mFontList[i];
00476         delete entry;
00477     }
00478 }
00479 //--------------------------------------------------------------------------
00480 
00481 PRBool nsUnicodeFontMappingMac::Equals(const nsUnicodeFontMappingMac& aMap)
00482 {
00483        PRUint32 i;
00484        if(&aMap != this) {
00485               for( i=0; i < smPseudoTotalScripts; i++)
00486               {
00487                      if(mScriptFallbackFontIDs[i] != aMap.mScriptFallbackFontIDs[i])
00488                             return PR_FALSE;
00489               }
00490               for( i=0; i < kUnicodeBlockVarScriptMax; i++)
00491               {
00492                      if(mPrivBlockToScript[i] != aMap.mPrivBlockToScript[i])
00493                             return PR_FALSE;
00494               }
00495        }
00496        return PR_TRUE;
00497 }
00498 
00499 //--------------------------------------------------------------------------
00500 
00501 short nsUnicodeFontMappingMac::GetFontID(PRUnichar aChar) {
00502     // initialize to bogus values
00503     short firstSymbolicFont = BAD_FONT_NUM, firstNonSymbolicFont = BAD_FONT_NUM;
00504     PRInt32 firstSymbolicFontIndex = -1;
00505     
00506     // Trap invisible chars
00507     if (CCMAP_HAS_CHAR_EXT(gIgnorableCCMapExt, aChar)) {
00508       return IGNORABLE_FONT_NUM;
00509     }
00510 
00511     // find the first symbolic font that has a glyph for aChar
00512     // and if there is one, remember it's index in the font list
00513     for(PRInt32 i = 0; i < mFontList.Count(); i++)
00514     {
00515         nsUnicodeFontMappingEntry* entry = (nsUnicodeFontMappingEntry*) mFontList[i];
00516         PRUint16 *ccmap = entry->GetCCMap();
00517         if(ccmap && CCMAP_HAS_CHAR(ccmap, aChar))
00518         {
00519             firstSymbolicFontIndex = i;
00520             firstSymbolicFont = entry->GetFontNum();
00521             break;
00522         }
00523     }
00524 
00525     // find the first non-symbolic font that has a glyph for aChar
00526        nsUnicodeBlock block = GetBlock(aChar);
00527        if(block < kUnicodeBlockFixedScriptMax) 
00528        {
00529               firstNonSymbolicFont = mScriptFallbackFontIDs[gUtil->BlockToScript(block)];
00530               
00531               // if there was no symbolic font we don't need to loop through the list again
00532         if(firstSymbolicFont == BAD_FONT_NUM)
00533             return firstNonSymbolicFont;
00534         
00535         // find the index of the first non symbolic font in the list and return the 
00536         // first font (symbolic or non symbolic) in the list that has a glyph for this char
00537         for(PRInt32 i = 0; i < mFontList.Count(); i++)
00538         {
00539             nsUnicodeFontMappingEntry* entry = (nsUnicodeFontMappingEntry*) mFontList[i];
00540             if(entry->GetFontNum() == firstNonSymbolicFont)
00541             {
00542                 return (firstSymbolicFontIndex < i ? firstSymbolicFont : firstNonSymbolicFont);
00543             }
00544         }
00545         return firstNonSymbolicFont;
00546        }
00547        
00548     return (firstSymbolicFont != BAD_FONT_NUM ? firstSymbolicFont : 
00549               mScriptFallbackFontIDs[ mPrivBlockToScript[ block - kUnicodeBlockFixedScriptMax] ]);
00550 }
00551 
00552 //------------------------------------------------------------------------
00553 static nsUnicodeBlock gU0xxxMap[32]=
00554 {
00555  kBasicLatin, kLatin,    // U+0000
00556  kLatin,      kLatin,    // U+0100
00557  kOthers,     kOthers,   // U+0200
00558  kOthers,     kGreek,    // U+0300
00559  kCyrillic,   kCyrillic, // U+0400
00560  kArmenian,   kOthers,   // U+0500
00561  kArabic,     kArabic,   // U+0600
00562  kOthers,     kOthers,   // U+0700
00563  kOthers,     kOthers,   // U+0800
00564  kDevanagari, kBengali,  // U+0900
00565  kGurmukhi,   kGujarati, // U+0a00
00566  kOriya,      kTamil,    // U+0b00
00567  kTelugu,     kKannada,  // U+0c00
00568  kMalayalam,  kOthers ,  // U+0d00
00569  kThai,       kLao,      // U+0e00
00570  kTibetan,    kTibetan,  // U+0f00
00571 };
00572 //--------------------------------------------------------------------------
00573 
00574 static nsUnicodeBlock GetBlockU0XXX(PRUnichar aChar)
00575 {
00576  nsUnicodeBlock res = gU0xxxMap[ (aChar >> 7) & 0x1F];
00577  if(res == kOthers) {
00578    if((0x0200 <= aChar) && ( aChar <= 0x024F ))           res =  kLatin;
00579    else if((0x0370 <= aChar) && ( aChar <= 0x037F ))      res =  kGreek;
00580    else if((0x0580 <= aChar) && ( aChar <= 0x058F ))      res =  kArmenian;
00581    else if((0x0590 <= aChar) && ( aChar <= 0x05ff ))      res =  kHebrew;
00582  } 
00583  return res;
00584 }
00585 //--------------------------------------------------------------------------
00586 
00587 static nsUnicodeBlock GetBlockU1XXX(PRUnichar aChar)
00588 {
00589   switch( aChar & 0x0F00 )
00590   {
00591      case 0x0000: return kGeorgian;
00592      case 0x0100: return kHangul;
00593      case 0x0e00: return kLatin;
00594      case 0x0f00: return kGreek;
00595      default:   
00596      {
00597        if ((0x0200 <= aChar) && ( aChar <= 0x037c)) return kEthiopic;
00598        if ((0x0400 <= aChar) && ( aChar <= 0x0676)) return kCanadian;
00599        if ((0x0780 <= aChar) && ( aChar <= 0x07ff)) return kKhmer;
00600        return kOthers;
00601      }
00602   }
00603 }
00604 //--------------------------------------------------------------------------
00605 
00606 static nsUnicodeBlock GetBlockU2XXX(PRUnichar aChar)
00607 {
00608   return kOthers;
00609 }
00610 //--------------------------------------------------------------------------
00611 
00612 static nsUnicodeBlock GetBlockU3XXX(PRUnichar aChar)
00613 {
00614   if(aChar < 0x3040)        return kCJKMisc;
00615   else if(aChar < 0x3100)   return kHiraganaKatakana; 
00616   else if(aChar < 0x3130)   return kBopomofo; 
00617   else if(aChar < 0x3190)   return kHangul; 
00618   else if(aChar >= 0x3400)  return kCJKIdeographs; // Unicode 3.0
00619   else                      return kCJKMisc;
00620 }
00621 
00622 //--------------------------------------------------------------------------
00623 
00624 static nsUnicodeBlock GetBlockCJKIdeographs(PRUnichar aChar)
00625 {
00626   return  kCJKIdeographs;
00627 }
00628 //--------------------------------------------------------------------------
00629 
00630 static nsUnicodeBlock GetBlockHangul(PRUnichar aChar)
00631 {
00632   return  kHangul;
00633 }
00634 //--------------------------------------------------------------------------
00635 
00636 static nsUnicodeBlock GetBlockUAXXX(PRUnichar aChar)
00637 {
00638   if(aChar < 0xAC00) return  kOthers;
00639   else               return  kHangul;
00640 }
00641 //--------------------------------------------------------------------------
00642 
00643 static nsUnicodeBlock GetBlockUDXXX(PRUnichar aChar)
00644 {
00645   if(aChar < 0xD800) return  kHangul;
00646   else               return  kOthers;
00647 }
00648 //--------------------------------------------------------------------------
00649 
00650 static nsUnicodeBlock GetBlockUEXXX(PRUnichar aChar)
00651 {
00652   return  kOthers;
00653 }
00654 //--------------------------------------------------------------------------
00655 
00656 static nsUnicodeBlock GetBlockUFXXX(PRUnichar aChar)
00657 {
00658   // U+FFxx is used more frequently in the U+Fxxxx block
00659   if(aChar >= 0xff00) 
00660   {
00661     if(aChar < 0xff60)           return kCJKMisc;
00662     else if(aChar < 0xffA0)      return kHiraganaKatakana;
00663     else if(aChar < 0xffe0)      return kHangul;
00664     else                         return kOthers;    
00665   }
00666 
00667   // The rest is rarely used, we don't care the performance below.
00668   if((0xf780 <= aChar) && (aChar <= 0xf7ff)) return kUserDefinedEncoding;
00669   else if(aChar < 0xf900)        return kOthers;
00670   else if(aChar < 0xfb00)        return kCJKIdeographs;
00671   else if(aChar < 0xfb10)        return kLatin;
00672   else if(aChar < 0xfb18)        return kArmenian;
00673   else if(aChar < 0xfb50)        return kHebrew;
00674   else if(aChar < 0xfe20)        return kArabic;
00675   else if(aChar < 0xfe70)        return kOthers;
00676   else                           return kArabic;
00677 }
00678 //--------------------------------------------------------------------------
00679 
00680 typedef nsUnicodeBlock (* getUnicodeBlock)(PRUnichar aChar);
00681 static getUnicodeBlock gAllGetBlock[16] = 
00682 {
00683   &GetBlockU0XXX,          // 0
00684   &GetBlockU1XXX,          // 1
00685   &GetBlockU2XXX,          // 2
00686   &GetBlockU3XXX,          // 3
00687   &GetBlockCJKIdeographs,  // 4
00688   &GetBlockCJKIdeographs,  // 5
00689   &GetBlockCJKIdeographs,  // 6
00690   &GetBlockCJKIdeographs,  // 7
00691   &GetBlockCJKIdeographs,  // 8
00692   &GetBlockCJKIdeographs,  // 9
00693   &GetBlockUAXXX,          // a
00694   &GetBlockHangul,         // b
00695   &GetBlockHangul,         // c
00696   &GetBlockUDXXX,          // d
00697   &GetBlockUEXXX,          // e
00698   &GetBlockUFXXX           // f
00699 };
00700 //--------------------------------------------------------------------------
00701 
00702 nsUnicodeBlock nsUnicodeFontMappingMac:: GetBlock(PRUnichar aChar)
00703 {
00704    return (*(gAllGetBlock[(aChar >> 12)]))(aChar);
00705 }