Back to index

lightning-sunbird  0.9+nobinonly
nsBulletFrame.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 Communicator client 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 #include "nsCOMPtr.h"
00038 #include "nsBulletFrame.h"
00039 #include "nsHTMLAtoms.h"
00040 #include "nsHTMLParts.h"
00041 #include "nsHTMLContainerFrame.h"
00042 #include "nsIFontMetrics.h"
00043 #include "nsGenericHTMLElement.h"
00044 #include "nsPresContext.h"
00045 #include "nsIPresShell.h"
00046 #include "nsIDocument.h"
00047 #include "nsReflowPath.h"
00048 #include "nsIRenderingContext.h"
00049 #include "nsILoadGroup.h"
00050 #include "nsIURL.h"
00051 #include "nsNetUtil.h"
00052 #include "nsLayoutAtoms.h"
00053 #include "prprf.h"
00054 #ifdef IBMBIDI
00055 #include "nsBidiPresUtils.h"
00056 #endif // IBMBIDI
00057 
00058 #include "imgILoader.h"
00059 #include "imgIContainer.h"
00060 #include "imgIDecoderObserver.h"
00061 
00062 #include "nsIServiceManager.h"
00063 #include "nsIComponentManager.h"
00064 #include "nsContentUtils.h"
00065 
00066 class nsBulletListener : public imgIDecoderObserver
00067 {
00068 public:
00069   nsBulletListener();
00070   virtual ~nsBulletListener();
00071 
00072   NS_DECL_ISUPPORTS
00073   NS_DECL_IMGIDECODEROBSERVER
00074   NS_DECL_IMGICONTAINEROBSERVER
00075 
00076   void SetFrame(nsBulletFrame *frame) { mFrame = frame; }
00077 
00078 private:
00079   nsBulletFrame *mFrame;
00080 };
00081 
00082 
00083 
00084 
00085 
00086 
00087 nsBulletFrame::nsBulletFrame()
00088 {
00089 }
00090 
00091 nsBulletFrame::~nsBulletFrame()
00092 {
00093 }
00094 
00095 NS_IMETHODIMP
00096 nsBulletFrame::Destroy(nsPresContext* aPresContext)
00097 {
00098   // Stop image loading first
00099   if (mImageRequest) {
00100     mImageRequest->Cancel(NS_ERROR_FAILURE);
00101     mImageRequest = nsnull;
00102   }
00103 
00104   if (mListener)
00105     NS_REINTERPRET_CAST(nsBulletListener*, mListener.get())->SetFrame(nsnull);
00106 
00107   // Let base class do the rest
00108   return nsFrame::Destroy(aPresContext);
00109 }
00110 
00111 #ifdef NS_DEBUG
00112 NS_IMETHODIMP
00113 nsBulletFrame::GetFrameName(nsAString& aResult) const
00114 {
00115   return MakeFrameName(NS_LITERAL_STRING("Bullet"), aResult);
00116 }
00117 #endif
00118 
00119 nsIAtom*
00120 nsBulletFrame::GetType() const
00121 {
00122   return nsLayoutAtoms::bulletFrame;
00123 }
00124 
00125 NS_IMETHODIMP
00126 nsBulletFrame::DidSetStyleContext(nsPresContext* aPresContext)
00127 {
00128   imgIRequest *newRequest = GetStyleList()->mListStyleImage;
00129 
00130   if (newRequest) {
00131 
00132     if (!mListener) {
00133       nsBulletListener *listener;
00134       NS_NEWXPCOM(listener, nsBulletListener);
00135       NS_ADDREF(listener);
00136       listener->SetFrame(this);
00137       listener->QueryInterface(NS_GET_IID(imgIDecoderObserver), getter_AddRefs(mListener));
00138       NS_ASSERTION(mListener, "queryinterface for the listener failed");
00139       NS_RELEASE(listener);
00140     }
00141 
00142     PRBool needNewRequest = PR_TRUE;
00143 
00144     if (mImageRequest) {
00145       // Reload the image, maybe...
00146       nsCOMPtr<nsIURI> oldURI;
00147       mImageRequest->GetURI(getter_AddRefs(oldURI));
00148       nsCOMPtr<nsIURI> newURI;
00149       newRequest->GetURI(getter_AddRefs(newURI));
00150       if (oldURI && newURI) {
00151         PRBool same;
00152         newURI->Equals(oldURI, &same);
00153         if (same) {
00154           needNewRequest = PR_FALSE;
00155         } else {
00156           mImageRequest->Cancel(NS_ERROR_FAILURE);
00157           mImageRequest = nsnull;
00158         }
00159       }
00160     }
00161 
00162     if (needNewRequest) {
00163       newRequest->Clone(mListener, getter_AddRefs(mImageRequest));
00164     }
00165   } else {
00166     // No image request on the new style context
00167     if (mImageRequest) {
00168       mImageRequest->Cancel(NS_ERROR_FAILURE);
00169       mImageRequest = nsnull;
00170     }
00171   }
00172 
00173   return NS_OK;
00174 }
00175 
00176 NS_IMETHODIMP
00177 nsBulletFrame::Paint(nsPresContext*      aPresContext,
00178                      nsIRenderingContext& aRenderingContext,
00179                      const nsRect&        aDirtyRect,
00180                      nsFramePaintLayer    aWhichLayer,
00181                      PRUint32             aFlags)
00182 {
00183   if (NS_FRAME_PAINT_LAYER_FOREGROUND != aWhichLayer) {
00184     return NS_OK;
00185   }
00186 
00187   PRBool isVisible;
00188   if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_TRUE, &isVisible)) && isVisible) {
00189     const nsStyleList* myList = GetStyleList();
00190     PRUint8 listStyleType = myList->mListStyleType;
00191 
00192     if (myList->mListStyleImage && mImageRequest) {
00193       PRUint32 status;
00194       mImageRequest->GetImageStatus(&status);
00195       if (status & imgIRequest::STATUS_LOAD_COMPLETE &&
00196           !(status & imgIRequest::STATUS_ERROR)) {
00197         nsCOMPtr<imgIContainer> imageCon;
00198         mImageRequest->GetImage(getter_AddRefs(imageCon));
00199         if (imageCon) {
00200           nsRect innerArea(0, 0,
00201                            mRect.width - (mPadding.left + mPadding.right),
00202                            mRect.height - (mPadding.top + mPadding.bottom));
00203           nsRect dest(mPadding.left, mPadding.top, innerArea.width, innerArea.height);
00204           aRenderingContext.DrawImage(imageCon, innerArea, dest);
00205           return NS_OK;
00206         }
00207       }
00208     }
00209 
00210     const nsStyleFont* myFont = GetStyleFont();
00211     const nsStyleColor* myColor = GetStyleColor();
00212 
00213     nsCOMPtr<nsIFontMetrics> fm;
00214     aRenderingContext.SetColor(myColor->mColor);
00215 
00216 #ifdef IBMBIDI
00217     nsCharType charType = eCharType_LeftToRight;
00218     PRUint8 level = 0;
00219     PRBool isBidiSystem = PR_FALSE;
00220     const nsStyleVisibility* vis = GetStyleVisibility();
00221     PRUint32 hints = 0;
00222 #endif // IBMBIDI
00223 
00224     nsAutoString text;
00225     switch (listStyleType) {
00226     case NS_STYLE_LIST_STYLE_NONE:
00227       break;
00228 
00229     default:
00230     case NS_STYLE_LIST_STYLE_DISC:
00231       aRenderingContext.FillEllipse(mPadding.left, mPadding.top,
00232                                     mRect.width - (mPadding.left + mPadding.right),
00233                                     mRect.height - (mPadding.top + mPadding.bottom));
00234       break;
00235 
00236     case NS_STYLE_LIST_STYLE_CIRCLE:
00237       aRenderingContext.DrawEllipse(mPadding.left, mPadding.top,
00238                                     mRect.width - (mPadding.left + mPadding.right),
00239                                     mRect.height - (mPadding.top + mPadding.bottom));
00240       break;
00241 
00242     case NS_STYLE_LIST_STYLE_SQUARE:
00243       aRenderingContext.FillRect(mPadding.left, mPadding.top,
00244                                  mRect.width - (mPadding.left + mPadding.right),
00245                                  mRect.height - (mPadding.top + mPadding.bottom));
00246       break;
00247 
00248     case NS_STYLE_LIST_STYLE_DECIMAL:
00249     case NS_STYLE_LIST_STYLE_OLD_DECIMAL:
00250     case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO:
00251 #ifdef IBMBIDI
00252       GetListItemText(*myList, text);
00253       charType = eCharType_EuropeanNumber;
00254       break;
00255 
00256     case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC:
00257       if (GetListItemText(*myList, text))
00258         charType = eCharType_ArabicNumber;
00259       else
00260         charType = eCharType_EuropeanNumber;
00261       break;
00262 
00263     case NS_STYLE_LIST_STYLE_HEBREW:
00264       aRenderingContext.GetHints(hints);
00265       isBidiSystem = (hints & NS_RENDERING_HINT_BIDI_REORDERING);
00266       if (!isBidiSystem) {
00267         if (GetListItemText(*myList, text)) {
00268           charType = eCharType_RightToLeft;
00269           level = 1;
00270         } else {
00271           charType = eCharType_EuropeanNumber;
00272         }
00273 
00274         if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
00275           text.Cut(0, 1);
00276           text.AppendLiteral(".");
00277         }
00278         break;
00279       }
00280       // else fall through
00281 #endif // IBMBIDI
00282 
00283     case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
00284     case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
00285     case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
00286     case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
00287     case NS_STYLE_LIST_STYLE_OLD_LOWER_ROMAN:
00288     case NS_STYLE_LIST_STYLE_OLD_UPPER_ROMAN:
00289     case NS_STYLE_LIST_STYLE_OLD_LOWER_ALPHA:
00290     case NS_STYLE_LIST_STYLE_OLD_UPPER_ALPHA:
00291     case NS_STYLE_LIST_STYLE_LOWER_GREEK:
00292 #ifndef IBMBIDI
00293     case NS_STYLE_LIST_STYLE_HEBREW:
00294 #endif
00295     case NS_STYLE_LIST_STYLE_ARMENIAN:
00296     case NS_STYLE_LIST_STYLE_GEORGIAN:
00297     case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC:
00298     case NS_STYLE_LIST_STYLE_HIRAGANA:
00299     case NS_STYLE_LIST_STYLE_KATAKANA:
00300     case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA:
00301     case NS_STYLE_LIST_STYLE_KATAKANA_IROHA:
00302     case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL: 
00303     case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL: 
00304     case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL: 
00305     case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL: 
00306     case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL: 
00307     case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL: 
00308     case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM:
00309     case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH:
00310 #ifndef IBMBIDI
00311     case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC:
00312 #endif
00313     case NS_STYLE_LIST_STYLE_MOZ_PERSIAN:
00314     case NS_STYLE_LIST_STYLE_MOZ_URDU:
00315     case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI:
00316     case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI:
00317     case NS_STYLE_LIST_STYLE_MOZ_GUJARATI:
00318     case NS_STYLE_LIST_STYLE_MOZ_ORIYA:
00319     case NS_STYLE_LIST_STYLE_MOZ_KANNADA:
00320     case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM:
00321     case NS_STYLE_LIST_STYLE_MOZ_BENGALI:
00322     case NS_STYLE_LIST_STYLE_MOZ_TAMIL:
00323     case NS_STYLE_LIST_STYLE_MOZ_TELUGU:
00324     case NS_STYLE_LIST_STYLE_MOZ_THAI:
00325     case NS_STYLE_LIST_STYLE_MOZ_LAO:
00326     case NS_STYLE_LIST_STYLE_MOZ_MYANMAR:
00327     case NS_STYLE_LIST_STYLE_MOZ_KHMER:
00328     case NS_STYLE_LIST_STYLE_MOZ_HANGUL:
00329     case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT:
00330     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME:
00331     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC:
00332     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM:
00333     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER:
00334     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET:
00335       fm = aPresContext->GetMetricsFor(myFont->mFont);
00336 #ifdef IBMBIDI
00337       // If we can't render our numeral using the chars in the numbering
00338       // system, we'll be using "decimal"...
00339       PRBool usedChars =
00340 #endif // IBMBIDI
00341       GetListItemText(*myList, text);
00342 #ifdef IBMBIDI
00343       if (!usedChars)
00344         charType = eCharType_EuropeanNumber;
00345 #endif
00346       aRenderingContext.SetFont(fm);
00347       nscoord ascent;
00348       fm->GetMaxAscent(ascent);
00349       aRenderingContext.DrawString(text, mPadding.left, mPadding.top + ascent);
00350       break;
00351     }
00352 #ifdef IBMBIDI
00353     if (charType != eCharType_LeftToRight) {
00354       fm = aPresContext->GetMetricsFor(myFont->mFont);
00355       aRenderingContext.SetFont(fm);
00356       nscoord ascent;
00357       fm->GetMaxAscent(ascent);
00358 
00359       nsBidiPresUtils* bidiUtils = aPresContext->GetBidiUtils();
00360       if (bidiUtils) {
00361         const PRUnichar* buffer = text.get();
00362         PRInt32 textLength = text.Length();
00363         if (eCharType_RightToLeft == charType) {
00364           bidiUtils->FormatUnicodeText(aPresContext, (PRUnichar*)buffer, textLength,
00365                                        charType, level, PR_FALSE);
00366         }
00367         else {
00368 //Mohamed
00369           aRenderingContext.GetHints(hints);
00370           isBidiSystem = (hints & NS_RENDERING_HINT_ARABIC_SHAPING);
00371           bidiUtils->FormatUnicodeText(aPresContext, (PRUnichar*)buffer, textLength,
00372                                        charType, level, isBidiSystem);//Mohamed
00373         }
00374       }
00375       aRenderingContext.DrawString(text, mPadding.left, mPadding.top + ascent);
00376     }   
00377 #endif // IBMBIDI
00378   }
00379   DO_GLOBAL_REFLOW_COUNT_DSP("nsBulletFrame", &aRenderingContext);
00380   return NS_OK;
00381 }
00382 
00383 PRInt32
00384 nsBulletFrame::SetListItemOrdinal(PRInt32 aNextOrdinal,
00385                                   PRBool* aChanged)
00386 {
00387   // Assume that the ordinal comes from the caller
00388   PRInt32 oldOrdinal = mOrdinal;
00389   mOrdinal = aNextOrdinal;
00390 
00391   // Try to get value directly from the list-item, if it specifies a
00392   // value attribute. Note: we do this with our parent's content
00393   // because our parent is the list-item.
00394   nsIContent* parentContent = mParent->GetContent();
00395   if (parentContent) {
00396     nsGenericHTMLElement *hc =
00397       nsGenericHTMLElement::FromContent(parentContent);
00398     if (hc) {
00399       const nsAttrValue* attr = hc->GetParsedAttr(nsHTMLAtoms::value);
00400       if (attr && attr->Type() == nsAttrValue::eInteger) {
00401         // Use ordinal specified by the value attribute
00402         mOrdinal = attr->GetIntegerValue();
00403       }
00404     }
00405   }
00406 
00407   *aChanged = oldOrdinal != mOrdinal;
00408 
00409   return mOrdinal + 1;
00410 }
00411 
00412 
00413 // XXX change roman/alpha to use unsigned math so that maxint and
00414 // maxnegint will work
00415 
00421 static PRBool DecimalToText(PRInt32 ordinal, nsString& result)
00422 {
00423    char cbuf[40];
00424    PR_snprintf(cbuf, sizeof(cbuf), "%ld", ordinal);
00425    result.AppendASCII(cbuf);
00426    return PR_TRUE;
00427 }
00428 static PRBool DecimalLeadingZeroToText(PRInt32 ordinal, nsString& result)
00429 {
00430    char cbuf[40];
00431    PR_snprintf(cbuf, sizeof(cbuf), "%02ld", ordinal);
00432    result.AppendASCII(cbuf);
00433    return PR_TRUE;
00434 }
00435 static PRBool OtherDecimalToText(PRInt32 ordinal, PRUnichar zeroChar, nsString& result)
00436 {
00437    PRUnichar diff = zeroChar - PRUnichar('0');
00438    DecimalToText(ordinal, result);
00439    PRUnichar* p = result.BeginWriting();
00440    if (ordinal < 0) {
00441      // skip the leading '-'
00442      ++p;
00443    }     
00444    for(; nsnull != *p ; p++) 
00445       *p += diff;
00446    return PR_TRUE;
00447 }
00448 static PRBool TamilToText(PRInt32 ordinal,  nsString& result)
00449 {
00450    PRUnichar diff = 0x0BE6 - PRUnichar('0');
00451    DecimalToText(ordinal, result); 
00452    if (ordinal < 1 || ordinal > 9999) {
00453      // Can't do those in this system.
00454      return PR_FALSE;
00455    }
00456    PRUnichar* p = result.BeginWriting();
00457    for(; nsnull != *p ; p++) 
00458       if(*p != PRUnichar('0'))
00459          *p += diff;
00460    return PR_TRUE;
00461 }
00462 
00463 
00464 static const char gLowerRomanCharsA[] = "ixcm";
00465 static const char gUpperRomanCharsA[] = "IXCM";
00466 static const char gLowerRomanCharsB[] = "vld";
00467 static const char gUpperRomanCharsB[] = "VLD";
00468 
00469 static PRBool RomanToText(PRInt32 ordinal, nsString& result, const char* achars, const char* bchars)
00470 {
00471   if (ordinal < 1 || ordinal > 3999) {
00472     DecimalToText(ordinal, result);
00473     return PR_FALSE;
00474   }
00475   nsAutoString addOn, decStr;
00476   decStr.AppendInt(ordinal, 10);
00477   PRIntn len = decStr.Length();
00478   const PRUnichar* dp = decStr.get();
00479   const PRUnichar* end = dp + len;
00480   PRIntn romanPos = len;
00481   PRIntn n;
00482 
00483   for (; dp < end; dp++) {
00484     romanPos--;
00485     addOn.SetLength(0);
00486     switch(*dp) {
00487       case '3':  addOn.Append(PRUnichar(achars[romanPos]));
00488       case '2':  addOn.Append(PRUnichar(achars[romanPos]));
00489       case '1':  addOn.Append(PRUnichar(achars[romanPos]));
00490         break;
00491       case '4':
00492         addOn.Append(PRUnichar(achars[romanPos]));
00493         // FALLTHROUGH
00494       case '5': case '6':
00495       case '7': case  '8':
00496         addOn.Append(PRUnichar(bchars[romanPos]));
00497         for(n=0;n<(*dp-'5');n++) {
00498           addOn.Append(PRUnichar(achars[romanPos]));
00499         }
00500         break;
00501       case '9':
00502         addOn.Append(PRUnichar(achars[romanPos]));
00503         addOn.Append(PRUnichar(achars[romanPos+1]));
00504         break;
00505       default:
00506         break;
00507     }
00508     result.Append(addOn);
00509   }
00510   return PR_TRUE;
00511 }
00512 
00513 #define ALPHA_SIZE 26
00514 static const PRUnichar gLowerAlphaChars[ALPHA_SIZE]  = 
00515 {
00516 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, // A   B   C   D   E
00517 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, // F   G   H   I   J
00518 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, // K   L   M   N   O
00519 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, // P   Q   R   S   T
00520 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, // U   V   W   X   Y
00521 0x007A                                  // Z
00522 };
00523 
00524 static const PRUnichar gUpperAlphaChars[ALPHA_SIZE]  = 
00525 {
00526 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, // A   B   C   D   E
00527 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, // F   G   H   I   J
00528 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, // K   L   M   N   O
00529 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, // P   Q   R   S   T
00530 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, // U   V   W   X   Y
00531 0x005A                                  // Z
00532 };
00533 
00534 
00535 #define KATAKANA_CHARS_SIZE 48
00536 // Page 94 Writing Systems of The World
00537 // after modification by momoi
00538 static const PRUnichar gKatakanaChars[KATAKANA_CHARS_SIZE] =
00539 {
00540 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, //  a    i   u    e    o
00541 0x30AB, 0x30AD, 0x30AF, 0x30B1, 0x30B3, // ka   ki  ku   ke   ko
00542 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD, // sa  shi  su   se   so
00543 0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, // ta  chi tsu   te   to
00544 0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, // na   ni  nu   ne   no
00545 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, // ha   hi  hu   he   ho
00546 0x30DE, 0x30DF, 0x30E0, 0x30E1, 0x30E2, // ma   mi  mu   me   mo
00547 0x30E4,         0x30E6,         0x30E8, // ya       yu        yo 
00548 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, // ra   ri  ru   re   ro
00549 0x30EF, 0x30F0,         0x30F1, 0x30F2, // wa (w)i     (w)e (w)o
00550 0x30F3                                  //  n
00551 };
00552 
00553 #define HIRAGANA_CHARS_SIZE 48 
00554 static const PRUnichar gHiraganaChars[HIRAGANA_CHARS_SIZE] =
00555 {
00556 0x3042, 0x3044, 0x3046, 0x3048, 0x304A, //  a    i    u    e    o
00557 0x304B, 0x304D, 0x304F, 0x3051, 0x3053, // ka   ki   ku   ke   ko
00558 0x3055, 0x3057, 0x3059, 0x305B, 0x305D, // sa  shi   su   se   so
00559 0x305F, 0x3061, 0x3064, 0x3066, 0x3068, // ta  chi  tsu   te   to
00560 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, // na   ni   nu   ne   no
00561 0x306F, 0x3072, 0x3075, 0x3078, 0x307B, // ha   hi   hu   he   ho
00562 0x307E, 0x307F, 0x3080, 0x3081, 0x3082, // ma   mi   mu   me   mo
00563 0x3084,         0x3086,         0x3088, // ya        yu       yo 
00564 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, // ra   ri   ru   re   ro
00565 0x308F, 0x3090,         0x3091, 0x3092, // wa (w)i      (w)e (w)o
00566 0x3093                                  // n
00567 };
00568 
00569 
00570 #define HIRAGANA_IROHA_CHARS_SIZE 47
00571 // Page 94 Writing Systems of The World
00572 static const PRUnichar gHiraganaIrohaChars[HIRAGANA_IROHA_CHARS_SIZE] =
00573 {
00574 0x3044, 0x308D, 0x306F, 0x306B, 0x307B, //  i   ro   ha   ni   ho
00575 0x3078, 0x3068, 0x3061, 0x308A, 0x306C, // he   to  chi   ri   nu
00576 0x308B, 0x3092, 0x308F, 0x304B, 0x3088, // ru (w)o   wa   ka   yo
00577 0x305F, 0x308C, 0x305D, 0x3064, 0x306D, // ta   re   so  tsu   ne
00578 0x306A, 0x3089, 0x3080, 0x3046, 0x3090, // na   ra   mu    u (w)i
00579 0x306E, 0x304A, 0x304F, 0x3084, 0x307E, // no    o   ku   ya   ma
00580 0x3051, 0x3075, 0x3053, 0x3048, 0x3066, // ke   hu   ko    e   te
00581 0x3042, 0x3055, 0x304D, 0x3086, 0x3081, //  a   sa   ki   yu   me
00582 0x307F, 0x3057, 0x3091, 0x3072, 0x3082, // mi  shi (w)e   hi   mo 
00583 0x305B, 0x3059                          // se   su
00584 };
00585 
00586 #define KATAKANA_IROHA_CHARS_SIZE 47
00587 static const PRUnichar gKatakanaIrohaChars[KATAKANA_IROHA_CHARS_SIZE] =
00588 {
00589 0x30A4, 0x30ED, 0x30CF, 0x30CB, 0x30DB, //  i   ro   ha   ni   ho
00590 0x30D8, 0x30C8, 0x30C1, 0x30EA, 0x30CC, // he   to  chi   ri   nu
00591 0x30EB, 0x30F2, 0x30EF, 0x30AB, 0x30E8, // ru (w)o   wa   ka   yo
00592 0x30BF, 0x30EC, 0x30BD, 0x30C4, 0x30CD, // ta   re   so  tsu   ne
00593 0x30CA, 0x30E9, 0x30E0, 0x30A6, 0x30F0, // na   ra   mu    u (w)i
00594 0x30CE, 0x30AA, 0x30AF, 0x30E4, 0x30DE, // no    o   ku   ya   ma
00595 0x30B1, 0x30D5, 0x30B3, 0x30A8, 0x30C6, // ke   hu   ko    e   te
00596 0x30A2, 0x30B5, 0x30AD, 0x30E6, 0x30E1, //  a   sa   ki   yu   me
00597 0x30DF, 0x30B7, 0x30F1, 0x30D2, 0x30E2, // mi  shi (w)e   hi   mo 
00598 0x30BB, 0x30B9                          // se   su
00599 };
00600 
00601 #define LOWER_GREEK_CHARS_SIZE 24
00602 // Note: 0x03C2 GREEK FINAL SIGMA is not used in here....
00603 static const PRUnichar gLowerGreekChars[LOWER_GREEK_CHARS_SIZE] =
00604 {
00605 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, // alpha  beta  gamma  delta  epsilon
00606 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, // zeta   eta   theta  iota   kappa   
00607 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, // lamda  mu    nu     xi     omicron 
00608 0x03C0, 0x03C1, 0x03C3, 0x03C4, 0x03C5, // pi     rho   sigma  tau    upsilon 
00609 0x03C6, 0x03C7, 0x03C8, 0x03C9          // phi    chi   psi    omega    
00610 };
00611 
00612 #define CJK_HEAVENLY_STEM_CHARS_SIZE 10 
00613 static const PRUnichar gCJKHeavenlyStemChars[CJK_HEAVENLY_STEM_CHARS_SIZE] =
00614 {
00615 0x7532, 0x4e59, 0x4e19, 0x4e01, 0x620a,
00616 0x5df1, 0x5e9a, 0x8f9b, 0x58ec, 0x7678
00617 };
00618 #define CJK_EARTHLY_BRANCH_CHARS_SIZE 12 
00619 static const PRUnichar gCJKEarthlyBranchChars[CJK_EARTHLY_BRANCH_CHARS_SIZE] =
00620 {
00621 0x5b50, 0x4e11, 0x5bc5, 0x536f, 0x8fb0, 0x5df3,
00622 0x5348, 0x672a, 0x7533, 0x9149, 0x620c, 0x4ea5
00623 };
00624 #define HANGUL_CHARS_SIZE 14 
00625 static const PRUnichar gHangulChars[HANGUL_CHARS_SIZE] =
00626 {
00627 0xac00, 0xb098, 0xb2e4, 0xb77c, 0xb9c8, 0xbc14,
00628 0xc0ac, 0xc544, 0xc790, 0xcc28, 0xce74, 0xd0c0,
00629 0xd30c, 0xd558
00630 };
00631 #define HANGUL_CONSONANT_CHARS_SIZE 14 
00632 static const PRUnichar gHangulConsonantChars[HANGUL_CONSONANT_CHARS_SIZE] =
00633 {                                      
00634 0x3131, 0x3134, 0x3137, 0x3139, 0x3141, 0x3142,
00635 0x3145, 0x3147, 0x3148, 0x314a, 0x314b, 0x314c,
00636 0x314d, 0x314e
00637 };
00638 
00639 // Ge'ez set of Ethiopic ordered list. There are other locale-dependent sets.
00640 // For the time being, let's implement two Ge'ez sets only
00641 // per Momoi san's suggestion in bug 102252. 
00642 // For details, refer to http://www.ethiopic.org/Collation/OrderedLists.html.
00643 #define ETHIOPIC_HALEHAME_CHARS_SIZE 26
00644 static const PRUnichar gEthiopicHalehameChars[ETHIOPIC_HALEHAME_CHARS_SIZE] =
00645 {                                      
00646 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228,
00647 0x1230, 0x1240, 0x1260, 0x1270, 0x1280, 0x1290,
00648 0x12a0, 0x12a8, 0x12c8, 0x12d0, 0x12d8, 0x12e8,
00649 0x12f0, 0x1308, 0x1320, 0x1330, 0x1338, 0x1340,
00650 0x1348, 0x1350
00651 };
00652 #define ETHIOPIC_HALEHAME_AM_CHARS_SIZE 33
00653 static const PRUnichar gEthiopicHalehameAmChars[ETHIOPIC_HALEHAME_AM_CHARS_SIZE] =
00654 {                                      
00655 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228,
00656 0x1230, 0x1238, 0x1240, 0x1260, 0x1270, 0x1278,
00657 0x1280, 0x1290, 0x1298, 0x12a0, 0x12a8, 0x12b8,
00658 0x12c8, 0x12d0, 0x12d8, 0x12e0, 0x12e8, 0x12f0,
00659 0x1300, 0x1308, 0x1320, 0x1328, 0x1330, 0x1338,
00660 0x1340, 0x1348, 0x1350
00661 };
00662 #define ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE 31
00663 static const PRUnichar gEthiopicHalehameTiErChars[ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE] =
00664 {                                      
00665 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230,
00666 0x1238, 0x1240, 0x1250, 0x1260, 0x1270, 0x1278,
00667 0x1290, 0x1298, 0x12a0, 0x12a8, 0x12b8, 0x12c8,
00668 0x12d0, 0x12d8, 0x12e0, 0x12e8, 0x12f0, 0x1300,
00669 0x1308, 0x1320, 0x1328, 0x1330, 0x1338, 0x1348,
00670 0x1350
00671 };
00672 #define ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE 34
00673 static const PRUnichar gEthiopicHalehameTiEtChars[ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE] =
00674 {                                      
00675 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228,
00676 0x1230, 0x1238, 0x1240, 0x1250, 0x1260, 0x1270,
00677 0x1278, 0x1280, 0x1290, 0x1298, 0x12a0, 0x12a8,
00678 0x12b8, 0x12c8, 0x12d0, 0x12d8, 0x12e0, 0x12e8,
00679 0x12f0, 0x1300, 0x1308, 0x1320, 0x1328, 0x1330,
00680 0x1338, 0x1340, 0x1348, 0x1350
00681 };
00682 
00683 
00684 // We know cjk-ideographic need 31 characters to display 99,999,999,999,999,999
00685 // georgian needs 6 at most
00686 // armenian needs 12 at most
00687 // hebrew may need more...
00688 
00689 #define NUM_BUF_SIZE 34 
00690 
00691 static PRBool CharListToText(PRInt32 ordinal, nsString& result, const PRUnichar* chars, PRInt32 aBase)
00692 {
00693   PRUnichar buf[NUM_BUF_SIZE];
00694   PRInt32 idx = NUM_BUF_SIZE;
00695   if (ordinal < 1) {
00696     DecimalToText(ordinal, result);
00697     return PR_FALSE;
00698   }
00699   do {
00700     ordinal--; // a == 0
00701     PRInt32 cur = ordinal % aBase;
00702     buf[--idx] = chars[cur];
00703     ordinal /= aBase ;
00704   } while ( ordinal > 0);
00705   result.Append(buf+idx,NUM_BUF_SIZE-idx);
00706   return PR_TRUE;
00707 }
00708 
00709 
00710 static const PRUnichar gCJKIdeographicDigit1[10] =
00711 {
00712   0x96f6, 0x4e00, 0x4e8c, 0x4e09, 0x56db,  // 0 - 4
00713   0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d   // 5 - 9
00714 };
00715 static const PRUnichar gCJKIdeographicDigit2[10] =
00716 {
00717   0x96f6, 0x58f9, 0x8cb3, 0x53c3, 0x8086,  // 0 - 4
00718   0x4f0d, 0x9678, 0x67d2, 0x634c, 0x7396   // 5 - 9
00719 };
00720 static const PRUnichar gCJKIdeographicDigit3[10] =
00721 {
00722   0x96f6, 0x58f9, 0x8d30, 0x53c1, 0x8086,  // 0 - 4
00723   0x4f0d, 0x9646, 0x67d2, 0x634c, 0x7396   // 5 - 9
00724 };
00725 static const PRUnichar gCJKIdeographicUnit1[4] =
00726 {
00727   0x000, 0x5341, 0x767e, 0x5343
00728 };
00729 static const PRUnichar gCJKIdeographicUnit2[4] =
00730 {
00731   0x000, 0x62FE, 0x4F70, 0x4EDF
00732 };
00733 static const PRUnichar gCJKIdeographic10KUnit1[4] =
00734 {
00735   0x000, 0x842c, 0x5104, 0x5146
00736 };
00737 static const PRUnichar gCJKIdeographic10KUnit2[4] =
00738 {
00739   0x000, 0x4E07, 0x4ebf, 0x5146
00740 };
00741 static const PRUnichar gCJKIdeographic10KUnit3[4] =
00742 {
00743   0x000, 0x4E07, 0x5104, 0x5146
00744 };
00745 
00746 static const PRBool CJKIdeographicToText(PRInt32 ordinal, nsString& result, 
00747                                    const PRUnichar* digits,
00748                                    const PRUnichar *unit, 
00749                                    const PRUnichar* unit10k)
00750 {
00751 // In theory, we need the following if condiction,
00752 // However, the limit, 10 ^ 16, is greater than the max of PRUint32
00753 // so we don't really need to test it here.
00754 // if( ordinal > 9999999999999999)
00755 // {
00756 //    PR_snprintf(cbuf, sizeof(cbuf), "%ld", ordinal);
00757 //    result.Append(cbuf);
00758 // } 
00759 // else 
00760 // {
00761   if (ordinal < 0) {
00762     DecimalToText(ordinal, result);
00763     return PR_FALSE;
00764   }
00765   PRUnichar c10kUnit = 0;
00766   PRUnichar cUnit = 0;
00767   PRUnichar cDigit = 0;
00768   PRUint32 ud = 0;
00769   PRUnichar buf[NUM_BUF_SIZE];
00770   PRInt32 idx = NUM_BUF_SIZE;
00771   PRBool bOutputZero = ( 0 == ordinal );
00772   do {
00773     if(0 == (ud % 4)) {
00774       c10kUnit = unit10k[ud/4];
00775     }
00776     PRInt32 cur = ordinal % 10;
00777     cDigit = digits[cur];
00778     if( 0 == cur)
00779     {
00780       cUnit = 0;
00781       if(bOutputZero) {
00782         bOutputZero = PR_FALSE;
00783         if(0 != cDigit)
00784           buf[--idx] = cDigit;
00785       }
00786     }
00787     else
00788     {
00789       bOutputZero = PR_TRUE;
00790       cUnit = unit[ud%4];
00791 
00792       if(0 != c10kUnit)
00793         buf[--idx] = c10kUnit;
00794       if(0 != cUnit)
00795         buf[--idx] = cUnit;
00796       if((0 != cDigit) && 
00797          ( (1 != cur) || (1 != (ud%4)) || ( ordinal > 10)) )
00798         buf[--idx] = cDigit;
00799 
00800       c10kUnit =  0;
00801     }
00802     ordinal /= 10;
00803     ++ud;
00804 
00805   } while( ordinal > 0);
00806   result.Append(buf+idx,NUM_BUF_SIZE-idx);
00807 // }
00808   return PR_TRUE;
00809 }
00810 
00811 #define HEBREW_THROSAND_SEP 0x0020
00812 #define HEBREW_GERESH       0x05F3
00813 #define HEBREW_GERSHAYIM    0x05F4
00814 static const PRUnichar gHebrewDigit[22] = 
00815 {
00816 //   1       2       3       4       5       6       7       8       9
00817 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8,
00818 //  10      20      30      40      50      60      70      80      90
00819 0x05D9, 0x05DB, 0x05DC, 0x05DE, 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6,
00820 // 100     200     300     400
00821 0x05E7, 0x05E8, 0x05E9, 0x05EA
00822 };
00823 
00824 static PRBool HebrewToText(PRInt32 ordinal, nsString& result)
00825 {
00826   if (ordinal < 0) {
00827     DecimalToText(ordinal, result);
00828     return PR_FALSE;
00829   }
00830   if (ordinal == 0) {
00831     // This one is treated specially
00832 #ifdef IBMBIDI
00833     static const PRUnichar hebrewZero[] = { 0x05D0, 0x05E4, 0x05E1 };
00834 #else
00835     static const PRUnichar hebrewZero[] = { 0x05E1, 0x05E4, 0x05D0 };
00836 #endif // IBMBIDI
00837     result.Append(hebrewZero);
00838     return PR_TRUE;
00839   }
00840   PRBool outputSep = PR_FALSE;
00841   PRUnichar buf[NUM_BUF_SIZE];
00842 #ifdef IBMBIDI
00843   // Changes: 1) don't reverse the text; 2) don't insert geresh/gershayim.
00844   PRInt32 idx = 0;
00845 #else
00846   PRInt32 idx = NUM_BUF_SIZE;
00847 #endif // IBMBIDI
00848   PRUnichar digit;
00849   do {
00850     PRInt32 n3 = ordinal % 1000;
00851     if(outputSep)
00852 #ifdef IBMBIDI
00853       buf[idx++] = HEBREW_THROSAND_SEP; // output thousand separator
00854 #else
00855       buf[--idx] = HEBREW_THROSAND_SEP; // output thousand separator
00856 #endif // IBMBIDI
00857     outputSep = ( n3 > 0); // request to output thousand separator next time.
00858 
00859     PRInt32 d = 0; // we need to keep track of digit got output per 3 digits,
00860     // so we can handle Gershayim and Gersh correctly
00861 
00862     // Process digit for 100 - 900
00863     for(PRInt32 n1 = 400; n1 > 0; )
00864     {
00865       if( n3 >= n1)
00866       {
00867         n3 -= n1;
00868 
00869         digit = gHebrewDigit[(n1/100)-1+18];
00870         if( n3 > 0)
00871         {
00872 #ifdef IBMBIDI
00873           buf[idx++] = digit;
00874 #else
00875           buf[--idx] = digit;
00876 #endif // IBMBIDI
00877           ++d;
00878         } else { 
00879           // if this is the last digit
00880 #ifdef IBMBIDI
00881           buf[idx++] = digit;
00882 #else
00883           if (d > 0)
00884           {
00885             buf[--idx] = HEBREW_GERSHAYIM; 
00886             buf[--idx] = digit;
00887           } else {
00888             buf[--idx] = digit;    
00889             buf[--idx] = HEBREW_GERESH;
00890           } // if
00891 #endif // IBMBIDI
00892         } // if
00893       } else {
00894         n1 -= 100;
00895       } // if
00896     } // for
00897 
00898     // Process digit for 10 - 90
00899     PRInt32 n2;
00900     if( n3 >= 10 )
00901     {
00902       // Special process for 15 and 16
00903       if(( 15 == n3 ) || (16 == n3)) {
00904         // Special rule for religious reason...
00905         // 15 is represented by 9 and 6, not 10 and 5
00906         // 16 is represented by 9 and 7, not 10 and 6
00907         n2 = 9;
00908         digit = gHebrewDigit[ n2 - 1];    
00909       } else {
00910         n2 = n3 - (n3 % 10);
00911         digit = gHebrewDigit[(n2/10)-1+9];
00912       } // if
00913 
00914       n3 -= n2;
00915 
00916       if( n3  > 0) {
00917 #ifdef IBMBIDI
00918         buf[idx++] = digit;
00919 #else
00920         buf[--idx] = digit;
00921 #endif // IBMBIDI
00922         ++d;
00923       } else {
00924         // if this is the last digit
00925 #ifdef IBMBIDI
00926         buf[idx++] = digit;
00927 #else
00928         if (d > 0)
00929         {
00930           buf[--idx] = HEBREW_GERSHAYIM;  
00931           buf[--idx] = digit;
00932         } else {
00933           buf[--idx] = digit;    
00934           buf[--idx] = HEBREW_GERESH;
00935         } // if
00936 #endif // IBMBIDI
00937       } // if
00938     } // if
00939   
00940     // Process digit for 1 - 9 
00941     if ( n3 > 0)
00942     {
00943       digit = gHebrewDigit[n3-1];
00944       // must be the last digit
00945 #ifdef IBMBIDI
00946       buf[idx++] = digit;
00947 #else
00948       if (d > 0)
00949       {
00950         buf[--idx] = HEBREW_GERSHAYIM; 
00951         buf[--idx] = digit;
00952       } else {
00953         buf[--idx] = digit;    
00954         buf[--idx] = HEBREW_GERESH;
00955       } // if
00956 #endif // IBMBIDI
00957     } // if
00958     ordinal /= 1000;
00959   } while (ordinal >= 1);
00960 #ifdef IBMBIDI
00961   result.Append(buf, idx);
00962 #else
00963   result.Append(buf+idx,NUM_BUF_SIZE-idx);
00964 #endif // IBMBIDI
00965   return PR_TRUE;
00966 }
00967 
00968 
00969 static PRBool ArmenianToText(PRInt32 ordinal, nsString& result)
00970 {
00971   // XXXbz this system goes out to a lot further than 9999... we should fix
00972   // that.  This algorithm seems broken in general.  There's this business of
00973   // "7000" being special and then there's the combining accent we're supposed
00974   // to be using...
00975   if (ordinal < 1 || ordinal > 9999) { // zero or reach the limit of Armenian numbering system
00976     DecimalToText(ordinal, result);
00977     return PR_FALSE;
00978   }
00979 
00980   PRUnichar buf[NUM_BUF_SIZE];
00981   PRInt32 idx = NUM_BUF_SIZE;
00982   PRInt32 d = 0;
00983   do {
00984     PRInt32 cur = ordinal % 10;
00985     if (cur > 0)
00986     {
00987       PRUnichar u = 0x0530 + (d * 9) + cur;
00988       buf[--idx] = u;
00989     }
00990     ++d;
00991     ordinal /= 10;
00992   } while (ordinal > 0);
00993   result.Append(buf + idx, NUM_BUF_SIZE - idx);
00994   return PR_TRUE;
00995 }
00996 
00997 
00998 static const PRUnichar gGeorgianValue [ 37 ] = { // 4 * 9 + 1 = 37
00999 //      1       2       3       4       5       6       7       8       9
01000    0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10F1, 0x10D7,
01001 //     10      20      30      40      50      60      70      80      90
01002    0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10F2, 0x10DD, 0x10DE, 0x10DF,
01003 //    100     200     300     400     500     600     700     800     900
01004    0x10E0, 0x10E1, 0x10E2, 0x10F3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8,
01005 //   1000    2000    3000    4000    5000    6000    7000    8000    9000
01006    0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10F4, 0x10EF, 0x10F0,
01007 //  10000
01008    0x10F5
01009 };
01010 static PRBool GeorgianToText(PRInt32 ordinal, nsString& result)
01011 {
01012   if (ordinal < 1 || ordinal > 19999) { // zero or reach the limit of Georgian numbering system
01013     DecimalToText(ordinal, result);
01014     return PR_FALSE;
01015   }
01016 
01017   PRUnichar buf[NUM_BUF_SIZE];
01018   PRInt32 idx = NUM_BUF_SIZE;
01019   PRInt32 d = 0;
01020   do {
01021     PRInt32 cur = ordinal % 10;
01022     if (cur > 0)
01023     {
01024       PRUnichar u = gGeorgianValue[(d * 9 ) + ( cur - 1)];
01025       buf[--idx] = u;
01026     }
01027     ++d;
01028     ordinal /= 10;
01029   } while (ordinal > 0);
01030   result.Append(buf + idx, NUM_BUF_SIZE - idx);
01031   return PR_TRUE;
01032 }
01033 
01034 // Convert ordinal to Ethiopic numeric representation.
01035 // The detail is available at http://www.ethiopic.org/Numerals/
01036 // The algorithm used here is based on the pseudo-code put up there by
01037 // Daniel Yacob <yacob@geez.org>.
01038 // Another reference is Unicode 3.0 standard section 11.1.
01039 #define ETHIOPIC_ONE             0x1369
01040 #define ETHIOPIC_TEN             0x1372
01041 #define ETHIOPIC_HUNDRED         0x137B
01042 #define ETHIOPIC_TEN_THOUSAND    0x137C
01043 
01044 static PRBool EthiopicToText(PRInt32 ordinal, nsString& result)
01045 {
01046   nsAutoString asciiNumberString;      // decimal string representation of ordinal
01047   DecimalToText(ordinal, asciiNumberString);
01048   if (ordinal < 1) {
01049     result.Append(asciiNumberString);
01050     return PR_FALSE;
01051   }
01052   PRUint8 asciiStringLength = asciiNumberString.Length();
01053 
01054   // If number length is odd, add a leading "0"
01055   // the leading "0" preconditions the string to always have the
01056   // leading tens place populated, this avoids a check within the loop.
01057   // If we didn't add the leading "0", decrement asciiStringLength so
01058   // it will be equivalent to a zero-based index in both cases.
01059   if (asciiStringLength & 1) {
01060     asciiNumberString.Insert(NS_LITERAL_STRING("0"), 0);
01061   } else {
01062     asciiStringLength--;
01063   }
01064 
01065   // Iterate from the highest digits to lowest
01066   // indexFromLeft       indexes digits (0 = most significant)
01067   // groupIndexFromRight indexes pairs of digits (0 = least significant)
01068   for (PRUint8 indexFromLeft = 0, groupIndexFromRight = asciiStringLength >> 1;
01069        indexFromLeft <= asciiStringLength;
01070        indexFromLeft += 2, groupIndexFromRight--) {
01071     PRUint8 tensValue  = asciiNumberString.CharAt(indexFromLeft) & 0x0F;
01072     PRUint8 unitsValue = asciiNumberString.CharAt(indexFromLeft + 1) & 0x0F;
01073     PRUint8 groupValue = tensValue * 10 + unitsValue;
01074 
01075     PRBool oddGroup = (groupIndexFromRight & 1);
01076 
01077     // we want to clear ETHIOPIC_ONE when it is superfluous
01078     if (ordinal > 1 &&
01079         groupValue == 1 &&                  // one without a leading ten
01080         (oddGroup || indexFromLeft == 0)) { // preceding (100) or leading the sequence
01081       unitsValue = 0;
01082     }
01083 
01084     // put it all together...
01085     if (tensValue) {
01086       // map onto Ethiopic "tens":
01087       result.Append((PRUnichar) (tensValue +  ETHIOPIC_TEN - 1));
01088     }
01089     if (unitsValue) {
01090       //map onto Ethiopic "units":
01091       result.Append((PRUnichar) (unitsValue + ETHIOPIC_ONE - 1));
01092     }
01093     // Add a separator for all even groups except the last,
01094     // and for odd groups with non-zero value.
01095     if (oddGroup) {
01096       if (groupValue) {
01097         result.Append((PRUnichar) ETHIOPIC_HUNDRED);
01098       }
01099     } else {
01100       if (groupIndexFromRight) {
01101         result.Append((PRUnichar) ETHIOPIC_TEN_THOUSAND);
01102       }
01103     }
01104   }
01105   return PR_TRUE;
01106 }
01107 
01108 
01109 /* static */ PRBool
01110 nsBulletFrame::AppendCounterText(PRInt32 aListStyleType,
01111                                  PRInt32 aOrdinal,
01112                                  nsString& result)
01113 {
01114   PRBool success;
01115   
01116   switch (aListStyleType) {
01117     case NS_STYLE_LIST_STYLE_NONE: // used by counters code only
01118       break;
01119 
01120     case NS_STYLE_LIST_STYLE_DISC: // used by counters code only
01121       // XXX We really need to do this the same way we do list bullets.
01122       result.Append(PRUnichar(0x2022));
01123       break;
01124 
01125     case NS_STYLE_LIST_STYLE_CIRCLE: // used by counters code only
01126       // XXX We really need to do this the same way we do list bullets.
01127       result.Append(PRUnichar(0x25E6));
01128       break;
01129 
01130     case NS_STYLE_LIST_STYLE_SQUARE: // used by counters code only
01131       // XXX We really need to do this the same way we do list bullets.
01132       result.Append(PRUnichar(0x25FE));
01133       break;
01134 
01135     case NS_STYLE_LIST_STYLE_DECIMAL:
01136     case NS_STYLE_LIST_STYLE_OLD_DECIMAL:
01137     default: // CSS2 say "A users  agent that does not recognize a numbering system
01138       // should use 'decimal'
01139       success = DecimalToText(aOrdinal, result);
01140       break;
01141 
01142     case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO:
01143       success = DecimalLeadingZeroToText(aOrdinal, result);
01144       break;
01145 
01146     case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
01147     case NS_STYLE_LIST_STYLE_OLD_LOWER_ROMAN:
01148       success = RomanToText(aOrdinal, result,
01149                             gLowerRomanCharsA, gLowerRomanCharsB);
01150       break;
01151     case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
01152     case NS_STYLE_LIST_STYLE_OLD_UPPER_ROMAN:
01153       success = RomanToText(aOrdinal, result,
01154                             gUpperRomanCharsA, gUpperRomanCharsB);
01155       break;
01156 
01157     case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
01158     case NS_STYLE_LIST_STYLE_OLD_LOWER_ALPHA:
01159       success = CharListToText(aOrdinal, result, gLowerAlphaChars, ALPHA_SIZE);
01160       break;
01161 
01162     case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
01163     case NS_STYLE_LIST_STYLE_OLD_UPPER_ALPHA:
01164       success = CharListToText(aOrdinal, result, gUpperAlphaChars, ALPHA_SIZE);
01165       break;
01166 
01167     case NS_STYLE_LIST_STYLE_KATAKANA:
01168       success = CharListToText(aOrdinal, result, gKatakanaChars,
01169                                KATAKANA_CHARS_SIZE);
01170       break;
01171 
01172     case NS_STYLE_LIST_STYLE_HIRAGANA:
01173       success = CharListToText(aOrdinal, result, gHiraganaChars,
01174                                HIRAGANA_CHARS_SIZE);
01175       break;
01176     
01177     case NS_STYLE_LIST_STYLE_KATAKANA_IROHA:
01178       success = CharListToText(aOrdinal, result, gKatakanaIrohaChars,
01179                                KATAKANA_IROHA_CHARS_SIZE);
01180       break;
01181  
01182     case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA:
01183       success = CharListToText(aOrdinal, result, gHiraganaIrohaChars,
01184                                HIRAGANA_IROHA_CHARS_SIZE);
01185       break;
01186 
01187     case NS_STYLE_LIST_STYLE_LOWER_GREEK:
01188       success = CharListToText(aOrdinal, result, gLowerGreekChars ,
01189                                LOWER_GREEK_CHARS_SIZE);
01190       break;
01191 
01192     case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC: 
01193     case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL: 
01194       success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1,
01195                                      gCJKIdeographicUnit1,
01196                                      gCJKIdeographic10KUnit1);
01197       break;
01198 
01199     case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL: 
01200       success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit2,
01201                                      gCJKIdeographicUnit2,
01202                                      gCJKIdeographic10KUnit1);
01203       break;
01204 
01205     case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL: 
01206       success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1,
01207                                      gCJKIdeographicUnit1,
01208                                      gCJKIdeographic10KUnit2);
01209       break;
01210 
01211     case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL: 
01212       success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit3,
01213                                      gCJKIdeographicUnit2,
01214                                      gCJKIdeographic10KUnit2);
01215       break;
01216 
01217     case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL: 
01218       success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1,
01219                                      gCJKIdeographicUnit1,
01220                                      gCJKIdeographic10KUnit3);
01221       break;
01222 
01223     case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL: 
01224       success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit2,
01225                                      gCJKIdeographicUnit2,
01226                                      gCJKIdeographic10KUnit3);
01227       break;
01228 
01229     case NS_STYLE_LIST_STYLE_HEBREW: 
01230       success = HebrewToText(aOrdinal, result);
01231       break;
01232 
01233     case NS_STYLE_LIST_STYLE_ARMENIAN: 
01234       success = ArmenianToText(aOrdinal, result);
01235       break;
01236 
01237     case NS_STYLE_LIST_STYLE_GEORGIAN: 
01238       success = GeorgianToText(aOrdinal, result);
01239       break;
01240  
01241     case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC:
01242       success = OtherDecimalToText(aOrdinal, 0x0660, result);
01243       break;
01244  
01245     case NS_STYLE_LIST_STYLE_MOZ_PERSIAN:
01246     case NS_STYLE_LIST_STYLE_MOZ_URDU:
01247       success = OtherDecimalToText(aOrdinal, 0x06f0, result);
01248       break;
01249  
01250     case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI:
01251       success = OtherDecimalToText(aOrdinal, 0x0966, result);
01252       break;
01253  
01254     case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI:
01255       success = OtherDecimalToText(aOrdinal, 0x0a66, result);
01256       break;
01257  
01258     case NS_STYLE_LIST_STYLE_MOZ_GUJARATI:
01259       success = OtherDecimalToText(aOrdinal, 0x0AE6, result);
01260       break;
01261  
01262     case NS_STYLE_LIST_STYLE_MOZ_ORIYA:
01263       success = OtherDecimalToText(aOrdinal, 0x0B66, result);
01264       break;
01265  
01266     case NS_STYLE_LIST_STYLE_MOZ_KANNADA:
01267       success = OtherDecimalToText(aOrdinal, 0x0CE6, result);
01268       break;
01269  
01270     case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM:
01271       success = OtherDecimalToText(aOrdinal, 0x0D66, result);
01272       break;
01273  
01274     case NS_STYLE_LIST_STYLE_MOZ_THAI:
01275       success = OtherDecimalToText(aOrdinal, 0x0E50, result);
01276       break;
01277  
01278     case NS_STYLE_LIST_STYLE_MOZ_LAO:
01279       success = OtherDecimalToText(aOrdinal, 0x0ED0, result);
01280       break;
01281  
01282     case NS_STYLE_LIST_STYLE_MOZ_MYANMAR:
01283       success = OtherDecimalToText(aOrdinal, 0x1040, result);
01284       break;
01285  
01286     case NS_STYLE_LIST_STYLE_MOZ_KHMER:
01287       success = OtherDecimalToText(aOrdinal, 0x17E0, result);
01288       break;
01289  
01290     case NS_STYLE_LIST_STYLE_MOZ_BENGALI:
01291       success = OtherDecimalToText(aOrdinal, 0x09E6, result);
01292       break;
01293  
01294     case NS_STYLE_LIST_STYLE_MOZ_TELUGU:
01295       success = OtherDecimalToText(aOrdinal, 0x0C66, result);
01296       break;
01297  
01298     case NS_STYLE_LIST_STYLE_MOZ_TAMIL:
01299       success = TamilToText(aOrdinal, result);
01300       break;
01301 
01302     case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM:
01303       success = CharListToText(aOrdinal, result, gCJKHeavenlyStemChars,
01304                                CJK_HEAVENLY_STEM_CHARS_SIZE);
01305       break;
01306 
01307     case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH:
01308       success = CharListToText(aOrdinal, result, gCJKEarthlyBranchChars,
01309                                CJK_EARTHLY_BRANCH_CHARS_SIZE);
01310       break;
01311 
01312     case NS_STYLE_LIST_STYLE_MOZ_HANGUL:
01313       success = CharListToText(aOrdinal, result, gHangulChars, HANGUL_CHARS_SIZE);
01314       break;
01315 
01316     case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT:
01317       success = CharListToText(aOrdinal, result, gHangulConsonantChars,
01318                                HANGUL_CONSONANT_CHARS_SIZE);
01319       break;
01320 
01321     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME:
01322       success = CharListToText(aOrdinal, result, gEthiopicHalehameChars,
01323                                ETHIOPIC_HALEHAME_CHARS_SIZE);
01324       break;
01325 
01326     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC:
01327       success = EthiopicToText(aOrdinal, result);
01328       break;
01329 
01330     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM:
01331       success = CharListToText(aOrdinal, result, gEthiopicHalehameAmChars,
01332                                ETHIOPIC_HALEHAME_AM_CHARS_SIZE);
01333       break;
01334 
01335     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER:
01336       success = CharListToText(aOrdinal, result, gEthiopicHalehameTiErChars,
01337                                ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE);
01338       break;
01339 
01340     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET:
01341       success = CharListToText(aOrdinal, result, gEthiopicHalehameTiEtChars,
01342                                ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE);
01343       break;
01344   }
01345   return success;
01346 }
01347 
01348 PRBool
01349 nsBulletFrame::GetListItemText(const nsStyleList& aListStyle,
01350                                nsString& result)
01351 {
01352 #ifdef IBMBIDI
01353   const nsStyleVisibility* vis = GetStyleVisibility();
01354 
01355   // XXX For some of these systems, "." is wrong!  This should really be
01356   // pushed down into the individual cases!
01357   if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
01358     result.AppendLiteral(".");
01359   }
01360 #endif // IBMBIDI
01361 
01362   NS_ASSERTION(aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_NONE &&
01363                aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_DISC &&
01364                aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_CIRCLE &&
01365                aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_SQUARE,
01366                "we should be using specialized code for these types");
01367   PRBool success =
01368     AppendCounterText(aListStyle.mListStyleType, mOrdinal, result);
01369 
01370   // XXX For some of these systems, "." is wrong!  This should really be
01371   // pushed up into the cases...
01372 #ifdef IBMBIDI
01373   if (NS_STYLE_DIRECTION_RTL != vis->mDirection)
01374 #endif // IBMBIDI
01375   result.AppendLiteral(".");
01376   return success;
01377 }
01378 
01379 #define MIN_BULLET_SIZE 1
01380 
01381 
01382 #define MINMAX(_value,_min,_max) \
01383     ((_value) < (_min)           \
01384      ? (_min)                    \
01385      : ((_value) > (_max)        \
01386         ? (_max)                 \
01387         : (_value)))
01388 
01389 
01390 void
01391 nsBulletFrame::GetDesiredSize(nsPresContext*  aCX,
01392                               const nsHTMLReflowState& aReflowState,
01393                               nsHTMLReflowMetrics& aMetrics)
01394 {
01395   // Reset our padding.  If we need it, we'll set it below.
01396   mPadding.SizeTo(0, 0, 0, 0);
01397   
01398   const nsStyleList* myList = GetStyleList();
01399   nscoord ascent;
01400 
01401   if (myList->mListStyleImage && mImageRequest) {
01402     PRUint32 status;
01403     mImageRequest->GetImageStatus(&status);
01404     if (status & imgIRequest::STATUS_SIZE_AVAILABLE &&
01405         !(status & imgIRequest::STATUS_ERROR)) {
01406       nscoord widthConstraint = NS_INTRINSICSIZE;
01407       nscoord heightConstraint = NS_INTRINSICSIZE;
01408       PRBool fixedContentWidth = PR_FALSE;
01409       PRBool fixedContentHeight = PR_FALSE;
01410 
01411       nscoord minWidth, maxWidth, minHeight, maxHeight;
01412       
01413       // Determine whether the image has fixed content width
01414       widthConstraint = aReflowState.mComputedWidth;
01415       minWidth = aReflowState.mComputedMinWidth;
01416       maxWidth = aReflowState.mComputedMaxWidth;
01417       if (widthConstraint != NS_INTRINSICSIZE) {
01418         fixedContentWidth = PR_TRUE;
01419       }
01420 
01421       // Determine whether the image has fixed content height
01422       heightConstraint = aReflowState.mComputedHeight;
01423       minHeight = aReflowState.mComputedMinHeight;
01424       maxHeight = aReflowState.mComputedMaxHeight;
01425       if (heightConstraint != NS_UNCONSTRAINEDSIZE) {
01426         fixedContentHeight = PR_TRUE;
01427       }
01428 
01429       PRBool haveComputedSize = PR_FALSE;
01430       PRBool needIntrinsicImageSize = PR_FALSE;
01431 
01432       nscoord newWidth=0, newHeight=0;
01433       if (fixedContentWidth) {
01434         newWidth = MINMAX(widthConstraint, minWidth, maxWidth);
01435         if (fixedContentHeight) {
01436           newHeight = MINMAX(heightConstraint, minHeight, maxHeight);
01437           haveComputedSize = PR_TRUE;
01438         } else {
01439           // We have a width, and an auto height. Compute height from
01440           // width once we have the intrinsic image size.
01441           if (mIntrinsicSize.height != 0) {
01442             newHeight = (mIntrinsicSize.height * newWidth) / mIntrinsicSize.width;
01443             haveComputedSize = PR_TRUE;
01444           } else {
01445             newHeight = 0;
01446             needIntrinsicImageSize = PR_TRUE;
01447           }
01448         }
01449       } else if (fixedContentHeight) {
01450         // We have a height, and an auto width. Compute width from height
01451         // once we have the intrinsic image size.
01452         newHeight = MINMAX(heightConstraint, minHeight, maxHeight);
01453         if (mIntrinsicSize.width != 0) {
01454           newWidth = (mIntrinsicSize.width * newHeight) / mIntrinsicSize.height;
01455           haveComputedSize = PR_TRUE;
01456         } else {
01457           newWidth = 0;
01458           needIntrinsicImageSize = PR_TRUE;
01459         }
01460       } else {
01461         // auto size the image
01462         if (mIntrinsicSize.width == 0 && mIntrinsicSize.height == 0)
01463           needIntrinsicImageSize = PR_TRUE;
01464         else
01465           haveComputedSize = PR_TRUE;
01466 
01467         newWidth = mIntrinsicSize.width;
01468         newHeight = mIntrinsicSize.height;
01469       }
01470 
01471       mComputedSize.width = newWidth;
01472       mComputedSize.height = newHeight;
01473 
01474 #if 0 // don't do scaled images in bullets
01475       if (mComputedSize == mIntrinsicSize) {
01476         mTransform.SetToIdentity();
01477       } else {
01478         if (mComputedSize.width != 0 && mComputedSize.height != 0) {
01479           mTransform.SetToScale(float(mIntrinsicSize.width) / float(mComputedSize.width),
01480                                 float(mIntrinsicSize.height) / float(mComputedSize.height));
01481         }
01482       }
01483 #endif
01484 
01485       aMetrics.width = mComputedSize.width;
01486       aMetrics.height = mComputedSize.height;
01487 
01488       aMetrics.ascent = aMetrics.height;
01489       aMetrics.descent = 0;
01490 
01491       return;
01492     }
01493   }
01494 
01495   // If we're getting our desired size and don't have an image, reset
01496   // mIntrinsicSize to (0,0).  Otherwise, if we used to have an image, it
01497   // changed, and the new one is coming in, but we're reflowing before it's
01498   // fully there, we'll end up with mIntrinsicSize not matching our size, but
01499   // won't trigger a reflow in OnStartContainer (because mIntrinsicSize will
01500   // match the image size).
01501   mIntrinsicSize.SizeTo(0, 0);
01502 
01503   const nsStyleFont* myFont = GetStyleFont();
01504   nsCOMPtr<nsIFontMetrics> fm = aCX->GetMetricsFor(myFont->mFont);
01505   nscoord bulletSize;
01506   float p2t;
01507   float t2p;
01508 
01509   nsAutoString text;
01510   switch (myList->mListStyleType) {
01511     case NS_STYLE_LIST_STYLE_NONE:
01512       aMetrics.width = 0;
01513       aMetrics.height = 0;
01514       aMetrics.ascent = 0;
01515       aMetrics.descent = 0;
01516       break;
01517 
01518     case NS_STYLE_LIST_STYLE_DISC:
01519     case NS_STYLE_LIST_STYLE_CIRCLE:
01520     case NS_STYLE_LIST_STYLE_SQUARE:
01521       t2p = aCX->TwipsToPixels();
01522       fm->GetMaxAscent(ascent);
01523       bulletSize = NSTwipsToIntPixels(
01524         (nscoord)NSToIntRound(0.8f * (float(ascent) / 2.0f)), t2p);
01525       if (bulletSize < MIN_BULLET_SIZE) {
01526         bulletSize = MIN_BULLET_SIZE;
01527       }
01528       p2t = aCX->PixelsToTwips();
01529       bulletSize = NSIntPixelsToTwips(bulletSize, p2t);
01530       mPadding.bottom = NSIntPixelsToTwips((nscoord) NSToIntRound((float)ascent / (8.0f * p2t)),p2t);
01531       aMetrics.width = mPadding.right + bulletSize;
01532       aMetrics.height = mPadding.bottom + bulletSize;
01533       aMetrics.ascent = mPadding.bottom + bulletSize;
01534       aMetrics.descent = 0;
01535       break;
01536 
01537     default:
01538     case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO:
01539     case NS_STYLE_LIST_STYLE_DECIMAL:
01540     case NS_STYLE_LIST_STYLE_OLD_DECIMAL:
01541     case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
01542     case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
01543     case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
01544     case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
01545     case NS_STYLE_LIST_STYLE_OLD_LOWER_ROMAN:
01546     case NS_STYLE_LIST_STYLE_OLD_UPPER_ROMAN:
01547     case NS_STYLE_LIST_STYLE_OLD_LOWER_ALPHA:
01548     case NS_STYLE_LIST_STYLE_OLD_UPPER_ALPHA:
01549     case NS_STYLE_LIST_STYLE_KATAKANA:
01550     case NS_STYLE_LIST_STYLE_HIRAGANA:
01551     case NS_STYLE_LIST_STYLE_KATAKANA_IROHA:
01552     case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA:
01553     case NS_STYLE_LIST_STYLE_LOWER_GREEK:
01554     case NS_STYLE_LIST_STYLE_HEBREW: 
01555     case NS_STYLE_LIST_STYLE_ARMENIAN: 
01556     case NS_STYLE_LIST_STYLE_GEORGIAN: 
01557     case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC: 
01558     case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL: 
01559     case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL: 
01560     case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL: 
01561     case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL: 
01562     case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL: 
01563     case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL: 
01564     case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM:
01565     case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH:
01566     case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC:
01567     case NS_STYLE_LIST_STYLE_MOZ_PERSIAN:
01568     case NS_STYLE_LIST_STYLE_MOZ_URDU:
01569     case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI:
01570     case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI:
01571     case NS_STYLE_LIST_STYLE_MOZ_GUJARATI:
01572     case NS_STYLE_LIST_STYLE_MOZ_ORIYA:
01573     case NS_STYLE_LIST_STYLE_MOZ_KANNADA:
01574     case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM:
01575     case NS_STYLE_LIST_STYLE_MOZ_BENGALI:
01576     case NS_STYLE_LIST_STYLE_MOZ_TAMIL:
01577     case NS_STYLE_LIST_STYLE_MOZ_TELUGU:
01578     case NS_STYLE_LIST_STYLE_MOZ_THAI:
01579     case NS_STYLE_LIST_STYLE_MOZ_LAO:
01580     case NS_STYLE_LIST_STYLE_MOZ_MYANMAR:
01581     case NS_STYLE_LIST_STYLE_MOZ_KHMER:
01582     case NS_STYLE_LIST_STYLE_MOZ_HANGUL:
01583     case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT:
01584     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME:
01585     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC:
01586     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM:
01587     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER:
01588     case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET:
01589       GetListItemText(*myList, text);
01590       fm->GetHeight(aMetrics.height);
01591       aReflowState.rendContext->SetFont(fm);
01592       aReflowState.rendContext->GetWidth(text, aMetrics.width);
01593       aMetrics.width += mPadding.right;
01594       fm->GetMaxAscent(aMetrics.ascent);
01595       fm->GetMaxDescent(aMetrics.descent);
01596       break;
01597   }
01598 }
01599 
01600 NS_IMETHODIMP
01601 nsBulletFrame::Reflow(nsPresContext* aPresContext,
01602                       nsHTMLReflowMetrics& aMetrics,
01603                       const nsHTMLReflowState& aReflowState,
01604                       nsReflowStatus& aStatus)
01605 {
01606   DO_GLOBAL_REFLOW_COUNT("nsBulletFrame", aReflowState.reason);
01607   DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
01608 
01609   // Get the base size
01610   GetDesiredSize(aPresContext, aReflowState, aMetrics);
01611 
01612   // Add in the border and padding; split the top/bottom between the
01613   // ascent and descent to make things look nice
01614   const nsMargin& borderPadding = aReflowState.mComputedBorderPadding;
01615   aMetrics.width += borderPadding.left + borderPadding.right;
01616   aMetrics.height += borderPadding.top + borderPadding.bottom;
01617   aMetrics.ascent += borderPadding.top;
01618   aMetrics.descent += borderPadding.bottom;
01619 
01620   if (aMetrics.mComputeMEW) {
01621     aMetrics.mMaxElementWidth = aMetrics.width;
01622   }
01623   aStatus = NS_FRAME_COMPLETE;
01624   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
01625   return NS_OK;
01626 }
01627 
01628 
01629 NS_IMETHODIMP nsBulletFrame::OnStartContainer(imgIRequest *aRequest,
01630                                               imgIContainer *aImage)
01631 {
01632   if (!aImage) return NS_ERROR_INVALID_ARG;
01633   if (!aRequest) return NS_ERROR_INVALID_ARG;
01634 
01635   PRUint32 status;
01636   aRequest->GetImageStatus(&status);
01637   if (status & imgIRequest::STATUS_ERROR) {
01638     return NS_OK;
01639   }
01640   
01641   nscoord w, h;
01642   aImage->GetWidth(&w);
01643   aImage->GetHeight(&h);
01644 
01645   float p2t;
01646   nsPresContext* presContext = GetPresContext();
01647   p2t = presContext->PixelsToTwips();
01648 
01649   nsSize newsize(NSIntPixelsToTwips(w, p2t), NSIntPixelsToTwips(h, p2t));
01650 
01651   if (mIntrinsicSize != newsize) {
01652     mIntrinsicSize = newsize;
01653 
01654     // Now that the size is available (or an error occurred), trigger
01655     // a reflow of the bullet frame.
01656     nsIPresShell *shell = presContext->GetPresShell();
01657     if (shell) {
01658       NS_ASSERTION(mParent, "No parent to pass the reflow request up to.");
01659       if (mParent) {
01660         mState |= NS_FRAME_IS_DIRTY;
01661         mParent->ReflowDirtyChild(shell, this);
01662       }
01663     }
01664   }
01665 
01666   // Handle animations
01667   aImage->SetAnimationMode(presContext->ImageAnimationMode());
01668   // Ensure the animation (if any) is started.
01669   aImage->StartAnimation();
01670 
01671   
01672   return NS_OK;
01673 }
01674 
01675 NS_IMETHODIMP nsBulletFrame::OnDataAvailable(imgIRequest *aRequest,
01676                                              gfxIImageFrame *aFrame,
01677                                              const nsRect *aRect)
01678 {
01679   // The image has changed.
01680   // Invalidate the entire content area. Maybe it's not optimal but it's simple and
01681   // always correct, and I'll be a stunned mullet if it ever matters for performance
01682   Invalidate(nsRect(0, 0, mRect.width, mRect.height), PR_FALSE);
01683 
01684   return NS_OK;
01685 }
01686 
01687 NS_IMETHODIMP nsBulletFrame::OnStopDecode(imgIRequest *aRequest,
01688                                           nsresult aStatus,
01689                                           const PRUnichar *aStatusArg)
01690 {
01691   // XXX should the bulletframe do anything if the image failed to load?
01692   //     it didn't in the old code...
01693 
01694 #if 0
01695   if (NS_FAILED(aStatus)) {
01696     // We failed to load the image. Notify the pres shell
01697     if (NS_FAILED(aStatus) && (mImageRequest == aRequest || !mImageRequest)) {
01698       imageFailed = PR_TRUE;
01699     }
01700   }
01701 #endif
01702 
01703   return NS_OK;
01704 }
01705 
01706 NS_IMETHODIMP nsBulletFrame::FrameChanged(imgIContainer *aContainer,
01707                                           gfxIImageFrame *aNewFrame,
01708                                           nsRect *aDirtyRect)
01709 {
01710   // Invalidate the entire content area. Maybe it's not optimal but it's simple and
01711   // always correct.
01712   Invalidate(nsRect(0, 0, mRect.width, mRect.height), PR_FALSE);
01713 
01714   return NS_OK;
01715 }
01716 
01717 void
01718 nsBulletFrame::GetLoadGroup(nsPresContext *aPresContext, nsILoadGroup **aLoadGroup)
01719 {
01720   if (!aPresContext)
01721     return;
01722 
01723   NS_PRECONDITION(nsnull != aLoadGroup, "null OUT parameter pointer");
01724 
01725   nsIPresShell *shell = aPresContext->GetPresShell();
01726 
01727   if (!shell)
01728     return;
01729 
01730   nsIDocument *doc = shell->GetDocument();
01731   if (!doc)
01732     return;
01733 
01734   *aLoadGroup = doc->GetDocumentLoadGroup().get();  // already_AddRefed
01735 }
01736 
01737 
01738 
01739 
01740 
01741 
01742 
01743 
01744 NS_IMPL_ISUPPORTS2(nsBulletListener, imgIDecoderObserver, imgIContainerObserver)
01745 
01746 nsBulletListener::nsBulletListener() :
01747   mFrame(nsnull)
01748 {
01749 }
01750 
01751 nsBulletListener::~nsBulletListener()
01752 {
01753 }
01754 
01755 NS_IMETHODIMP nsBulletListener::OnStartDecode(imgIRequest *aRequest)
01756 {
01757   return NS_OK;
01758 }
01759 
01760 NS_IMETHODIMP nsBulletListener::OnStartContainer(imgIRequest *aRequest,
01761                                                  imgIContainer *aImage)
01762 {
01763   if (!mFrame)
01764     return NS_ERROR_FAILURE;
01765 
01766   return mFrame->OnStartContainer(aRequest, aImage);
01767 }
01768 
01769 NS_IMETHODIMP nsBulletListener::OnStartFrame(imgIRequest *aRequest,
01770                                              gfxIImageFrame *aFrame)
01771 {
01772   return NS_OK;
01773 }
01774 
01775 NS_IMETHODIMP nsBulletListener::OnDataAvailable(imgIRequest *aRequest,
01776                                                 gfxIImageFrame *aFrame,
01777                                                 const nsRect *aRect)
01778 {
01779   if (!mFrame)
01780     return NS_ERROR_FAILURE;
01781 
01782   return mFrame->OnDataAvailable(aRequest, aFrame, aRect);
01783 }
01784 
01785 NS_IMETHODIMP nsBulletListener::OnStopFrame(imgIRequest *aRequest,
01786                                             gfxIImageFrame *aFrame)
01787 {
01788   return NS_OK;
01789 }
01790 
01791 NS_IMETHODIMP nsBulletListener::OnStopContainer(imgIRequest *aRequest,
01792                                                 imgIContainer *aImage)
01793 {
01794   return NS_OK;
01795 }
01796 
01797 NS_IMETHODIMP nsBulletListener::OnStopDecode(imgIRequest *aRequest,
01798                                              nsresult status,
01799                                              const PRUnichar *statusArg)
01800 {
01801   if (!mFrame)
01802     return NS_ERROR_FAILURE;
01803   
01804   return mFrame->OnStopDecode(aRequest, status, statusArg);
01805 }
01806 
01807 NS_IMETHODIMP nsBulletListener::FrameChanged(imgIContainer *aContainer,
01808                                              gfxIImageFrame *newframe,
01809                                              nsRect * dirtyRect)
01810 {
01811   if (!mFrame)
01812     return NS_ERROR_FAILURE;
01813 
01814   return mFrame->FrameChanged(aContainer, newframe, dirtyRect);
01815 }