Back to index

lightning-sunbird  0.9+nobinonly
nsUnicodeRenderingToolkit.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) 1999
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 "nsUnicodeRenderingToolkit.h"
00039 #include "nsUnicodeFontMappingMac.h"
00040 #include "nsUnicodeFallbackCache.h"
00041 #include "nsDrawingSurfaceMac.h"
00042 #include "nsTransform2D.h"
00043 #include "nsFontMetricsMac.h"
00044 #include "nsGraphicState.h"
00045 #include "prprf.h"
00046 #include "nsCarbonHelpers.h"
00047 #include "nsISaveAsCharset.h"
00048 #include "nsIComponentManager.h"
00049 #include "nsUnicharUtils.h"
00050 
00051 
00052 #include "nsMacUnicodeFontInfo.h"
00053 #include "nsICharRepresentable.h"
00054 
00055 #include <FixMath.h>
00056 
00057 #define STACK_TRESHOLD 1000
00058 
00059 static NS_DEFINE_CID(kSaveAsCharsetCID, NS_SAVEASCHARSET_CID);
00060 
00061 //#define DISABLE_TEC_FALLBACK
00062 //#define DISABLE_PRECOMPOSEHANGUL_FALLBACK
00063 //#define DISABLE_LATINL_FALLBACK
00064 //#define DISABLE_ATSUI_FALLBACK
00065 //#define DISABLE_TRANSLITERATE_FALLBACK
00066 //#define DISABLE_UPLUS_FALLBACK
00067 
00068 #define IS_FORMAT_CONTROL_CHARS(c)        ((0x2000==((c)&0xFFF0))||(0x2028==((c)&0xFFF8)))
00069 #define IS_CONTEXTUAL_CHARS(c)              ((0x0600<=(c))&&((c)<0x1000))
00070 #define IS_COMBINING_CHARS(c)               ((0x0300<=(c))&&((c)<0x0370))
00071 
00072 #define QUESTION_FALLBACKSIZE 9
00073 #define UPLUS_FALLBACKSIZE 9
00074 #define IN_RANGE(c, l, h) (((l) <= (c)) && ((c) <= (h)))
00075 #define IN_STANDARD_MAC_ROMAN_FONT(c) ( \
00076   (((c) < 0x180) && (! (\
00077    (0x0110 == (c)) || \
00078    (0x012c == (c)) || \
00079    (0x012d == (c)) || \
00080    (0x0138 == (c)) || \
00081    (0x014a == (c)) || \
00082    (0x014b == (c)) || \
00083    (0x017f == (c))    \
00084    )))) 
00085 #define IN_SYMBOL_FONT(c) ( \
00086   IN_RANGE(c, 0x0391, 0x03a1) || \
00087   IN_RANGE(c, 0x03a3, 0x03a9) || \
00088   IN_RANGE(c, 0x03b1, 0x03c1) || \
00089   IN_RANGE(c, 0x03c3, 0x03c9) || \
00090   (0x2111 == (c))   || \
00091   (0x2118 == (c))   || \
00092   (0x211c == (c))   || \
00093   (0x2135 == (c))   || \
00094   IN_RANGE(c, 0x2190, 0x2193) || \
00095   IN_RANGE(c, 0x21d0, 0x21d3) || \
00096   IN_RANGE(c, 0x21ed, 0x21ee) || \
00097   (0x2200 == (c))   || \
00098   (0x2203 == (c))   || \
00099   (0x2205 == (c))   || \
00100   (0x2208 == (c))   || \
00101   (0x2209 == (c))   || \
00102   (0x2212 == (c))   || \
00103   (0x2217 == (c))   || \
00104   (0x221d == (c))   || \
00105   (0x2220 == (c))   || \
00106   IN_RANGE(c, 0x2227, 0x222b) || \
00107   (0x2234 == (c))   || \
00108   (0x223c == (c))   || \
00109   (0x2261 == (c))   || \
00110   (0x2282 == (c))   || \
00111   (0x2283 == (c))   || \
00112   (0x2286 == (c))   || \
00113   (0x2287 == (c))   || \
00114   (0x2295 == (c))   || \
00115   (0x2297 == (c))   || \
00116   (0x22a5 == (c))   || \
00117   (0x2320 == (c))   || \
00118   (0x2321 == (c))   || \
00119   (0x240d == (c))   || \
00120   (0x2660 == (c))   || \
00121   (0x2663 == (c))   || \
00122   (0x2665 == (c))   || \
00123   (0x2666 == (c))      \
00124   )
00125 #define SPECIAL_IN_SYMBOL_FONT(c) ( \
00126   IN_RANGE(c, 0x2308, 0x230b) || \
00127   (0x2329 == (c))   || \
00128   (0x232a == (c))    \
00129   )
00130 #define BAD_TEXT_ENCODING 0xFFFFFFFF
00131 
00132 // all the chracter should not be drawn if there are no glyph
00133 #define IS_ZERO_WIDTH_CHAR(c) ( \
00134   IN_RANGE(c, 0x200b, 0x200f) || \
00135   IN_RANGE(c, 0x202a, 0x202e) \
00136   )
00137   
00138 
00139 #define IN_ARABIC_PRESENTATION_A(a) ((0xfb50 <= (a)) && ((a) <= 0xfdff))
00140 #define IN_ARABIC_PRESENTATION_B(a) ((0xfe70 <= (a)) && ((a) <= 0xfeff))
00141 #define IN_ARABIC_PRESENTATION_A_OR_B(a) (IN_ARABIC_PRESENTATION_A(a) || IN_ARABIC_PRESENTATION_B(a))
00142 
00143 // we should not ues TEC fallback for characters in latin, greek and cyrillic script
00144 // because Japanese, Chinese and Korean font have these chracters. If we let them 
00145 // render in the TEC fallback process, then we will use a Japanese/korean/chinese font
00146 // to render it even the current font have a glyph in it
00147 // if we skip the TEC fallback, then the ATSUI fallback will try to use the glyph 
00148 // in the font first (TEC or TEC fallback are using QuickDraw, which can only use 
00149 // the glyphs that in the font script's encodign. but a lot of TrueType font
00150 // have houndred more glyph in additional to the font scripts
00151 #define IS_LATIN(c)  ( IN_RANGE(c, 0x0000, 0x024F) || IN_RANGE(c, 0x1e00, 0x1eff) )
00152 #define IS_GREEK(c)  ( IN_RANGE(c, 0x0370, 0x03FF) || IN_RANGE(c, 0x1f00, 0x1fff) )
00153 #define IS_CYRILLIC(c)  IN_RANGE(c, 0x0400, 0x04ff)
00154 #define IS_SKIP_TEC_FALLBACK(c) (IS_LATIN(c) || IS_GREEK(c) || IS_CYRILLIC(c))
00155 
00156 //------------------------------------------------------------------------
00157 #pragma mark -
00158 //------------------------------------------------------------------------
00159 
00160 nsUnicodeFallbackCache* nsUnicodeRenderingToolkit :: GetTECFallbackCache()
00161 {
00162        static nsUnicodeFallbackCache* gTECFallbackCache = nsnull;
00163        
00164        if( ! gTECFallbackCache)
00165               gTECFallbackCache = new nsUnicodeFallbackCache();
00166        return gTECFallbackCache;
00167 }
00168 //------------------------------------------------------------------------
00169 
00170 PRBool 
00171 nsUnicodeRenderingToolkit::TECFallbackGetDimensions(
00172   const PRUnichar *aCharPt, 
00173   nsTextDimensions& oDim, 
00174   short origFontNum, 
00175   nsUnicodeFontMappingMac& fontMapping)
00176 {
00177   char buf[20];
00178   ByteCount processBytes = 0;
00179   ByteCount outLen = 0;
00180   ScriptCode fallbackScript;
00181   nsUnicodeFallbackCache* cache = GetTECFallbackCache();
00182   short aWidth;
00183   FontInfo finfo;
00184   const short *scriptFallbackFonts = fontMapping.GetScriptFallbackFonts();
00185   
00186   if ((0xf780 <= *aCharPt) && (*aCharPt <= 0xf7ff))
00187   {
00188     // If we are encountering our PUA characters for User-Defined characters, we better
00189     // just drop the high-byte and return the width for the low-byte.
00190     *buf = (*aCharPt & 0x00FF);
00191     ::GetFontInfo(&finfo);
00192     oDim.ascent = finfo.ascent;
00193     oDim.descent = finfo.descent;
00194     
00195     GetScriptTextWidth (buf,1,aWidth);
00196     oDim.width = aWidth;
00197 
00198     return PR_TRUE;
00199   }
00200   else if (cache->Get(*aCharPt, fallbackScript))
00201   {
00202     if (BAD_SCRIPT == fallbackScript)
00203       return PR_FALSE;
00204     
00205     if(fontMapping.ConvertUnicodeToGlyphs(scriptFallbackFonts[fallbackScript], aCharPt, 1,
00206         buf, STACK_TRESHOLD, outLen, processBytes, kUnicodeLooseMappingsMask))
00207     {  
00208         ::TextFont(scriptFallbackFonts[fallbackScript]);
00209         GetScriptTextWidth(buf, outLen, aWidth);
00210         ::GetFontInfo(&finfo);
00211         oDim.ascent = finfo.ascent;
00212         oDim.descent = finfo.descent;
00213         oDim.width = aWidth;
00214         ::TextFont(origFontNum);
00215     }
00216     return PR_TRUE;
00217   }
00218   
00219   for(fallbackScript = 0 ; fallbackScript < 32; fallbackScript++)
00220   {
00221     if (BAD_FONT_NUM != scriptFallbackFonts[fallbackScript])
00222     {
00223         if(fontMapping.ConvertUnicodeToGlyphs(scriptFallbackFonts[fallbackScript], aCharPt, 1,
00224             buf, STACK_TRESHOLD, outLen, processBytes, kUnicodeLooseMappingsMask))
00225         {
00226             NS_PRECONDITION(0 == (processBytes % 2), "strange conversion result");
00227             ::TextFont(scriptFallbackFonts[fallbackScript]);
00228             GetScriptTextWidth(buf, outLen, aWidth);
00229             ::GetFontInfo(&finfo);
00230             oDim.ascent = finfo.ascent;
00231             oDim.descent = finfo.descent;
00232             oDim.width = aWidth;
00233             ::TextFont(origFontNum);        
00234             break;
00235         }          
00236     }
00237   }
00238   
00239   if (0 == outLen)
00240     fallbackScript = BAD_SCRIPT;
00241     
00242   // put into cache
00243   cache->Set(*aCharPt, fallbackScript);
00244   
00245   return (BAD_SCRIPT != fallbackScript);
00246 }
00247 //------------------------------------------------------------------------
00248 
00249 #if MOZ_MATHML
00250 PRBool nsUnicodeRenderingToolkit::TECFallbackGetBoundingMetrics(
00251     const PRUnichar *aCharPt,
00252     nsBoundingMetrics& oBoundingMetrics,
00253     short fontNum,
00254     nsUnicodeFontMappingMac& fontMapping)
00255 {
00256     char buf[STACK_TRESHOLD];
00257     ByteCount processBytes = 0;
00258     ByteCount outLen = 0;
00259     ScriptCode fallbackScript;
00260     nsUnicodeFallbackCache* cache = GetTECFallbackCache();
00261     const short *scriptFallbackFonts = fontMapping.GetScriptFallbackFonts();
00262     
00263     if((0xf780 <= *aCharPt) && (*aCharPt <= 0xf7ff))
00264     {
00265         // If we are encountering our PUA characters for User-Defined characters, we better
00266         // just drop the high-byte and return the width for the low-byte.
00267         *buf = (*aCharPt & 0x00FF);
00268         GetScriptTextBoundingMetrics(buf, 1, ::FontToScript(fontNum), oBoundingMetrics);
00269         return PR_TRUE;
00270     }
00271     else if(cache->Get(*aCharPt, fallbackScript))
00272     {
00273         if(BAD_SCRIPT == fallbackScript)
00274             return PR_FALSE;
00275         
00276         if(fontMapping.ConvertUnicodeToGlyphs(scriptFallbackFonts[fallbackScript], aCharPt, 1,
00277             buf, STACK_TRESHOLD, outLen, processBytes, kUnicodeLooseMappingsMask))
00278         {  
00279             ::TextFont(scriptFallbackFonts[fallbackScript]);
00280             GetScriptTextBoundingMetrics(buf, outLen, fallbackScript, oBoundingMetrics);
00281             ::TextFont(fontNum);
00282             return PR_TRUE;
00283         }
00284         return PR_FALSE;
00285     }
00286     
00287     for(fallbackScript = 0; fallbackScript < 32; fallbackScript++)
00288     {
00289         if(BAD_FONT_NUM != scriptFallbackFonts[fallbackScript])
00290         {
00291             if(fontMapping.ConvertUnicodeToGlyphs(scriptFallbackFonts[fallbackScript], aCharPt, 1,
00292                 buf, STACK_TRESHOLD, outLen, processBytes, kUnicodeLooseMappingsMask))
00293             {
00294                 NS_PRECONDITION(0 == (processBytes % 2), "strange conversion result");
00295                 ::TextFont(scriptFallbackFonts[fallbackScript]);
00296                 GetScriptTextBoundingMetrics(buf, outLen, fallbackScript, oBoundingMetrics);           
00297                 ::TextFont(fontNum);
00298                 break;
00299             }   
00300         }
00301     }
00302     
00303     if(0 == outLen)
00304         fallbackScript = BAD_SCRIPT;
00305         
00306     // put into cache
00307     cache->Set(*aCharPt, fallbackScript);
00308     
00309     return (BAD_SCRIPT != fallbackScript);
00310 }
00311 #endif // MOZ_MATHML
00312 //------------------------------------------------------------------------
00313 
00314 PRBool nsUnicodeRenderingToolkit :: TECFallbackDrawChar(
00315   const PRUnichar *aCharPt, 
00316   PRInt32 x, 
00317   PRInt32 y, 
00318   short& oWidth, 
00319   short origFontNum, 
00320   nsUnicodeFontMappingMac& fontMapping)
00321 {
00322   char buf[20];
00323   ByteCount processBytes = 0;
00324   ByteCount outLen = 0;
00325   ScriptCode fallbackScript;
00326   nsUnicodeFallbackCache* cache = GetTECFallbackCache();
00327   const short *scriptFallbackFonts = fontMapping.GetScriptFallbackFonts();
00328   
00329   // since we always call TECFallbackGetWidth before TECFallbackDrawChar
00330   // we could assume that we can always get the script code from cache.
00331   if ((0xf780 <= *aCharPt) && (*aCharPt <= 0xf7ff))
00332   {
00333     // If we are encountering our PUA characters for User-Defined characters, we better
00334     // just drop the high-byte and draw the text for the low-byte.
00335     *buf = (*aCharPt & 0x00FF);
00336     DrawScriptText (buf,1,x,y,oWidth);
00337 
00338     return PR_TRUE;
00339   }
00340   else if (cache->Get(*aCharPt, fallbackScript))
00341   {
00342     if (BAD_SCRIPT == fallbackScript)
00343       return PR_FALSE;
00344     
00345     if(fontMapping.ConvertUnicodeToGlyphs(scriptFallbackFonts[fallbackScript], aCharPt, 1,
00346         buf, STACK_TRESHOLD, outLen, processBytes, kUnicodeLooseMappingsMask))
00347     {
00348         ::TextFont(scriptFallbackFonts[fallbackScript]);
00349         DrawScriptText(buf, outLen, x, y, oWidth);
00350         ::TextFont(origFontNum);
00351         return PR_TRUE;
00352     }
00353   }
00354   return PR_FALSE;
00355 }
00356 //------------------------------------------------------------------------
00357 static PRUnichar gSymbolReplacement[]={0xf8ee,0xf8f9,0xf8f0,0xf8fb,0x3008,0x3009};
00358 
00359 //------------------------------------------------------------------------
00360 
00361 static nsresult FormAorBIsolated(PRUnichar aChar, nsMacUnicodeFontInfo& aInfo, PRUnichar* aOutChar)
00362 {
00363   static const PRUnichar arabicisolated[]=
00364   {
00365     // start of form a
00366     0xFB50, 0x0671,  0xFB52, 0x067B,  0xFB56, 0x067E,  0xFB5A, 0x0680,  0xFB5E, 0x067A,
00367     0xFB62, 0x067F,  0xFB66, 0x0679,  0xFB6A, 0x06A4,  0xFB6E, 0x06A6,  0xFB72, 0x0684,
00368     0xFB76, 0x0683,  0xFB7A, 0x0686,  0xFB7E, 0x0687,  0xFB82, 0x068D,  0xFB84, 0x068C,
00369     0xFB86, 0x068E,  0xFB88, 0x0688,  0xFB8A, 0x0698,  0xFB8C, 0x0691,  0xFB8E, 0x06A9,
00370     0xFB92, 0x06AF,  0xFB96, 0x06B3,  0xFB9A, 0x06B1,  0xFB9E, 0x06BA,  0xFBA0, 0x06BB,
00371     0xFBA4, 0x06C0,  0xFBA6, 0x06C1,  0xFBAA, 0x06BE,  0xFBAE, 0x06D2,  0xFBB0, 0x06D3,
00372     0xFBD3, 0x06AD,  0xFBD7, 0x06C7,  0xFBD9, 0x06C6,  0xFBDB, 0x06C8,  0xFBDD, 0x0677,
00373     0xFBDE, 0x06CB,  0xFBE0, 0x06C5,  0xFBE2, 0x06C9,  0xFBE4, 0x06D0,  0xFBFC, 0x06CC,
00374 
00375     // start of form b
00376     0xFE70, 0x064B,  0xFE72, 0x064C,  0xFE74, 0x064D,  0xFE76, 0x064E,  0xFE78, 0x064F,
00377     0xFE7A, 0x0650,  0xFE7C, 0x0651,  0xFE7E, 0x0652,  0xFE80, 0x0621,  0xFE81, 0x0622,
00378     0xFE83, 0x0623,  0xFE85, 0x0624,  0xFE87, 0x0625,  0xFE89, 0x0626,  0xFE8D, 0x0627,
00379     0xFE8F, 0x0628,  0xFE93, 0x0629,  0xFE95, 0x062A,  0xFE99, 0x062B,  0xFE9D, 0x062C,
00380     0xFEA1, 0x062D,  0xFEA5, 0x062E,  0xFEA9, 0x062F,  0xFEAB, 0x0630,  0xFEAD, 0x0631,
00381     0xFEAF, 0x0632,  0xFEB1, 0x0633,  0xFEB5, 0x0634,  0xFEB9, 0x0635,  0xFEBD, 0x0636,
00382     0xFEC1, 0x0637,  0xFEC5, 0x0638,  0xFEC9, 0x0639,  0xFECD, 0x063A,  0xFED1, 0x0641,
00383     0xFED5, 0x0642,  0xFED9, 0x0643,  0xFEDD, 0x0644,  0xFEE1, 0x0645,  0xFEE5, 0x0646,
00384     0xFEE9, 0x0647,  0xFEED, 0x0648,  0xFEEF, 0x0649,  0xFEF1, 0x064A,
00385     0x0000
00386   };
00387   const PRUnichar* p;
00388   for ( p= arabicisolated; *p; p += 2) {
00389     if (aChar == *p) {
00390       if (aInfo.HasGlyphFor(*(p+1))) {
00391         *aOutChar = *(p+1);
00392         return NS_OK;
00393       }
00394     }
00395   }
00396   return NS_ERROR_FAILURE;
00397 }
00398 //------------------------------------------------------------------------
00399 
00400 PRBool 
00401 nsUnicodeRenderingToolkit::ATSUIFallbackGetDimensions(
00402   const PRUnichar *aCharPt, 
00403   nsTextDimensions& oDim, 
00404   short origFontNum,
00405   short aSize, PRBool aBold, PRBool aItalic, nscolor aColor) 
00406 {
00407   
00408   nsMacUnicodeFontInfo info;
00409   if (nsATSUIUtils::IsAvailable()  
00410       && (IN_STANDARD_MAC_ROMAN_FONT(*aCharPt) 
00411          ||IN_SYMBOL_FONT(*aCharPt)
00412          ||SPECIAL_IN_SYMBOL_FONT(*aCharPt)
00413          ||info.HasGlyphFor(*aCharPt)))
00414   {
00415     mATSUIToolkit.PrepareToDraw(mPort, mContext );
00416     nsresult res;
00417     if (SPECIAL_IN_SYMBOL_FONT(*aCharPt))
00418     {
00419       short rep = 0;
00420       if ((*aCharPt) > 0x230b)
00421          rep = (*aCharPt) - 0x2325;
00422       else 
00423          rep = (*aCharPt) - 0x2308;
00424       res = mATSUIToolkit.GetTextDimensions(gSymbolReplacement+rep, 1, oDim, aSize, 
00425                                             origFontNum, 
00426                                             aBold, aItalic, aColor);
00427     } 
00428     else 
00429     {
00430       res = mATSUIToolkit.GetTextDimensions(aCharPt, 1, oDim, aSize, 
00431                                             origFontNum, 
00432                                             aBold, aItalic, aColor);
00433     }
00434     if (NS_SUCCEEDED(res)) 
00435       return PR_TRUE;
00436   }
00437 
00438   if (IN_ARABIC_PRESENTATION_A_OR_B(*aCharPt))
00439   {      
00440     PRUnichar isolated;
00441     if (NS_SUCCEEDED( FormAorBIsolated(*aCharPt, info, &isolated))) 
00442     {
00443       if (ATSUIFallbackGetDimensions(&isolated, oDim, origFontNum, 
00444                                      aSize, aBold, aItalic, aColor))
00445          return PR_TRUE;
00446     }                                                 
00447   }
00448 
00449   // we know some ATSUI font do not have bold, turn it off and try again
00450   if (aBold) 
00451   {
00452          if (ATSUIFallbackGetDimensions(aCharPt, oDim, origFontNum, 
00453                                         aSize, PR_FALSE, aItalic, aColor))
00454             return PR_TRUE;
00455   }
00456 
00457   // we know some ATSUI font do not have italic, turn it off and try again
00458   if (aItalic) 
00459   {
00460          if (ATSUIFallbackGetDimensions(aCharPt, oDim, origFontNum, 
00461                                         aSize, PR_FALSE, PR_FALSE, aColor))
00462             return PR_TRUE;
00463   }
00464 
00465   return PR_FALSE;
00466 }
00467 
00468 //------------------------------------------------------------------------
00469 
00470 #ifdef MOZ_MATHML
00471 PRBool
00472 nsUnicodeRenderingToolkit::ATSUIFallbackGetBoundingMetrics(
00473   const PRUnichar *aCharPt,
00474   nsBoundingMetrics& oBoundingMetrics,
00475   short origFontNum,
00476   short aSize, PRBool aBold, PRBool aItalic, nscolor aColor)
00477 {
00478 
00479   nsMacUnicodeFontInfo info;
00480   if (nsATSUIUtils::IsAvailable()  
00481       && (IN_STANDARD_MAC_ROMAN_FONT(*aCharPt) 
00482          ||IN_SYMBOL_FONT(*aCharPt)
00483          ||SPECIAL_IN_SYMBOL_FONT(*aCharPt)
00484          ||info.HasGlyphFor(*aCharPt)))
00485   {
00486     mATSUIToolkit.PrepareToDraw(mPort, mContext );
00487     nsresult res;
00488     if (SPECIAL_IN_SYMBOL_FONT(*aCharPt))
00489     {
00490       short rep = 0;
00491       if ((*aCharPt) > 0x230b)
00492          rep = (*aCharPt) - 0x2325;
00493       else
00494          rep = (*aCharPt) - 0x2308;
00495       res = mATSUIToolkit.GetBoundingMetrics(gSymbolReplacement+rep, 1, oBoundingMetrics, aSize, 
00496                                              origFontNum, 
00497                                              aBold, aItalic, aColor);
00498     }
00499     else
00500     {
00501       res = mATSUIToolkit.GetBoundingMetrics(aCharPt, 1, oBoundingMetrics, aSize, 
00502                                              origFontNum, 
00503                                              aBold, aItalic, aColor);
00504     }
00505     if (NS_SUCCEEDED(res))
00506       return PR_TRUE;
00507   }
00508 
00509   if (IN_ARABIC_PRESENTATION_A_OR_B(*aCharPt))
00510   {  
00511     PRUnichar isolated;
00512     if (NS_SUCCEEDED(FormAorBIsolated(*aCharPt, info, &isolated)))
00513     {
00514       if (ATSUIFallbackGetBoundingMetrics(&isolated, oBoundingMetrics, origFontNum, 
00515                                           aSize, aBold, aItalic, aColor))
00516         return PR_TRUE;
00517     }                                                 
00518   }
00519 
00520   // we know some ATSUI font do not have bold, turn it off and try again
00521   if (aBold)
00522   {
00523     if (ATSUIFallbackGetBoundingMetrics(aCharPt, oBoundingMetrics, origFontNum, 
00524                                         aSize, PR_FALSE, aItalic, aColor))
00525       return PR_TRUE;
00526   }
00527 
00528   // we know some ATSUI font do not have italic, turn it off and try again
00529   if (aItalic) 
00530   {
00531     if (ATSUIFallbackGetBoundingMetrics(aCharPt, oBoundingMetrics, origFontNum, 
00532                                         aSize, PR_FALSE, PR_FALSE, aColor))
00533       return PR_TRUE;
00534   }
00535 
00536   return PR_FALSE;
00537 }
00538 #endif // MOZ_MATHML
00539 
00540 //------------------------------------------------------------------------
00541 
00542 PRBool nsUnicodeRenderingToolkit :: ATSUIFallbackDrawChar(
00543   const PRUnichar *aCharPt, 
00544   PRInt32 x,   PRInt32 y, 
00545   short& oWidth, 
00546   short origFontNum,
00547   short aSize, PRBool aBold, PRBool aItalic, nscolor aColor) 
00548 {
00549   nsMacUnicodeFontInfo info;
00550   if (nsATSUIUtils::IsAvailable()  
00551       && (IN_STANDARD_MAC_ROMAN_FONT(*aCharPt) 
00552          ||IN_SYMBOL_FONT(*aCharPt)
00553          ||SPECIAL_IN_SYMBOL_FONT(*aCharPt)
00554          ||info.HasGlyphFor(*aCharPt)))
00555   {
00556     mATSUIToolkit.PrepareToDraw(mPort, mContext );
00557     nsresult res;
00558     if(SPECIAL_IN_SYMBOL_FONT(*aCharPt)) 
00559     {
00560       short rep = 0;
00561       if ((*aCharPt) > 0x230b)
00562         rep = (*aCharPt) - 0x2325;
00563       else 
00564         rep = (*aCharPt) - 0x2308;
00565       res = mATSUIToolkit.DrawString(gSymbolReplacement+rep, 1, x, y, oWidth, aSize, 
00566                                      origFontNum, 
00567                                      aBold, aItalic, aColor);
00568     } else {
00569       res = mATSUIToolkit.DrawString(aCharPt, 1, x, y, oWidth, aSize, 
00570                                      origFontNum, 
00571                                      aBold, aItalic, aColor);
00572     }
00573     if (NS_SUCCEEDED(res))
00574       return PR_TRUE;
00575   }
00576 
00577   if (IN_ARABIC_PRESENTATION_A_OR_B(*aCharPt))
00578   {      
00579     PRUnichar isolated;
00580     if (NS_SUCCEEDED(FormAorBIsolated(*aCharPt, info, &isolated))) {
00581       if (ATSUIFallbackDrawChar(&isolated, x, y, oWidth, origFontNum, 
00582                                 aSize, aBold, aItalic, aColor))
00583          return PR_TRUE;
00584     }                                                 
00585   }
00586 
00587   // we know some ATSUI font do not have bold, turn it off and try again
00588   if (aBold)
00589   {
00590     if (ATSUIFallbackDrawChar(aCharPt, x, y, oWidth, origFontNum, 
00591                               aSize, PR_FALSE, aItalic, aColor))
00592        return PR_TRUE;
00593   }
00594 
00595   // we know some ATSUI font do not have italic, turn it off and try again
00596   if (aItalic)
00597   {
00598     if (ATSUIFallbackDrawChar(aCharPt, x, y, oWidth, origFontNum, 
00599                               aSize, PR_FALSE, PR_FALSE, aColor))
00600        return PR_TRUE;
00601   }
00602 
00603   return PR_FALSE;
00604 }
00605 
00606 PRBool  nsUnicodeRenderingToolkit :: SurrogateGetDimensions(
00607   const PRUnichar *aSurrogatePt, nsTextDimensions& oDim, short origFontNum,  
00608   short aSize, PRBool aBold, PRBool aItalic, nscolor aColor)
00609 {
00610   nsresult res;
00611   mATSUIToolkit.PrepareToDraw(mPort, mContext );
00612   res = mATSUIToolkit.GetTextDimensions(aSurrogatePt, 2, oDim, aSize, 
00613                                         origFontNum, 
00614                                         aBold, aItalic, aColor);
00615   return NS_SUCCEEDED(res);
00616 }
00617 
00618 PRBool  nsUnicodeRenderingToolkit :: SurrogateDrawChar(
00619   const PRUnichar *aSurrogatePt, PRInt32 x, PRInt32 y, short& oWidth, short origFontNum, 
00620   short aSize, PRBool aBold, PRBool aItalic, nscolor aColor)
00621 {
00622   nsresult res;
00623   mATSUIToolkit.PrepareToDraw(mPort, mContext );
00624   res = mATSUIToolkit.DrawString(aSurrogatePt, 2, x, y, oWidth, aSize, 
00625                                  origFontNum, 
00626                                  aBold, aItalic, aColor);
00627   return NS_SUCCEEDED(res);
00628 }
00629 
00630 #ifdef MOZ_MATHML
00631 PRBool  nsUnicodeRenderingToolkit :: SurrogateGetBoundingMetrics(
00632   const PRUnichar *aSurrogatePt, nsBoundingMetrics& oBoundingMetrics, short origFontNum,
00633   short aSize, PRBool aBold, PRBool aItalic, nscolor aColor)
00634 {
00635   nsresult res;
00636   mATSUIToolkit.PrepareToDraw(mPort, mContext );
00637   res = mATSUIToolkit.GetBoundingMetrics(aSurrogatePt, 2, oBoundingMetrics, aSize, 
00638                                              origFontNum, 
00639                                              aBold, aItalic, aColor);
00640 
00641   return NS_SUCCEEDED(res);
00642 }
00643 #endif
00644 
00645 static const char question[] = "<?>";
00646 
00647 //------------------------------------------------------------------------
00648 
00649 PRBool nsUnicodeRenderingToolkit :: QuestionMarkFallbackGetWidth(
00650        const PRUnichar *aCharPt, 
00651        short& oWidth)
00652 {
00653   CGrafPtr thePort;
00654   ::GetPort((GrafPtr*)&thePort);
00655   short saveSize = ::GetPortTextSize(thePort);          
00656   ::TextSize(QUESTION_FALLBACKSIZE);
00657   GetScriptTextWidth(question, 3,oWidth);
00658   ::TextSize(saveSize);
00659   return PR_TRUE;
00660 }
00661 //------------------------------------------------------------------------
00662 
00663 PRBool nsUnicodeRenderingToolkit :: QuestionMarkFallbackDrawChar(
00664        const PRUnichar *aCharPt, 
00665        PRInt32 x, 
00666        PRInt32 y, 
00667        short& oWidth)
00668 {
00669   CGrafPtr thePort;
00670   ::GetPort((GrafPtr*)&thePort);
00671   short saveSize = ::GetPortTextSize(thePort);          
00672   ::TextSize(QUESTION_FALLBACKSIZE);
00673   DrawScriptText(question, 3, x, y, oWidth);
00674   ::TextSize(saveSize);
00675   return PR_TRUE;
00676 }
00677 //------------------------------------------------------------------------
00678 PRBool nsUnicodeRenderingToolkit :: LoadTransliterator()
00679 {
00680        if(mTrans) 
00681               return PR_TRUE;
00682               
00683        nsresult res;
00684     mTrans = do_CreateInstance(kSaveAsCharsetCID, &res);
00685     if ( NS_SUCCEEDED(res) )
00686     {
00687        res = mTrans->Init("x-mac-roman",
00688                nsISaveAsCharset::attr_FallbackQuestionMark +
00689                nsISaveAsCharset::attr_EntityBeforeCharsetConv +
00690                nsISaveAsCharset::attr_IgnoreIgnorables,
00691                nsIEntityConverter::transliterate);
00692       NS_ASSERTION(NS_SUCCEEDED(res), "cannot init the converter");
00693       if (NS_FAILED(res)) 
00694       {
00695         mTrans = nsnull;
00696         return PR_FALSE;
00697       }
00698     }
00699     return PR_TRUE;
00700 }
00701 //------------------------------------------------------------------------
00702 PRBool nsUnicodeRenderingToolkit :: TransliterateFallbackGetWidth(
00703        const PRUnichar *aCharPt, 
00704        short& oWidth)
00705 {
00706   if(LoadTransliterator()) {
00707     nsAutoString tmp(aCharPt, 1);
00708     char* conv = nsnull;
00709     if(NS_SUCCEEDED(mTrans->Convert(tmp.get(), &conv)) && conv) {
00710       CGrafPtr thePort;
00711       ::GetPort((GrafPtr*)&thePort);
00712            short aSize = ::GetPortTextSize(thePort);                         
00713               PRInt32 l=strlen(conv);
00714        if((l>3) && ('^' == conv[0]) && ('(' == conv[1]) && (')' == conv[l-1])) // sup
00715        {
00716               short small = aSize * 2 / 3;
00717               ::TextSize(small);
00718                      GetScriptTextWidth(conv+2, l-3,oWidth);   
00719               ::TextSize(aSize);
00720        } 
00721        else if((l>3) && ('v' == conv[0]) && ('(' == conv[1]) && (')' == conv[l-1])) // sub
00722        {
00723               short small = aSize * 2 / 3;
00724               ::TextSize(small);
00725                      GetScriptTextWidth(conv+2, l-3,oWidth);   
00726               ::TextSize(aSize);
00727               } 
00728               else if((l>1) && ('0' <= conv[0]) && ( conv[0] <= '9') && ('/' == conv[1])) // fract
00729        {
00730               short small = aSize * 2 / 3;
00731               short tmpw=0;
00732               
00733               ::TextSize(small);
00734                      GetScriptTextWidth(conv, 1 ,tmpw);   
00735                      oWidth = tmpw;
00736               
00737               ::TextSize(aSize);
00738                      GetScriptTextWidth(conv+1, 1,tmpw);   
00739               oWidth += tmpw;
00740               
00741               if(l>2) {
00742                      ::TextSize(small);
00743                             GetScriptTextWidth(conv+2, l-2,tmpw);   
00744                      oWidth += tmpw;
00745                      ::TextSize(aSize);
00746               }
00747        } else {
00748                      GetScriptTextWidth(conv, l,oWidth);   
00749               }
00750               
00751                
00752        nsMemory::Free(conv);
00753        return PR_TRUE;
00754     }
00755   }
00756   return PR_FALSE;
00757 }
00758 //------------------------------------------------------------------------
00759 
00760 PRBool nsUnicodeRenderingToolkit :: TransliterateFallbackDrawChar(
00761        const PRUnichar *aCharPt, 
00762        PRInt32 x, 
00763        PRInt32 y, 
00764        short& oWidth)
00765 {
00766   if(LoadTransliterator()) {
00767     nsAutoString tmp(aCharPt, 1);
00768     char* conv = nsnull;
00769     if(NS_SUCCEEDED(mTrans->Convert(tmp.get(), &conv)) && conv) {
00770            CGrafPtr thePort;
00771            ::GetPort((GrafPtr*)&thePort);
00772            short aSize = ::GetPortTextSize(thePort);           
00773        PRInt32 l=strlen(conv);
00774        if((l>3) && ('^' == conv[0]) && ('(' == conv[1]) && (')' == conv[l-1])) // sup
00775        {
00776               short small = aSize * 2 / 3;
00777               ::TextSize(small);
00778               DrawScriptText(conv+2, l-3, x, y-small/2, oWidth);
00779               ::TextSize(aSize);
00780        } 
00781        else if((l>3) && ('v' == conv[0]) && ('(' == conv[1]) && (')' == conv[l-1])) // sub
00782        {
00783               short small = aSize * 2 / 3;
00784               ::TextSize(small);
00785               DrawScriptText(conv+2, l-3, x, y+small/2, oWidth);
00786               ::TextSize(aSize);
00787               } 
00788               else if((l>1) && ('0' <= conv[0]) && ( conv[0] <= '9') && ('/' == conv[1])) // fract
00789        {
00790               short small = aSize * 2 / 3;
00791               short tmpw=0;
00792               
00793               ::TextSize(small);
00794               DrawScriptText(conv, 1, x, y-small/2, tmpw);
00795               oWidth = tmpw;
00796               
00797               ::TextSize(aSize);
00798               DrawScriptText(conv+1, 1, x+oWidth, y, tmpw);
00799               oWidth += tmpw;
00800               
00801               if(l>2) {
00802                      ::TextSize(small);
00803                      DrawScriptText(conv+2, l-2, x+oWidth, y+small/2, tmpw);
00804                      oWidth += tmpw;
00805                      ::TextSize(aSize);
00806               }
00807        } else {
00808                      DrawScriptText(conv, l, x, y, oWidth);
00809               }
00810        nsMemory::Free(conv);
00811        return PR_TRUE;
00812     }
00813   }
00814   return PR_FALSE;
00815 }
00816 //------------------------------------------------------------------------
00817 #define CAN_DO_PRECOMPOSE_HANGUL(u, f) ((0xAC00<=(u)) && ((u)<=0xD7FF) && ((f) != BAD_FONT_NUM))
00818 #define SBase 0xAC00
00819 #define LCount 19
00820 #define VCount 21
00821 #define TCount 28
00822 #define NCount (VCount * TCount)
00823 static void UnicodePrecomposedHangulTo4EUCKR(PRUnichar in, char *out)
00824 {
00825         static const PRUint8 lMap[LCount] = {
00826           0xa1, 0xa2, 0xa4, 0xa7, 0xa8, 0xa9, 0xb1, 0xb2, 0xb3, 0xb5,
00827           0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe
00828         };
00829 
00830         static const PRUint8 tMap[TCount] = {
00831           0xd4, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa9, 0xaa, 
00832           0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb4, 0xb5, 
00833           0xb6, 0xb7, 0xb8, 0xba, 0xbb, 0xbc, 0xbd, 0xbe
00834         };
00835         PRUint16 SIndex, LIndex, VIndex, TIndex;
00836         /* the following line are copy from Unicode 2.0 page 3-13 */
00837         /* item 1 of Hangul Syllabel Decomposition */
00838         SIndex =  in - SBase;
00839 
00840         /* the following lines are copy from Unicode 2.0 page 3-14 */
00841         /* item 2 of Hangul Syllabel Decomposition w/ modification */
00842         LIndex = SIndex / NCount;
00843         VIndex = (SIndex % NCount) / TCount;
00844         TIndex = SIndex % TCount;
00845               // somehow Apple's Korean font show glaph on A4D4 :( so we use '[' + L + V + T + ']' intead of 
00846               // Filler + L + V + T to display
00847               // output '['
00848               *out++ = '['; 
00849               // output L
00850               *out++ = 0xA4;
00851               *out++ = lMap[LIndex] ;
00852               // output V
00853               *out++ = 0xA4;
00854               *out++  = (VIndex + 0xbf);
00855               // output T
00856               *out++ = 0xA4;
00857               *out++ = tMap[TIndex] ;
00858               // output ']'
00859               *out++ = ']'; 
00860 }
00861     
00862 //------------------------------------------------------------------------
00863 PRBool nsUnicodeRenderingToolkit :: PrecomposeHangulFallbackGetWidth(
00864        const PRUnichar *aCharPt, 
00865        short& oWidth,
00866        short koreanFont,
00867        short origFont)
00868 {
00869   if(CAN_DO_PRECOMPOSE_HANGUL(*aCharPt, koreanFont)) {
00870          char euckr[8];
00871          if(koreanFont != origFont)
00872               ::TextFont(koreanFont);              
00873          UnicodePrecomposedHangulTo4EUCKR(*aCharPt, euckr);
00874          GetScriptTextWidth(euckr, 8, oWidth); 
00875          if(koreanFont != origFont)
00876               ::TextFont(origFont);                
00877          return PR_TRUE;
00878   } else {
00879          return PR_FALSE;
00880   }
00881 }
00882 //------------------------------------------------------------------------
00883 
00884 PRBool nsUnicodeRenderingToolkit :: PrecomposeHangulFallbackDrawChar(
00885        const PRUnichar *aCharPt, 
00886        PRInt32 x, 
00887        PRInt32 y, 
00888        short& oWidth,
00889        short koreanFont,
00890        short origFont)
00891 {
00892   if(CAN_DO_PRECOMPOSE_HANGUL(*aCharPt, koreanFont)) {
00893          char euckr[8];
00894          if(koreanFont != origFont)
00895               ::TextFont(koreanFont);              
00896          UnicodePrecomposedHangulTo4EUCKR(*aCharPt, euckr);
00897          DrawScriptText(euckr, 8, x, y, oWidth); 
00898          if(koreanFont != origFont)
00899               ::TextFont(origFont);                
00900          return PR_TRUE;
00901   } else {
00902          return PR_FALSE;
00903   }
00904 }
00905 //------------------------------------------------------------------------
00906 
00907 PRBool nsUnicodeRenderingToolkit :: UPlusFallbackGetWidth(
00908        const PRUnichar *aCharPt, 
00909        short& oWidth)
00910 {
00911   CGrafPtr thePort;
00912   ::GetPort((GrafPtr*)&thePort);
00913   short saveSize = ::GetPortTextSize(thePort);          
00914   char buf[16];
00915   PRUint32 len = PR_snprintf(buf, 16 , "<U+%04X>", *aCharPt);
00916   ::TextSize(UPLUS_FALLBACKSIZE);
00917   if(len != -1) 
00918     GetScriptTextWidth(buf, len, oWidth);
00919   ::TextSize(saveSize);
00920   return (-1 != len);
00921 }
00922 //------------------------------------------------------------------------
00923 
00924 PRBool nsUnicodeRenderingToolkit :: UPlusFallbackDrawChar(
00925        const PRUnichar *aCharPt, 
00926        PRInt32 x, 
00927        PRInt32 y, 
00928        short& oWidth)
00929 {
00930   CGrafPtr thePort;
00931   ::GetPort((GrafPtr*)&thePort);
00932   short saveSize = ::GetPortTextSize(thePort);          
00933   char buf[16];
00934   PRUint32 len = PR_snprintf(buf, 16 , "<U+%04X>", *aCharPt);
00935   ::TextSize(UPLUS_FALLBACKSIZE);
00936   if(len != -1) 
00937     DrawScriptText(buf, len, x, y, oWidth);
00938   ::TextSize(saveSize);
00939   return (-1 != len);
00940 }
00941 //------------------------------------------------------------------------
00942 /*
00943 # capital mean above
00944 # small mean below
00945 # r - ring below
00946 # R - Ring Above
00947 # d - dot below
00948 # D - Dot Above
00949 # l - line below
00950 # L - Line Above
00951 # c - cedilla
00952 # A - Acute
00953 # x - circumflex below
00954 # X - Circumflex Above
00955 # G - Grave above
00956 # T - Tilde above
00957 # t - tilde below
00958 # B - Breve Above
00959 # b - breve below
00960 # U - Diaeresis Above
00961 # u - diaeresis below
00962 # H - Hook Above 
00963 # N - Horn Above
00964 */
00965 static const char * const g1E00Dec = 
00966 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1E00 - U+1E0F
00967  "Ar ar BD bD Bd bd Bl bl CcAccADD dD Dd dd Dl dl "
00968 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1E10 - U+1E1F
00969  "Dc dc Dx dx ELGeLGELAeLAEx ex Et et EcBecBFD fD "
00970 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1E20 - U+1E2F
00971  "GL gL HD hD Hd hd HU hU Hc hc Hb hb It it IUAiUA"
00972 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1E30 - U+1E3F
00973  "KA kA Kd kd Kl kl Ld ld LdLldLLl ll Lx lx MA mA "
00974 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1E40 - U+1E4F
00975  "MD mD Md md ND nD Nd nd Nl nl Nx nx OTAoTAOTUoTU"
00976 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1E50 - U+1E5F
00977  "OLGoLGOLAoLAPA pA PD pD RD rD Rd rd RdLrdLRl rl "
00978 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1E60 - U+1E6F
00979  "SD sD Sd sd SADsADSBDsBDSdDsdDTD tD Td td Tl tl "
00980 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1E70 - U+1E7F
00981  "Tx tx Uu uu Ut ut Ux ux UTAuTAULUuLUVT vT Vd vd "
00982 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1E80 - U+1E8F
00983  "WG wG WA wA WU wU WD wD Wd wd XD xD XU xU YD Yd "
00984 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1E90 - U+1E9F
00985  "ZX zX Zd zd Zl zl Hl tU wR yR aH                "
00986 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1EA0 - U+1EAF
00987  "Ad ad AH aH AXAaXAAXGaXGAXHaXHAXTaXTAdXadXABAaBA"
00988 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1EB0 - U+1EBF
00989  "ABGaBGABHaBHABTaBTAdBadBEd ed EH eH ET eT EXAeXA"
00990 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1EC0 - U+1ECF
00991  "EXGeXGEXHeXHEXTeXTEdXedXIH iH Id id Od od OH oH "
00992 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1ED0 - U+1EDF
00993  "OXAoXAOXGoXGOXHoXHOXToXTOdXodXOAnoAnOGnoGnOHnoHn"
00994 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1EE0 - U+1EEF
00995  "OHToHTOdTodTUd ud UH uh UAnuAnUGnuGnUHnuHnUTnuTn"
00996 //0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   U+1EF0 - U+1EFF
00997  "UdnudnYG yG Yd yd YH yH YT yT                   "
00998 ;
00999 //------------------------------------------------------------------------
01000 static void CCodeToMacRoman(char aIn, char& aOut,short aWidth, short aHeight, short& oXadj, short& oYadj)
01001 {
01002        aOut = ' ';
01003        oXadj = oYadj = 0;
01004        switch(aIn)
01005        {
01006               case 'r' : aOut = '\xfb'; oYadj = aHeight * 5 / 6; break ;// # r - ring below
01007               case 'R' : aOut = '\xfb';                          break ;// # R - Ring Above
01008               case 'd' : aOut = '\xfa'; oYadj = aHeight * 5 / 6; break ;// # d - dot below
01009               case 'D' : aOut = '\xfa';                          break ;// # D - Dot Above
01010               case 'l' : aOut = '_';                             break ;// # l - line below
01011               case 'L' : aOut = '\xf8';                          break ;// # L - Line Above
01012               case 'c' : aOut = '\xfc';                          break ;// # c - cedilla
01013               case 'A' : aOut = '\xab';                          break ;// # A - Acute
01014               case 'x' : aOut = '\xf6'; oYadj= aHeight * 5 / 6;  break ;// # x - circumflex below
01015               case 'X' : aOut = '\xf6';                          break ;// # X - Circumflex Above
01016               case 'G' : aOut = '`';                             break ;// # G - Grave above
01017               case 'T' : aOut = '\xf7';                          break ;// # T - Tilde above
01018               case 't' : aOut = '\xf7'; oYadj= aHeight * 5 / 6;  break ;// # t - tilde below
01019               case 'B' : aOut = '\xf9';                          break ;// # B - Breve Above
01020               case 'b' : aOut = '\xf9'; oYadj= aHeight * 5 / 6;  break ;// # b - breve below
01021               case 'U' : aOut = '\xac';                          break ;// # U - Diaeresis Above
01022               case 'u' : aOut = '\xac'; oYadj= aHeight * 5 / 6;  break ;// # u - diaeresis below
01023               case 'H' : aOut = ',';    oYadj= - aHeight * 5 / 6;  break ;// # H - Hook Above 
01024               case 'n' : aOut = ',';    oYadj= - aHeight * 5 / 6;  oXadj = aWidth /4; break ;// # N - Horn Above
01025               default: NS_ASSERTION(0, "unknown ccode");
01026                       break;       
01027        }
01028 }
01029 
01030 PRBool nsUnicodeRenderingToolkit :: LatinFallbackGetWidth(
01031        const PRUnichar *aCharPt, 
01032        short& oWidth)
01033 {
01034   if(0x1E00 == (0xFF00 & *aCharPt)) 
01035   {
01036        PRInt32 idx = 3 * ( *aCharPt & 0x00FF);
01037        if(' ' != g1E00Dec[idx])
01038        {
01039               GetScriptTextWidth(g1E00Dec+idx, 1, oWidth);
01040               return PR_TRUE;
01041        }
01042   }
01043   return PR_FALSE;
01044 }
01045 //------------------------------------------------------------------------
01046 
01047 PRBool nsUnicodeRenderingToolkit :: LatinFallbackDrawChar(
01048        const PRUnichar *aCharPt, 
01049        PRInt32 x, 
01050        PRInt32 y, 
01051        short& oWidth)
01052 {
01053   if(0x1E00 == (0xFF00 & *aCharPt)) 
01054   {
01055        PRInt32 idx = 3 * ( *aCharPt & 0x00FF);
01056        if(' ' != g1E00Dec[idx])
01057        {
01058       CGrafPtr thePort;
01059       ::GetPort((GrafPtr*)&thePort);
01060            short aSize = ::GetPortTextSize(thePort);    
01061            short dummy;
01062            short realwidth;
01063               char comb[2];
01064               short xadj;
01065               short yadj;
01066               short yadjB=0;
01067               
01068               PRBool baseTooBig =  ('A'<= g1E00Dec[idx]  ) && (g1E00Dec[idx] <= 'Z'  ) 
01069                                    || ('f' == g1E00Dec[idx])|| ('l' == g1E00Dec[idx])|| ('k' == g1E00Dec[idx]);
01070               PRBool firstIsAbove    = ('A'<= g1E00Dec[idx+1]) && (g1E00Dec[idx+1] <= 'Z') ;
01071               PRBool secondIsAbove   = ('A'<= g1E00Dec[idx+2]) && (g1E00Dec[idx+2] <= 'Z') ;
01072               
01073               GetScriptTextWidth(g1E00Dec+idx, 1, oWidth);
01074               if(baseTooBig && (firstIsAbove ||secondIsAbove ))
01075               ::TextSize(aSize *3/4);            
01076 
01077               DrawScriptText(g1E00Dec+idx, 1, x, y, realwidth);
01078 
01079               if(baseTooBig && (firstIsAbove ||secondIsAbove ))
01080                      ::TextSize(aSize);                 
01081               if(' ' != g1E00Dec[idx+1]) {
01082                      CCodeToMacRoman(g1E00Dec[idx+1],comb[0], realwidth, aSize, xadj, yadj);
01083                      
01084                      GetScriptTextWidth(comb, 1, dummy);
01085                      
01086                      DrawScriptText( comb, 1, x + xadj + ( realwidth - dummy ) / 2, y + yadj + yadjB, dummy);
01087               }
01088               if(' ' != g1E00Dec[idx+2]) {
01089                      if( firstIsAbove && secondIsAbove)
01090                             yadjB = yadjB - aSize / 6;         
01091               
01092                      CCodeToMacRoman(g1E00Dec[idx+2],comb[0], realwidth, aSize, xadj, yadj);
01093                      GetScriptTextWidth(comb, 1, dummy);
01094                      DrawScriptText( comb, 1, x + xadj+ ( realwidth - dummy ) / 2, y+ yadj + yadjB, dummy);
01095               }
01096               return PR_TRUE;
01097        }
01098   }
01099   return PR_FALSE;
01100 }
01101 
01102 //------------------------------------------------------------------------
01103 void nsUnicodeRenderingToolkit :: GetScriptTextWidth(
01104        const char* buf, 
01105        ByteCount aLen, 
01106        short& oWidth)
01107 {
01108        oWidth = ::TextWidth(buf, 0, aLen);
01109 }
01110 
01111 #if MOZ_MATHML
01112 //------------------------------------------------------------------------
01113 void nsUnicodeRenderingToolkit::GetScriptTextBoundingMetrics(
01114     const char* buf,
01115     ByteCount aLen,
01116     ScriptCode aScript,
01117     nsBoundingMetrics& oBoundingMetrics)
01118 {
01119     Point scale = { 1, 1 };
01120     Fixed stackWidths[STACK_TRESHOLD], *widths;
01121     Fixed stackLefts[STACK_TRESHOLD], *lefts;
01122     Rect stackRects[STACK_TRESHOLD], *rects;
01123     OSStatus err;
01124 
01125     NS_PRECONDITION(aLen > 0, "length must be greater than 0");
01126 
01127     if(aLen > STACK_TRESHOLD)
01128     {
01129         widths = (Fixed*) nsMemory::Alloc(aLen * sizeof(Fixed));
01130         lefts = (Fixed*) nsMemory::Alloc(aLen * sizeof(Fixed));
01131         rects = (Rect*) nsMemory::Alloc(aLen * sizeof(Rect));
01132         
01133         // if any of the allocations failed the 'else' case below will be executed
01134     }
01135     else
01136     {
01137         widths = stackWidths;
01138         lefts = stackLefts;
01139         rects = stackRects;
01140     }
01141 
01142     if(!GetOutlinePreferred())
01143         SetOutlinePreferred(PR_TRUE);
01144 
01145     if(widths && lefts && rects &&
01146         (err = ::OutlineMetrics(aLen, buf, scale, scale, NULL, NULL, widths, lefts, rects)) == noErr)
01147     {
01148         ByteCount byteIndex = 0, glyphIndex = 0;
01149 
01150         while(byteIndex < aLen)
01151         {
01152             nsBoundingMetrics bounds;
01153             bounds.leftBearing = rects[glyphIndex].left + FixRound(lefts[glyphIndex]);
01154             bounds.rightBearing = rects[glyphIndex].right + FixRound(lefts[glyphIndex]);
01155             bounds.ascent = rects[glyphIndex].bottom;
01156             bounds.descent = -rects[glyphIndex].top;
01157             bounds.width = FixRound(widths[glyphIndex]);
01158 
01159             if(glyphIndex == 0)
01160                 oBoundingMetrics = bounds;
01161             else
01162                 oBoundingMetrics += bounds;
01163 
01164             // for two byte characters byteIndex will increase by 2
01165             //   while glyph index will only increase by 1
01166             if(CharacterByteType((Ptr) buf, byteIndex, aScript) == smFirstByte)
01167                 byteIndex += 2;
01168             else
01169                 byteIndex++;
01170             glyphIndex++;
01171         }
01172     }
01173     else
01174     {
01175         NS_WARNING("OulineMetrics failed");
01176 
01177         FontInfo fInfo;
01178         ::GetFontInfo(&fInfo);
01179 
01180         oBoundingMetrics.leftBearing = 0;
01181         oBoundingMetrics.rightBearing = ::TextWidth(buf, 0, aLen);
01182         oBoundingMetrics.ascent = fInfo.ascent;
01183         oBoundingMetrics.descent = fInfo.descent;
01184         oBoundingMetrics.width = oBoundingMetrics.rightBearing;
01185     }
01186 
01187     if(aLen > STACK_TRESHOLD)
01188     {
01189         if(widths)
01190             nsMemory::Free(widths);
01191         if(lefts)
01192             nsMemory::Free(lefts);
01193         if(rects)
01194             nsMemory::Free(rects);
01195     }
01196 }
01197 #endif // MOZ_MATHML
01198 
01199 //------------------------------------------------------------------------
01200 void nsUnicodeRenderingToolkit :: DrawScriptText(
01201        const char* buf, 
01202        ByteCount aLen, 
01203        PRInt32 x, 
01204        PRInt32 y, 
01205        short& oWidth)
01206 {
01207        ::MoveTo(x, y);
01208        ::DrawText(buf,0,aLen);
01209        
01210        Point   penLoc;
01211        ::GetPen(&penLoc);
01212        oWidth = penLoc.h - x;
01213 }
01214 //------------------------------------------------------------------------
01215 
01216 nsresult 
01217 nsUnicodeRenderingToolkit::GetTextSegmentWidth(
01218                      const PRUnichar *aString, PRUint32 aLength, 
01219                      short fontNum, nsUnicodeFontMappingMac& fontMapping, 
01220                      PRUint32& oWidth)
01221 {
01222   nsTextDimensions dim;
01223   nsresult res = GetTextSegmentDimensions(aString, aLength, fontNum, fontMapping, dim);
01224   oWidth = dim.width;
01225   return res;
01226 }
01227 //------------------------------------------------------------------------
01228 
01229 
01230 nsresult 
01231 nsUnicodeRenderingToolkit::GetTextSegmentDimensions(
01232       const PRUnichar *aString, PRUint32 aLength, 
01233       short fontNum, nsUnicodeFontMappingMac& fontMapping, 
01234       nsTextDimensions& oDim)
01235 {
01236   oDim.Clear();
01237   if(aLength == 0 || fontNum == IGNORABLE_FONT_NUM) 
01238     return NS_OK;
01239   NS_PRECONDITION(BAD_FONT_NUM != fontNum, "illegal font num");
01240   PRUint32 processLen = 0;
01241   char *heapBuf = nsnull;
01242   PRUint32 heapBufSize = 0;
01243   short thisWidth = 0;
01244   char stackBuf[STACK_TRESHOLD];
01245   char *buf ;
01246   ByteCount processBytes;
01247   ByteCount outLen;
01248   const short *scriptFallbackFonts = fontMapping.GetScriptFallbackFonts();
01249   
01250   ::TextFont(fontNum);
01251   
01252   FontInfo fInfo;
01253   ::GetFontInfo(&fInfo);
01254   nsTextDimensions segDim;
01255   segDim.ascent = fInfo.ascent;
01256   segDim.descent = fInfo.descent;
01257   oDim.Combine(segDim);
01258   
01259   // find buf from stack or heap. We only need to do this once in this function.
01260   // put this out of the loop for performance...
01261   ByteCount bufLen = aLength * 2 + 10;
01262   if (bufLen > STACK_TRESHOLD)
01263   {
01264     if (bufLen > heapBufSize)
01265     {
01266       if (heapBuf)
01267         nsMemory::Free(heapBuf);
01268       heapBuf = (char*) nsMemory::Alloc(bufLen);
01269       heapBufSize = bufLen;
01270       if (nsnull == heapBuf) 
01271         return NS_ERROR_OUT_OF_MEMORY;
01272     } 
01273     buf = heapBuf;
01274   } 
01275   else 
01276   {
01277     bufLen = STACK_TRESHOLD;
01278     buf = stackBuf;
01279   }
01280   do {
01281     outLen = 0;
01282     processBytes = 0;
01283 
01284     if(fontMapping.ConvertUnicodeToGlyphs(fontNum, aString, aLength - processLen,
01285             buf, bufLen, outLen, processBytes, 0))
01286     {
01287         GetScriptTextWidth(buf, outLen, thisWidth);
01288       
01289         segDim.Clear();
01290         segDim.width = thisWidth;
01291         oDim.Combine(segDim);
01292     
01293         NS_PRECONDITION(0 == (processBytes % 2), "strange conversion result");
01294     
01295         PRInt32 processUnicode = processBytes / 2;
01296         processLen += processUnicode;
01297         aString += processUnicode;
01298     }
01299          
01300     // Cannot precess by TEC, process one char a time by fallback mechanism
01301     if (processLen < aLength)
01302     {
01303       PRBool fallbackDone = PR_FALSE;
01304       segDim.Clear();
01305       
01306       if (IS_HIGH_SURROGATE(*aString) && 
01307           ((processLen+1) < aLength) &&
01308           IS_LOW_SURROGATE(*(aString+1)))
01309       {
01310          const nsFont *font = &mGS->mFontMetrics->Font();
01311          fallbackDone = SurrogateGetDimensions(aString, segDim, fontNum, 
01312                                                font->size, 
01313                                                (font->weight > NS_FONT_WEIGHT_NORMAL), 
01314                                                ((NS_FONT_STYLE_ITALIC ==  font->style) || 
01315                                                (NS_FONT_STYLE_OBLIQUE ==  font->style)),
01316                                                mGS->mColor );     
01317          if (fallbackDone)
01318          {   
01319            oDim.Combine(segDim);    
01320            // for fallback measure/drawing, we always do one char a time.
01321            aString += 2;
01322            processLen += 2;
01323            continue;
01324          }
01325       }
01326 #ifndef DISABLE_TEC_FALLBACK
01327       // Fallback by try different Script code
01328       if (! IS_SKIP_TEC_FALLBACK(*aString))
01329         fallbackDone = TECFallbackGetDimensions(aString, segDim, fontNum, fontMapping);
01330 #endif
01331 
01332       //
01333       // We really don't care too much of performance after this
01334       // This will only be called when we cannot display this character in ANY mac script avaliable
01335       // 
01336 #ifndef DISABLE_ATSUI_FALLBACK  
01337       // Fallback by using ATSUI
01338       if (!fallbackDone)  
01339       {
01340         const nsFont *font = &mGS->mFontMetrics->Font();
01341         fallbackDone = ATSUIFallbackGetDimensions(aString, segDim, fontNum, 
01342                                                   font->size, 
01343                                                   (font->weight > NS_FONT_WEIGHT_NORMAL), 
01344                                                   ((NS_FONT_STYLE_ITALIC ==  font->style) || 
01345                                                    (NS_FONT_STYLE_OBLIQUE ==  font->style)),
01346                                                   mGS->mColor );
01347       }
01348 
01349 #endif
01350                 if(! fallbackDone) {
01351                    if(IS_ZERO_WIDTH_CHAR(*aString))
01352                    {
01353                       fallbackDone = PR_TRUE;
01354                    }
01355                 }
01356 #ifndef DISABLE_LATIN_FALLBACK
01357       if (!fallbackDone) 
01358       {
01359         fallbackDone = LatinFallbackGetWidth(aString, thisWidth);
01360         if (fallbackDone)
01361           segDim.width = thisWidth;
01362       }
01363 #endif
01364 #ifndef DISABLE_PRECOMPOSEHANGUL_FALLBACK
01365       if (!fallbackDone)
01366       {
01367         fallbackDone = PrecomposeHangulFallbackGetWidth(aString, thisWidth,
01368                                                         scriptFallbackFonts[smKorean], fontNum);
01369         if (fallbackDone)
01370           segDim.width = thisWidth;
01371       }
01372 #endif
01373 #ifndef DISABLE_TRANSLITERATE_FALLBACK  
01374       // Fallback to Transliteration
01375       if (!fallbackDone) 
01376       {
01377         fallbackDone = TransliterateFallbackGetWidth(aString, thisWidth);
01378         if (fallbackDone)
01379           segDim.width = thisWidth;
01380       }
01381 #endif
01382 #ifndef DISABLE_UPLUS_FALLBACK  
01383       // Fallback to UPlus
01384       if (!fallbackDone)
01385       {
01386         fallbackDone = UPlusFallbackGetWidth(aString, thisWidth);
01387         if (fallbackDone)
01388           segDim.width = thisWidth;
01389       }
01390 #endif
01391         
01392       // Fallback to question mark
01393       if (!fallbackDone) 
01394       {
01395         QuestionMarkFallbackGetWidth(aString, thisWidth);
01396         if (fallbackDone)
01397           segDim.width = thisWidth;
01398       }
01399       
01400       oDim.Combine(segDim);    
01401       // for fallback measure/drawing, we always do one char a time.
01402       aString++;
01403       processLen++;
01404     }
01405   } while (processLen < aLength);
01406     
01407     // release buffer if it is from heap
01408   if (heapBuf)
01409     nsMemory::Free(heapBuf);
01410       
01411   return NS_OK;
01412 }
01413 //------------------------------------------------------------------------
01414 
01415 #ifdef MOZ_MATHML
01416 nsresult
01417 nsUnicodeRenderingToolkit::GetTextSegmentBoundingMetrics(
01418       const PRUnichar *aString, PRUint32 aLength,
01419       short fontNum, nsUnicodeFontMappingMac& fontMapping,
01420       nsBoundingMetrics& oBoundingMetrics)
01421 {
01422   oBoundingMetrics.Clear();
01423   if(aLength == 0 || fontNum == IGNORABLE_FONT_NUM) 
01424     return NS_OK;
01425   NS_PRECONDITION(BAD_FONT_NUM != fontNum, "illegal font num");
01426   PRBool firstTime = PR_TRUE;
01427   PRUint32 processLen = 0;
01428   nsBoundingMetrics segBoundingMetrics;
01429   char *heapBuf = nsnull;
01430   PRUint32 heapBufSize = 0;
01431   char stackBuf[STACK_TRESHOLD];
01432   char *buf;
01433   ByteCount processBytes;
01434   ByteCount outLen;
01435   
01436   ::TextFont(fontNum);
01437   ScriptCode script = ::FontToScript(fontNum);
01438   
01439   // find buf from stack or heap. We only need to do this once in this function.
01440   // put this out of the loop for performance...
01441   ByteCount bufLen = aLength * 2 + 10;
01442   if (bufLen > STACK_TRESHOLD)
01443   {
01444     if (bufLen > heapBufSize)
01445     {
01446       if (heapBuf)
01447         nsMemory::Free(heapBuf);
01448       heapBuf = (char*) nsMemory::Alloc(bufLen);
01449       heapBufSize = bufLen;
01450       if (nsnull == heapBuf) 
01451         return NS_ERROR_OUT_OF_MEMORY;
01452     } 
01453     buf = heapBuf;
01454   } 
01455   else 
01456   {
01457     bufLen = STACK_TRESHOLD;
01458     buf = stackBuf;
01459   }
01460 
01461   do {
01462     outLen = 0;
01463     processBytes = 0;
01464         
01465     if(fontMapping.ConvertUnicodeToGlyphs(fontNum, aString, aLength - processLen,
01466         buf, bufLen, outLen, processBytes, 0))
01467     {
01468         segBoundingMetrics.Clear();
01469         GetScriptTextBoundingMetrics(buf, outLen, script, segBoundingMetrics);
01470         
01471         if(firstTime) {
01472             firstTime = PR_FALSE;
01473             oBoundingMetrics = segBoundingMetrics;
01474         }
01475         else
01476             oBoundingMetrics += segBoundingMetrics;
01477         
01478         NS_PRECONDITION(0 == (processBytes % 2), "strange conversion result");
01479         
01480         PRInt32 processUnicode = processBytes / 2;
01481         processLen += processUnicode;
01482         aString += processUnicode;
01483     }
01484     
01485     // Cannot process by TEC, process one char a time by fallback mechanism
01486     if (processLen < aLength)
01487     {
01488       PRBool fallbackDone = PR_FALSE;
01489       segBoundingMetrics.Clear();
01490 
01491       if (IS_HIGH_SURROGATE(*aString) && 
01492           ((processLen+1) < aLength) &&
01493           IS_LOW_SURROGATE(*(aString+1)) )
01494       {
01495          const nsFont *font = &mGS->mFontMetrics->Font();
01496          fallbackDone = SurrogateGetBoundingMetrics(aString, segBoundingMetrics, fontNum, 
01497                                                     font->size, 
01498                                                     (font->weight > NS_FONT_WEIGHT_NORMAL), 
01499                                                     ((NS_FONT_STYLE_ITALIC ==  font->style) || 
01500                                                      (NS_FONT_STYLE_OBLIQUE ==  font->style)),
01501                                                      mGS->mColor );
01502          if (fallbackDone)
01503          {      
01504            if (firstTime) {
01505              firstTime = PR_FALSE;
01506              oBoundingMetrics = segBoundingMetrics;
01507            }
01508            else
01509              oBoundingMetrics += segBoundingMetrics;
01510            aString += 2;
01511            processLen += 2;
01512            continue;
01513          }
01514       }
01515 #ifndef DISABLE_TEC_FALLBACK
01516       if (! IS_SKIP_TEC_FALLBACK(*aString))
01517         fallbackDone = TECFallbackGetBoundingMetrics(aString, segBoundingMetrics, fontNum, fontMapping);
01518 #endif
01519 
01520 #ifndef DISABLE_ATSUI_FALLBACK  
01521       // Fallback by using ATSUI
01522       if (!fallbackDone)  
01523       {
01524         const nsFont *font = &mGS->mFontMetrics->Font();
01525         fallbackDone = ATSUIFallbackGetBoundingMetrics(aString, segBoundingMetrics, fontNum, 
01526                                                   font->size, 
01527                                                   (font->weight > NS_FONT_WEIGHT_NORMAL), 
01528                                                   ((NS_FONT_STYLE_ITALIC ==  font->style) || 
01529                                                    (NS_FONT_STYLE_OBLIQUE ==  font->style)),
01530                                                   mGS->mColor );
01531       }
01532 
01533 #endif
01534       if(! fallbackDone) {
01535          if(IS_ZERO_WIDTH_CHAR(*aString))
01536          {
01537            fallbackDone = PR_TRUE;
01538          }
01539       }
01540 
01541       if (firstTime) {
01542         firstTime = PR_FALSE;
01543         oBoundingMetrics = segBoundingMetrics;
01544       }
01545       else
01546         oBoundingMetrics += segBoundingMetrics;
01547       // for fallback measure/drawing, we always do one char a time.
01548       aString++;
01549       processLen++;
01550     }
01551   } while (processLen < aLength);
01552   
01553   // release buffer if it is from heap
01554   if (heapBuf)
01555     nsMemory::Free(heapBuf);
01556   
01557   return NS_OK;
01558 }
01559 #endif // MOZ_MATHML
01560 //------------------------------------------------------------------------
01561 
01562 
01563 nsresult nsUnicodeRenderingToolkit :: DrawTextSegment(
01564                      const PRUnichar *aString, PRUint32 aLength, 
01565                      short fontNum, nsUnicodeFontMappingMac& fontMapping, 
01566                      PRInt32 x, PRInt32 y, PRUint32& oWidth)
01567 {
01568        if(aLength == 0 || fontNum == IGNORABLE_FONT_NUM) {
01569               oWidth = 0;
01570               return NS_OK;
01571        }      
01572        NS_PRECONDITION(BAD_FONT_NUM != fontNum, "illegal font num");
01573     short textWidth = 0;
01574     PRUint32 processLen = 0;
01575     char *heapBuf = nsnull;
01576     PRUint32 heapBufSize = 0;
01577     short thisWidth = 0;
01578     char stackBuf[STACK_TRESHOLD];
01579     char *buf ;
01580     ByteCount processBytes;
01581     ByteCount outLen;
01582        const short *scriptFallbackFonts = fontMapping.GetScriptFallbackFonts();
01583 
01584     ::TextFont(fontNum);
01585        
01586        // find buf from stack or heap. We only need to do this once in this function.
01587        // put this out of the loop for performance...
01588        ByteCount bufLen = aLength * 2 + 10;
01589        if( bufLen > STACK_TRESHOLD)
01590        {
01591               if(bufLen > heapBufSize )
01592               {
01593                      if(heapBuf)
01594                             delete[] heapBuf;
01595                      heapBuf = new char [bufLen];
01596                      heapBufSize = bufLen;
01597                      if(nsnull == heapBuf) {
01598                             return NS_ERROR_OUT_OF_MEMORY;
01599                      }                           
01600               } 
01601               buf = heapBuf;
01602         } else {
01603               bufLen = STACK_TRESHOLD;
01604               buf = stackBuf;
01605        }
01606 
01607     do {
01608       outLen = 0;
01609       processBytes = 0;
01610         
01611       if(fontMapping.ConvertUnicodeToGlyphs(fontNum, aString, aLength - processLen,
01612                 buf, bufLen, outLen, processBytes, 0))
01613       {
01614         DrawScriptText(buf, outLen, x, y, thisWidth);
01615         
01616         textWidth += thisWidth;
01617         x += thisWidth;                   
01618         
01619         NS_PRECONDITION(0 == (processBytes % 2), "strange conversion result");
01620         
01621         PRInt32 processUnicode = processBytes / 2;
01622         processLen += processUnicode;
01623         aString += processUnicode;
01624       }
01625                
01626          // Cannot precess by TEC, process one char a time by fallback mechanism
01627          if( processLen < aLength)
01628          {
01629                 PRBool fallbackDone = PR_FALSE;
01630 
01631       if (IS_HIGH_SURROGATE(*aString) && 
01632           ((processLen+1) < aLength) &&
01633           IS_LOW_SURROGATE(*(aString+1)) )
01634       {
01635          const nsFont *font = &mGS->mFontMetrics->Font();
01636          fallbackDone = SurrogateDrawChar(aString, x, y, thisWidth, fontNum, 
01637                                           font->size, 
01638                                           (font->weight > NS_FONT_WEIGHT_NORMAL), 
01639                                           ((NS_FONT_STYLE_ITALIC ==  font->style) || (NS_FONT_STYLE_OBLIQUE ==  font->style)),
01640                                           mGS->mColor ); 
01641          if (fallbackDone)
01642          {      
01643            textWidth += thisWidth;
01644            x += thisWidth;         
01645            aString += 2;
01646            processLen += 2;
01647            continue;
01648          }
01649       }
01650 #ifndef DISABLE_TEC_FALLBACK
01651                 // Fallback by try different Script code
01652                 if (! IS_SKIP_TEC_FALLBACK(*aString))
01653                 fallbackDone = TECFallbackDrawChar(aString, x, y, thisWidth, fontNum, fontMapping);
01654 #endif
01655                 //
01656                 // We really don't care too much of performance after this
01657                 // This will only be called when we cannot display this character in ANY mac script avaliable
01658                 // 
01659 
01660 #ifndef DISABLE_ATSUI_FALLBACK  
01661                 // Fallback by using ATSUI
01662                 if(! fallbackDone)  {
01663                      const nsFont *font = &mGS->mFontMetrics->Font();
01664                      fallbackDone = ATSUIFallbackDrawChar(aString, x, y, thisWidth, fontNum, 
01665                                                                              font->size, 
01666                                                                              (font->weight > NS_FONT_WEIGHT_NORMAL), 
01667                                                                              ((NS_FONT_STYLE_ITALIC ==  font->style) || (NS_FONT_STYLE_OBLIQUE ==  font->style)),
01668                                                                              mGS->mColor );
01669                 }
01670 #endif
01671                 if(! fallbackDone) {
01672                    if(IS_ZERO_WIDTH_CHAR(*aString))
01673                    {
01674                       thisWidth = 0;
01675                       fallbackDone = PR_TRUE;
01676                    }
01677                 }
01678       
01679 #ifndef DISABLE_LATIN_FALLBACK
01680                 if(! fallbackDone)
01681                      fallbackDone = LatinFallbackDrawChar(aString, x, y, thisWidth);
01682 #endif
01683 #ifndef DISABLE_PRECOMPOSEHANGUL_FALLBACK
01684                 if(! fallbackDone)
01685                      fallbackDone = PrecomposeHangulFallbackDrawChar(aString, x, y, thisWidth,scriptFallbackFonts[smKorean], fontNum);
01686 #endif
01687 #ifndef DISABLE_TRANSLITERATE_FALLBACK  
01688                 // Fallback to Transliteration
01689                 if(! fallbackDone) {
01690                      fallbackDone = TransliterateFallbackDrawChar(aString, x, y, thisWidth);
01691                 }
01692 #endif
01693 #ifndef DISABLE_UPLUS_FALLBACK  
01694                 // Fallback to U+xxxx
01695                 if(! fallbackDone)
01696                      fallbackDone = UPlusFallbackDrawChar(aString, x, y, thisWidth);
01697 #endif
01698                      
01699                 // Fallback to question mark
01700                 if(! fallbackDone)
01701                      QuestionMarkFallbackDrawChar(aString, x, y, thisWidth);
01702                      
01703                 textWidth += thisWidth;
01704                 x += thisWidth;
01705                 
01706                 // for fallback measure/drawing, we always do one char a time.
01707                 aString++;
01708                 processLen++;
01709          }
01710     } while (processLen < aLength);
01711     
01712     // release buffer if it is from heap
01713     if(heapBuf)
01714        delete[] heapBuf;
01715        
01716     oWidth = textWidth;
01717     return NS_OK;
01718 }
01719 //------------------------------------------------------------------------
01720 
01721 nsresult 
01722 nsUnicodeRenderingToolkit::GetWidth(const PRUnichar *aString, PRUint32 aLength, 
01723                                     nscoord &aWidth, PRInt32 *aFontID)
01724 {
01725   nsTextDimensions dim;
01726 
01727   nsresult res = GetTextDimensions(aString, aLength, dim, aFontID);
01728   aWidth = dim.width;
01729   return res;
01730 }
01731 
01732 nsresult 
01733 nsUnicodeRenderingToolkit::GetTextDimensions(const PRUnichar *aString, PRUint32 aLength, 
01734                                               nsTextDimensions &aDim, PRInt32 *aFontID)
01735 {
01736   nsresult res = NS_OK;
01737   nsFontMetricsMac *metrics = (nsFontMetricsMac*) mGS->mFontMetrics;
01738   nsUnicodeFontMappingMac* fontmap = metrics->GetUnicodeFontMapping();
01739 
01740   PRUint32 i;
01741   short fontNum[2];
01742   fontNum[0] = fontNum[1] = BAD_FONT_NUM;
01743   PRUint32 start;
01744     
01745   nsTextDimensions textDim;
01746   nsTextDimensions thisDim;
01747   
01748   for(i =0, start = 0; i < aLength; i++)
01749   {
01750     fontNum[ i % 2] = fontmap->GetFontID(aString[i]);
01751     if ((fontNum[0] != fontNum[1]) && (0 != i))
01752     {  // start new font run...
01753       thisDim.Clear();
01754       res =  GetTextSegmentDimensions(aString+start, i - start, fontNum[(i + 1) % 2], *fontmap, thisDim);
01755       if (NS_FAILED (res)) 
01756         return res;    
01757       textDim.Combine(thisDim);
01758       start = i;
01759     }
01760   }
01761   res = GetTextSegmentDimensions(aString+start, aLength - start, fontNum[(i + 1) % 2], *fontmap, thisDim);
01762   if (NS_FAILED (res)) 
01763     return res;    
01764   textDim.Combine(thisDim);
01765 
01766   aDim.width = NSToCoordRound(float(textDim.width) * mP2T);
01767   aDim.ascent = NSToCoordRound(float(textDim.ascent) * mP2T);
01768   aDim.descent = NSToCoordRound(float(textDim.descent) * mP2T);
01769   return res;  
01770 }
01771 //------------------------------------------------------------------------
01772 
01773 #ifdef MOZ_MATHML
01774 nsresult
01775 nsUnicodeRenderingToolkit::GetTextBoundingMetrics(const PRUnichar *aString, PRUint32 aLength,
01776                                                   nsBoundingMetrics &aBoundingMetrics, PRInt32 *aFontID)
01777 {
01778   nsresult res = NS_OK;
01779   nsFontMetricsMac *metrics = (nsFontMetricsMac*) mGS->mFontMetrics;
01780   nsUnicodeFontMappingMac* fontmap = metrics->GetUnicodeFontMapping();
01781 
01782   PRUint32 i;
01783   short fontNum[2];
01784   fontNum[0] = fontNum[1] = BAD_FONT_NUM;
01785   PRUint32 start;
01786   PRBool firstTime = PR_TRUE;
01787   nsBoundingMetrics thisBoundingMetrics;
01788 
01789   for(i =0, start = 0; i < aLength; i++)
01790   {
01791     fontNum[ i % 2] = fontmap->GetFontID(aString[i]);
01792     if ((fontNum[0] != fontNum[1]) && (0 != i))
01793     {  // start new font run...
01794       res = GetTextSegmentBoundingMetrics(aString+start, i - start, fontNum[(i + 1) % 2], *fontmap, thisBoundingMetrics);
01795       if (NS_FAILED (res))
01796         return res;
01797       if (firstTime) {
01798         firstTime = PR_FALSE;
01799         aBoundingMetrics = thisBoundingMetrics;
01800       }
01801       else
01802         aBoundingMetrics += thisBoundingMetrics;
01803       start = i;
01804     }
01805   }
01806   res = GetTextSegmentBoundingMetrics(aString+start, aLength - start, fontNum[(i + 1) % 2], *fontmap, thisBoundingMetrics);
01807   if (NS_FAILED (res))
01808     return res;
01809   if (firstTime)
01810     aBoundingMetrics = thisBoundingMetrics;
01811   else
01812     aBoundingMetrics += thisBoundingMetrics;
01813 
01814   aBoundingMetrics.leftBearing = NSToCoordRound(float(aBoundingMetrics.leftBearing) * mP2T);
01815   aBoundingMetrics.rightBearing = NSToCoordRound(float(aBoundingMetrics.rightBearing) * mP2T);
01816   aBoundingMetrics.ascent = NSToCoordRound(float(aBoundingMetrics.ascent) * mP2T);
01817   aBoundingMetrics.descent = NSToCoordRound(float(aBoundingMetrics.descent) * mP2T);
01818   aBoundingMetrics.width = NSToCoordRound(float(aBoundingMetrics.width) * mP2T);
01819 
01820   return res;
01821 }
01822 #endif // MOZ_MATHML
01823 
01824 //------------------------------------------------------------------------
01825 
01826 nsresult
01827 nsUnicodeRenderingToolkit::DrawString(const PRUnichar *aString, PRUint32 aLength,
01828                                          nscoord aX, nscoord aY, PRInt32 aFontID,
01829                                          const nscoord* aSpacing)
01830 {
01831   nsresult res = NS_OK;
01832   nsFontMetricsMac *metrics = (nsFontMetricsMac*) mGS->mFontMetrics;
01833   nsUnicodeFontMappingMac* fontmap = metrics->GetUnicodeFontMapping();
01834 
01835   PRInt32 x = aX;
01836   PRInt32 transformedY = aY;
01837   mGS->mTMatrix.TransformCoord(&x, &transformedY);
01838 
01839   PRUint32 i;
01840   PRInt32 currentX = aX;
01841   PRUint32 thisWidth = 0;
01842        
01843   if (aSpacing)
01844   {
01845     // fix me ftang -  handle (mRightToLeftText) here
01846     for (i = 0; i < aLength; )
01847     {
01848       PRUint32 drawLen;
01849       short curFontNum = fontmap->GetFontID(aString[i]);
01850 
01851       for (drawLen = 1; (i + drawLen) < aLength; drawLen++)
01852       {
01853         PRUnichar uc = aString[i+drawLen];
01854        if(! (IS_CONTEXTUAL_CHARS(uc) || 
01855                   IS_FORMAT_CONTROL_CHARS(uc) ||
01856              IS_COMBINING_CHARS(uc)) ) {
01857          break;
01858        }
01859       }
01860 
01861       PRInt32 transformedX = currentX, ignoreY = 0;
01862       mGS->mTMatrix.TransformCoord(&transformedX, &ignoreY);
01863       res = DrawTextSegment(aString+i, drawLen, curFontNum, *fontmap, transformedX, transformedY, thisWidth);
01864            if (NS_FAILED(res))
01865                        return res;
01866       
01867       for (PRUint32 j = 0; j < drawLen; j++)
01868                 currentX += aSpacing[i + j];
01869                 
01870               i += drawLen;
01871     }
01872   }
01873   else    // no spacing array
01874   {
01875     short thisFont, nextFont;
01876     
01877     PRUint32 start;
01878 
01879       // normal left to right
01880         thisFont = fontmap->GetFontID(aString[0]);
01881            for (i = 1, start = 0; i < aLength; i++)
01882            {
01883               PRUnichar uch = aString[i];
01884               if(! IS_FORMAT_CONTROL_CHARS(uch))
01885               {
01886                      nextFont = fontmap->GetFontID(uch);
01887                      if (thisFont != nextFont) 
01888                {
01889                  // start new font run...
01890                  PRInt32 transformedX = currentX, ignoreY = 0;
01891                  mGS->mTMatrix.TransformCoord(&transformedX, &ignoreY);
01892                  
01893             res = DrawTextSegment(aString + start, i - start, thisFont, *fontmap, transformedX, transformedY, thisWidth);
01894                      if (NS_FAILED(res))
01895                               return res;
01896                             
01897                        currentX += NSToCoordRound(float(thisWidth) * mP2T);
01898                        start = i;
01899                        thisFont = nextFont;
01900                      }
01901               }
01902            }
01903 
01904            PRInt32 transformedX = currentX, ignoreY = 0;
01905            mGS->mTMatrix.TransformCoord(&transformedX, &ignoreY);
01906       res = DrawTextSegment(aString+start, aLength-start, thisFont, *fontmap, transformedX, transformedY, thisWidth);
01907     if (NS_FAILED(res))
01908       return res;
01909   }
01910   
01911        return NS_OK;
01912 }
01913 
01914 
01915 //------------------------------------------------------------------------
01916 nsresult
01917 nsUnicodeRenderingToolkit::PrepareToDraw(float aP2T, nsIDeviceContext* aContext,
01918                                          nsGraphicState* aGS, 
01919                                          CGrafPtr aPort, PRBool aRightToLeftText )
01920 {
01921        mP2T = aP2T;
01922        mContext = aContext;
01923        mGS = aGS;
01924        mPort = aPort;
01925        mRightToLeftText = aRightToLeftText;
01926        return NS_OK;
01927 }