Bug 449371 Firefox/Thunderbird crashes at exit [@ gdk_display_x11_finalize], p=Brian...
[wine-gecko.git] / layout / generic / nsBulletFrame.cpp
blobe4e1aa8b38aa6d1973463bf08ccb2e5e35c64b6a
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 /* rendering object for list-item bullets */
40 #include "nsCOMPtr.h"
41 #include "nsBulletFrame.h"
42 #include "nsGkAtoms.h"
43 #include "nsHTMLParts.h"
44 #include "nsHTMLContainerFrame.h"
45 #include "nsIFontMetrics.h"
46 #include "nsGenericHTMLElement.h"
47 #include "nsPresContext.h"
48 #include "nsIPresShell.h"
49 #include "nsIDocument.h"
50 #include "nsIRenderingContext.h"
51 #include "nsILoadGroup.h"
52 #include "nsIURL.h"
53 #include "nsNetUtil.h"
54 #include "prprf.h"
55 #include "nsDisplayList.h"
57 #include "imgILoader.h"
58 #include "imgIContainer.h"
59 #include "nsStubImageDecoderObserver.h"
61 #include "nsIServiceManager.h"
62 #include "nsIComponentManager.h"
63 #include "nsContentUtils.h"
65 class nsBulletListener : public nsStubImageDecoderObserver
67 public:
68 nsBulletListener();
69 virtual ~nsBulletListener();
71 NS_DECL_ISUPPORTS
72 // imgIDecoderObserver (override nsStubImageDecoderObserver)
73 NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
74 NS_IMETHOD OnDataAvailable(imgIRequest *aRequest, gfxIImageFrame *aFrame,
75 const nsRect *aRect);
76 NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult status,
77 const PRUnichar *statusArg);
78 // imgIContainerObserver (override nsStubImageDecoderObserver)
79 NS_IMETHOD FrameChanged(imgIContainer *aContainer, gfxIImageFrame *newframe,
80 nsRect * dirtyRect);
82 void SetFrame(nsBulletFrame *frame) { mFrame = frame; }
84 private:
85 nsBulletFrame *mFrame;
89 nsBulletFrame::~nsBulletFrame()
93 void
94 nsBulletFrame::Destroy()
96 // Stop image loading first
97 if (mImageRequest) {
98 mImageRequest->Cancel(NS_ERROR_FAILURE);
99 mImageRequest = nsnull;
102 if (mListener)
103 reinterpret_cast<nsBulletListener*>(mListener.get())->SetFrame(nsnull);
105 // Let base class do the rest
106 nsFrame::Destroy();
109 #ifdef NS_DEBUG
110 NS_IMETHODIMP
111 nsBulletFrame::GetFrameName(nsAString& aResult) const
113 return MakeFrameName(NS_LITERAL_STRING("Bullet"), aResult);
115 #endif
117 nsIAtom*
118 nsBulletFrame::GetType() const
120 return nsGkAtoms::bulletFrame;
123 PRBool
124 nsBulletFrame::IsEmpty()
126 return IsSelfEmpty();
129 PRBool
130 nsBulletFrame::IsSelfEmpty()
132 return GetStyleList()->mListStyleType == NS_STYLE_LIST_STYLE_NONE;
135 NS_IMETHODIMP
136 nsBulletFrame::DidSetStyleContext()
138 imgIRequest *newRequest = GetStyleList()->mListStyleImage;
140 if (newRequest) {
142 if (!mListener) {
143 nsBulletListener *listener;
144 NS_NEWXPCOM(listener, nsBulletListener);
145 NS_ADDREF(listener);
146 listener->SetFrame(this);
147 listener->QueryInterface(NS_GET_IID(imgIDecoderObserver), getter_AddRefs(mListener));
148 NS_ASSERTION(mListener, "queryinterface for the listener failed");
149 NS_RELEASE(listener);
152 PRBool needNewRequest = PR_TRUE;
154 if (mImageRequest) {
155 // Reload the image, maybe...
156 nsCOMPtr<nsIURI> oldURI;
157 mImageRequest->GetURI(getter_AddRefs(oldURI));
158 nsCOMPtr<nsIURI> newURI;
159 newRequest->GetURI(getter_AddRefs(newURI));
160 if (oldURI && newURI) {
161 PRBool same;
162 newURI->Equals(oldURI, &same);
163 if (same) {
164 needNewRequest = PR_FALSE;
165 } else {
166 mImageRequest->Cancel(NS_ERROR_FAILURE);
167 mImageRequest = nsnull;
172 if (needNewRequest) {
173 newRequest->Clone(mListener, getter_AddRefs(mImageRequest));
175 } else {
176 // No image request on the new style context
177 if (mImageRequest) {
178 mImageRequest->Cancel(NS_ERROR_FAILURE);
179 mImageRequest = nsnull;
183 return NS_OK;
186 class nsDisplayBullet : public nsDisplayItem {
187 public:
188 nsDisplayBullet(nsBulletFrame* aFrame) : nsDisplayItem(aFrame) {
189 MOZ_COUNT_CTOR(nsDisplayBullet);
191 #ifdef NS_BUILD_REFCNT_LOGGING
192 virtual ~nsDisplayBullet() {
193 MOZ_COUNT_DTOR(nsDisplayBullet);
195 #endif
197 virtual nsIFrame* HitTest(nsDisplayListBuilder* aBuilder, nsPoint aPt,
198 HitTestState* aState) { return mFrame; }
199 virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
200 const nsRect& aDirtyRect);
201 NS_DISPLAY_DECL_NAME("Bullet")
204 void nsDisplayBullet::Paint(nsDisplayListBuilder* aBuilder,
205 nsIRenderingContext* aCtx, const nsRect& aDirtyRect)
207 static_cast<nsBulletFrame*>(mFrame)->
208 PaintBullet(*aCtx, aBuilder->ToReferenceFrame(mFrame), aDirtyRect);
211 NS_IMETHODIMP
212 nsBulletFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
213 const nsRect& aDirtyRect,
214 const nsDisplayListSet& aLists)
216 if (!IsVisibleForPainting(aBuilder))
217 return NS_OK;
219 DO_GLOBAL_REFLOW_COUNT_DSP("nsBulletFrame");
221 return aLists.Content()->AppendNewToTop(new (aBuilder) nsDisplayBullet(this));
224 void
225 nsBulletFrame::PaintBullet(nsIRenderingContext& aRenderingContext, nsPoint aPt,
226 const nsRect& aDirtyRect)
228 const nsStyleList* myList = GetStyleList();
229 PRUint8 listStyleType = myList->mListStyleType;
231 if (myList->mListStyleImage && mImageRequest) {
232 PRUint32 status;
233 mImageRequest->GetImageStatus(&status);
234 if (status & imgIRequest::STATUS_LOAD_COMPLETE &&
235 !(status & imgIRequest::STATUS_ERROR)) {
236 nsCOMPtr<imgIContainer> imageCon;
237 mImageRequest->GetImage(getter_AddRefs(imageCon));
238 if (imageCon) {
239 nsRect dest(mPadding.left, mPadding.top,
240 mRect.width - (mPadding.left + mPadding.right),
241 mRect.height - (mPadding.top + mPadding.bottom));
242 nsLayoutUtils::DrawImage(&aRenderingContext, imageCon,
243 dest + aPt, aDirtyRect);
244 return;
249 const nsStyleColor* myColor = GetStyleColor();
251 nsCOMPtr<nsIFontMetrics> fm;
252 aRenderingContext.SetColor(myColor->mColor);
254 mTextIsRTL = PR_FALSE;
256 nsAutoString text;
257 switch (listStyleType) {
258 case NS_STYLE_LIST_STYLE_NONE:
259 break;
261 default:
262 case NS_STYLE_LIST_STYLE_DISC:
263 aRenderingContext.FillEllipse(mPadding.left + aPt.x, mPadding.top + aPt.y,
264 mRect.width - (mPadding.left + mPadding.right),
265 mRect.height - (mPadding.top + mPadding.bottom));
266 break;
268 case NS_STYLE_LIST_STYLE_CIRCLE:
269 aRenderingContext.DrawEllipse(mPadding.left + aPt.x, mPadding.top + aPt.y,
270 mRect.width - (mPadding.left + mPadding.right),
271 mRect.height - (mPadding.top + mPadding.bottom));
272 break;
274 case NS_STYLE_LIST_STYLE_SQUARE:
275 aRenderingContext.FillRect(mPadding.left + aPt.x, mPadding.top + aPt.y,
276 mRect.width - (mPadding.left + mPadding.right),
277 mRect.height - (mPadding.top + mPadding.bottom));
278 break;
280 case NS_STYLE_LIST_STYLE_DECIMAL:
281 case NS_STYLE_LIST_STYLE_OLD_DECIMAL:
282 case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO:
283 case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
284 case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
285 case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
286 case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
287 case NS_STYLE_LIST_STYLE_OLD_LOWER_ROMAN:
288 case NS_STYLE_LIST_STYLE_OLD_UPPER_ROMAN:
289 case NS_STYLE_LIST_STYLE_OLD_LOWER_ALPHA:
290 case NS_STYLE_LIST_STYLE_OLD_UPPER_ALPHA:
291 case NS_STYLE_LIST_STYLE_LOWER_GREEK:
292 case NS_STYLE_LIST_STYLE_HEBREW:
293 case NS_STYLE_LIST_STYLE_ARMENIAN:
294 case NS_STYLE_LIST_STYLE_GEORGIAN:
295 case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC:
296 case NS_STYLE_LIST_STYLE_HIRAGANA:
297 case NS_STYLE_LIST_STYLE_KATAKANA:
298 case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA:
299 case NS_STYLE_LIST_STYLE_KATAKANA_IROHA:
300 case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL:
301 case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL:
302 case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL:
303 case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL:
304 case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL:
305 case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL:
306 case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM:
307 case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH:
308 case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC:
309 case NS_STYLE_LIST_STYLE_MOZ_PERSIAN:
310 case NS_STYLE_LIST_STYLE_MOZ_URDU:
311 case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI:
312 case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI:
313 case NS_STYLE_LIST_STYLE_MOZ_GUJARATI:
314 case NS_STYLE_LIST_STYLE_MOZ_ORIYA:
315 case NS_STYLE_LIST_STYLE_MOZ_KANNADA:
316 case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM:
317 case NS_STYLE_LIST_STYLE_MOZ_BENGALI:
318 case NS_STYLE_LIST_STYLE_MOZ_TAMIL:
319 case NS_STYLE_LIST_STYLE_MOZ_TELUGU:
320 case NS_STYLE_LIST_STYLE_MOZ_THAI:
321 case NS_STYLE_LIST_STYLE_MOZ_LAO:
322 case NS_STYLE_LIST_STYLE_MOZ_MYANMAR:
323 case NS_STYLE_LIST_STYLE_MOZ_KHMER:
324 case NS_STYLE_LIST_STYLE_MOZ_HANGUL:
325 case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT:
326 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME:
327 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC:
328 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM:
329 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER:
330 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET:
331 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
332 GetListItemText(*myList, text);
333 aRenderingContext.SetFont(fm);
334 nscoord ascent;
335 fm->GetMaxAscent(ascent);
336 aRenderingContext.SetTextRunRTL(mTextIsRTL);
337 aRenderingContext.DrawString(text, mPadding.left + aPt.x,
338 mPadding.top + aPt.y + ascent);
339 break;
343 PRInt32
344 nsBulletFrame::SetListItemOrdinal(PRInt32 aNextOrdinal,
345 PRBool* aChanged)
347 // Assume that the ordinal comes from the caller
348 PRInt32 oldOrdinal = mOrdinal;
349 mOrdinal = aNextOrdinal;
351 // Try to get value directly from the list-item, if it specifies a
352 // value attribute. Note: we do this with our parent's content
353 // because our parent is the list-item.
354 nsIContent* parentContent = mParent->GetContent();
355 if (parentContent) {
356 nsGenericHTMLElement *hc =
357 nsGenericHTMLElement::FromContent(parentContent);
358 if (hc) {
359 const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::value);
360 if (attr && attr->Type() == nsAttrValue::eInteger) {
361 // Use ordinal specified by the value attribute
362 mOrdinal = attr->GetIntegerValue();
367 *aChanged = oldOrdinal != mOrdinal;
369 return mOrdinal + 1;
373 // XXX change roman/alpha to use unsigned math so that maxint and
374 // maxnegint will work
377 * For all functions below, a return value of PR_TRUE means that we
378 * could represent mOrder in the desired numbering system. PR_FALSE
379 * means we had to fall back to decimal
381 static PRBool DecimalToText(PRInt32 ordinal, nsString& result)
383 char cbuf[40];
384 PR_snprintf(cbuf, sizeof(cbuf), "%ld", ordinal);
385 result.AppendASCII(cbuf);
386 return PR_TRUE;
388 static PRBool DecimalLeadingZeroToText(PRInt32 ordinal, nsString& result)
390 char cbuf[40];
391 PR_snprintf(cbuf, sizeof(cbuf), "%02ld", ordinal);
392 result.AppendASCII(cbuf);
393 return PR_TRUE;
395 static PRBool OtherDecimalToText(PRInt32 ordinal, PRUnichar zeroChar, nsString& result)
397 PRUnichar diff = zeroChar - PRUnichar('0');
398 DecimalToText(ordinal, result);
399 PRUnichar* p = result.BeginWriting();
400 if (ordinal < 0) {
401 // skip the leading '-'
402 ++p;
404 for(; nsnull != *p ; p++)
405 *p += diff;
406 return PR_TRUE;
408 static PRBool TamilToText(PRInt32 ordinal, nsString& result)
410 PRUnichar diff = 0x0BE6 - PRUnichar('0');
411 DecimalToText(ordinal, result);
412 if (ordinal < 1 || ordinal > 9999) {
413 // Can't do those in this system.
414 return PR_FALSE;
416 PRUnichar* p = result.BeginWriting();
417 for(; nsnull != *p ; p++)
418 if(*p != PRUnichar('0'))
419 *p += diff;
420 return PR_TRUE;
424 static const char gLowerRomanCharsA[] = "ixcm";
425 static const char gUpperRomanCharsA[] = "IXCM";
426 static const char gLowerRomanCharsB[] = "vld";
427 static const char gUpperRomanCharsB[] = "VLD";
429 static PRBool RomanToText(PRInt32 ordinal, nsString& result, const char* achars, const char* bchars)
431 if (ordinal < 1 || ordinal > 3999) {
432 DecimalToText(ordinal, result);
433 return PR_FALSE;
435 nsAutoString addOn, decStr;
436 decStr.AppendInt(ordinal, 10);
437 PRIntn len = decStr.Length();
438 const PRUnichar* dp = decStr.get();
439 const PRUnichar* end = dp + len;
440 PRIntn romanPos = len;
441 PRIntn n;
443 for (; dp < end; dp++) {
444 romanPos--;
445 addOn.SetLength(0);
446 switch(*dp) {
447 case '3': addOn.Append(PRUnichar(achars[romanPos]));
448 case '2': addOn.Append(PRUnichar(achars[romanPos]));
449 case '1': addOn.Append(PRUnichar(achars[romanPos]));
450 break;
451 case '4':
452 addOn.Append(PRUnichar(achars[romanPos]));
453 // FALLTHROUGH
454 case '5': case '6':
455 case '7': case '8':
456 addOn.Append(PRUnichar(bchars[romanPos]));
457 for(n=0;n<(*dp-'5');n++) {
458 addOn.Append(PRUnichar(achars[romanPos]));
460 break;
461 case '9':
462 addOn.Append(PRUnichar(achars[romanPos]));
463 addOn.Append(PRUnichar(achars[romanPos+1]));
464 break;
465 default:
466 break;
468 result.Append(addOn);
470 return PR_TRUE;
473 #define ALPHA_SIZE 26
474 static const PRUnichar gLowerAlphaChars[ALPHA_SIZE] =
476 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, // A B C D E
477 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, // F G H I J
478 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, // K L M N O
479 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, // P Q R S T
480 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, // U V W X Y
481 0x007A // Z
484 static const PRUnichar gUpperAlphaChars[ALPHA_SIZE] =
486 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, // A B C D E
487 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, // F G H I J
488 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, // K L M N O
489 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, // P Q R S T
490 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, // U V W X Y
491 0x005A // Z
495 #define KATAKANA_CHARS_SIZE 48
496 // Page 94 Writing Systems of The World
497 // after modification by momoi
498 static const PRUnichar gKatakanaChars[KATAKANA_CHARS_SIZE] =
500 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, // a i u e o
501 0x30AB, 0x30AD, 0x30AF, 0x30B1, 0x30B3, // ka ki ku ke ko
502 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD, // sa shi su se so
503 0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, // ta chi tsu te to
504 0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, // na ni nu ne no
505 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, // ha hi hu he ho
506 0x30DE, 0x30DF, 0x30E0, 0x30E1, 0x30E2, // ma mi mu me mo
507 0x30E4, 0x30E6, 0x30E8, // ya yu yo
508 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, // ra ri ru re ro
509 0x30EF, 0x30F0, 0x30F1, 0x30F2, // wa (w)i (w)e (w)o
510 0x30F3 // n
513 #define HIRAGANA_CHARS_SIZE 48
514 static const PRUnichar gHiraganaChars[HIRAGANA_CHARS_SIZE] =
516 0x3042, 0x3044, 0x3046, 0x3048, 0x304A, // a i u e o
517 0x304B, 0x304D, 0x304F, 0x3051, 0x3053, // ka ki ku ke ko
518 0x3055, 0x3057, 0x3059, 0x305B, 0x305D, // sa shi su se so
519 0x305F, 0x3061, 0x3064, 0x3066, 0x3068, // ta chi tsu te to
520 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, // na ni nu ne no
521 0x306F, 0x3072, 0x3075, 0x3078, 0x307B, // ha hi hu he ho
522 0x307E, 0x307F, 0x3080, 0x3081, 0x3082, // ma mi mu me mo
523 0x3084, 0x3086, 0x3088, // ya yu yo
524 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, // ra ri ru re ro
525 0x308F, 0x3090, 0x3091, 0x3092, // wa (w)i (w)e (w)o
526 0x3093 // n
530 #define HIRAGANA_IROHA_CHARS_SIZE 47
531 // Page 94 Writing Systems of The World
532 static const PRUnichar gHiraganaIrohaChars[HIRAGANA_IROHA_CHARS_SIZE] =
534 0x3044, 0x308D, 0x306F, 0x306B, 0x307B, // i ro ha ni ho
535 0x3078, 0x3068, 0x3061, 0x308A, 0x306C, // he to chi ri nu
536 0x308B, 0x3092, 0x308F, 0x304B, 0x3088, // ru (w)o wa ka yo
537 0x305F, 0x308C, 0x305D, 0x3064, 0x306D, // ta re so tsu ne
538 0x306A, 0x3089, 0x3080, 0x3046, 0x3090, // na ra mu u (w)i
539 0x306E, 0x304A, 0x304F, 0x3084, 0x307E, // no o ku ya ma
540 0x3051, 0x3075, 0x3053, 0x3048, 0x3066, // ke hu ko e te
541 0x3042, 0x3055, 0x304D, 0x3086, 0x3081, // a sa ki yu me
542 0x307F, 0x3057, 0x3091, 0x3072, 0x3082, // mi shi (w)e hi mo
543 0x305B, 0x3059 // se su
546 #define KATAKANA_IROHA_CHARS_SIZE 47
547 static const PRUnichar gKatakanaIrohaChars[KATAKANA_IROHA_CHARS_SIZE] =
549 0x30A4, 0x30ED, 0x30CF, 0x30CB, 0x30DB, // i ro ha ni ho
550 0x30D8, 0x30C8, 0x30C1, 0x30EA, 0x30CC, // he to chi ri nu
551 0x30EB, 0x30F2, 0x30EF, 0x30AB, 0x30E8, // ru (w)o wa ka yo
552 0x30BF, 0x30EC, 0x30BD, 0x30C4, 0x30CD, // ta re so tsu ne
553 0x30CA, 0x30E9, 0x30E0, 0x30A6, 0x30F0, // na ra mu u (w)i
554 0x30CE, 0x30AA, 0x30AF, 0x30E4, 0x30DE, // no o ku ya ma
555 0x30B1, 0x30D5, 0x30B3, 0x30A8, 0x30C6, // ke hu ko e te
556 0x30A2, 0x30B5, 0x30AD, 0x30E6, 0x30E1, // a sa ki yu me
557 0x30DF, 0x30B7, 0x30F1, 0x30D2, 0x30E2, // mi shi (w)e hi mo
558 0x30BB, 0x30B9 // se su
561 #define LOWER_GREEK_CHARS_SIZE 24
562 // Note: 0x03C2 GREEK FINAL SIGMA is not used in here....
563 static const PRUnichar gLowerGreekChars[LOWER_GREEK_CHARS_SIZE] =
565 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, // alpha beta gamma delta epsilon
566 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, // zeta eta theta iota kappa
567 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, // lamda mu nu xi omicron
568 0x03C0, 0x03C1, 0x03C3, 0x03C4, 0x03C5, // pi rho sigma tau upsilon
569 0x03C6, 0x03C7, 0x03C8, 0x03C9 // phi chi psi omega
572 #define CJK_HEAVENLY_STEM_CHARS_SIZE 10
573 static const PRUnichar gCJKHeavenlyStemChars[CJK_HEAVENLY_STEM_CHARS_SIZE] =
575 0x7532, 0x4e59, 0x4e19, 0x4e01, 0x620a,
576 0x5df1, 0x5e9a, 0x8f9b, 0x58ec, 0x7678
578 #define CJK_EARTHLY_BRANCH_CHARS_SIZE 12
579 static const PRUnichar gCJKEarthlyBranchChars[CJK_EARTHLY_BRANCH_CHARS_SIZE] =
581 0x5b50, 0x4e11, 0x5bc5, 0x536f, 0x8fb0, 0x5df3,
582 0x5348, 0x672a, 0x7533, 0x9149, 0x620c, 0x4ea5
584 #define HANGUL_CHARS_SIZE 14
585 static const PRUnichar gHangulChars[HANGUL_CHARS_SIZE] =
587 0xac00, 0xb098, 0xb2e4, 0xb77c, 0xb9c8, 0xbc14,
588 0xc0ac, 0xc544, 0xc790, 0xcc28, 0xce74, 0xd0c0,
589 0xd30c, 0xd558
591 #define HANGUL_CONSONANT_CHARS_SIZE 14
592 static const PRUnichar gHangulConsonantChars[HANGUL_CONSONANT_CHARS_SIZE] =
594 0x3131, 0x3134, 0x3137, 0x3139, 0x3141, 0x3142,
595 0x3145, 0x3147, 0x3148, 0x314a, 0x314b, 0x314c,
596 0x314d, 0x314e
599 // Ge'ez set of Ethiopic ordered list. There are other locale-dependent sets.
600 // For the time being, let's implement two Ge'ez sets only
601 // per Momoi san's suggestion in bug 102252.
602 // For details, refer to http://www.ethiopic.org/Collation/OrderedLists.html.
603 #define ETHIOPIC_HALEHAME_CHARS_SIZE 26
604 static const PRUnichar gEthiopicHalehameChars[ETHIOPIC_HALEHAME_CHARS_SIZE] =
606 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228,
607 0x1230, 0x1240, 0x1260, 0x1270, 0x1280, 0x1290,
608 0x12a0, 0x12a8, 0x12c8, 0x12d0, 0x12d8, 0x12e8,
609 0x12f0, 0x1308, 0x1320, 0x1330, 0x1338, 0x1340,
610 0x1348, 0x1350
612 #define ETHIOPIC_HALEHAME_AM_CHARS_SIZE 33
613 static const PRUnichar gEthiopicHalehameAmChars[ETHIOPIC_HALEHAME_AM_CHARS_SIZE] =
615 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228,
616 0x1230, 0x1238, 0x1240, 0x1260, 0x1270, 0x1278,
617 0x1280, 0x1290, 0x1298, 0x12a0, 0x12a8, 0x12b8,
618 0x12c8, 0x12d0, 0x12d8, 0x12e0, 0x12e8, 0x12f0,
619 0x1300, 0x1308, 0x1320, 0x1328, 0x1330, 0x1338,
620 0x1340, 0x1348, 0x1350
622 #define ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE 31
623 static const PRUnichar gEthiopicHalehameTiErChars[ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE] =
625 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230,
626 0x1238, 0x1240, 0x1250, 0x1260, 0x1270, 0x1278,
627 0x1290, 0x1298, 0x12a0, 0x12a8, 0x12b8, 0x12c8,
628 0x12d0, 0x12d8, 0x12e0, 0x12e8, 0x12f0, 0x1300,
629 0x1308, 0x1320, 0x1328, 0x1330, 0x1338, 0x1348,
630 0x1350
632 #define ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE 34
633 static const PRUnichar gEthiopicHalehameTiEtChars[ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE] =
635 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228,
636 0x1230, 0x1238, 0x1240, 0x1250, 0x1260, 0x1270,
637 0x1278, 0x1280, 0x1290, 0x1298, 0x12a0, 0x12a8,
638 0x12b8, 0x12c8, 0x12d0, 0x12d8, 0x12e0, 0x12e8,
639 0x12f0, 0x1300, 0x1308, 0x1320, 0x1328, 0x1330,
640 0x1338, 0x1340, 0x1348, 0x1350
644 // We know cjk-ideographic need 31 characters to display 99,999,999,999,999,999
645 // georgian needs 6 at most
646 // armenian needs 12 at most
647 // hebrew may need more...
649 #define NUM_BUF_SIZE 34
651 static PRBool CharListToText(PRInt32 ordinal, nsString& result, const PRUnichar* chars, PRInt32 aBase)
653 PRUnichar buf[NUM_BUF_SIZE];
654 PRInt32 idx = NUM_BUF_SIZE;
655 if (ordinal < 1) {
656 DecimalToText(ordinal, result);
657 return PR_FALSE;
659 do {
660 ordinal--; // a == 0
661 PRInt32 cur = ordinal % aBase;
662 buf[--idx] = chars[cur];
663 ordinal /= aBase ;
664 } while ( ordinal > 0);
665 result.Append(buf+idx,NUM_BUF_SIZE-idx);
666 return PR_TRUE;
670 static const PRUnichar gCJKIdeographicDigit1[10] =
672 0x96f6, 0x4e00, 0x4e8c, 0x4e09, 0x56db, // 0 - 4
673 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d // 5 - 9
675 static const PRUnichar gCJKIdeographicDigit2[10] =
677 0x96f6, 0x58f9, 0x8cb3, 0x53c3, 0x8086, // 0 - 4
678 0x4f0d, 0x9678, 0x67d2, 0x634c, 0x7396 // 5 - 9
680 static const PRUnichar gCJKIdeographicDigit3[10] =
682 0x96f6, 0x58f9, 0x8d30, 0x53c1, 0x8086, // 0 - 4
683 0x4f0d, 0x9646, 0x67d2, 0x634c, 0x7396 // 5 - 9
685 static const PRUnichar gCJKIdeographicUnit1[4] =
687 0x000, 0x5341, 0x767e, 0x5343
689 static const PRUnichar gCJKIdeographicUnit2[4] =
691 0x000, 0x62FE, 0x4F70, 0x4EDF
693 static const PRUnichar gCJKIdeographic10KUnit1[4] =
695 0x000, 0x842c, 0x5104, 0x5146
697 static const PRUnichar gCJKIdeographic10KUnit2[4] =
699 0x000, 0x4E07, 0x4ebf, 0x5146
701 static const PRUnichar gCJKIdeographic10KUnit3[4] =
703 0x000, 0x4E07, 0x5104, 0x5146
706 static const PRBool CJKIdeographicToText(PRInt32 ordinal, nsString& result,
707 const PRUnichar* digits,
708 const PRUnichar *unit,
709 const PRUnichar* unit10k)
711 // In theory, we need the following if condiction,
712 // However, the limit, 10 ^ 16, is greater than the max of PRUint32
713 // so we don't really need to test it here.
714 // if( ordinal > 9999999999999999)
715 // {
716 // PR_snprintf(cbuf, sizeof(cbuf), "%ld", ordinal);
717 // result.Append(cbuf);
718 // }
719 // else
720 // {
721 if (ordinal < 0) {
722 DecimalToText(ordinal, result);
723 return PR_FALSE;
725 PRUnichar c10kUnit = 0;
726 PRUnichar cUnit = 0;
727 PRUnichar cDigit = 0;
728 PRUint32 ud = 0;
729 PRUnichar buf[NUM_BUF_SIZE];
730 PRInt32 idx = NUM_BUF_SIZE;
731 PRBool bOutputZero = ( 0 == ordinal );
732 do {
733 if(0 == (ud % 4)) {
734 c10kUnit = unit10k[ud/4];
736 PRInt32 cur = ordinal % 10;
737 cDigit = digits[cur];
738 if( 0 == cur)
740 cUnit = 0;
741 if(bOutputZero) {
742 bOutputZero = PR_FALSE;
743 if(0 != cDigit)
744 buf[--idx] = cDigit;
747 else
749 bOutputZero = PR_TRUE;
750 cUnit = unit[ud%4];
752 if(0 != c10kUnit)
753 buf[--idx] = c10kUnit;
754 if(0 != cUnit)
755 buf[--idx] = cUnit;
756 if((0 != cDigit) &&
757 ( (1 != cur) || (1 != (ud%4)) || ( ordinal > 10)) )
758 buf[--idx] = cDigit;
760 c10kUnit = 0;
762 ordinal /= 10;
763 ++ud;
765 } while( ordinal > 0);
766 result.Append(buf+idx,NUM_BUF_SIZE-idx);
767 // }
768 return PR_TRUE;
771 #define HEBREW_GERESH 0x05F3
772 static const PRUnichar gHebrewDigit[22] =
774 // 1 2 3 4 5 6 7 8 9
775 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8,
776 // 10 20 30 40 50 60 70 80 90
777 0x05D9, 0x05DB, 0x05DC, 0x05DE, 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6,
778 // 100 200 300 400
779 0x05E7, 0x05E8, 0x05E9, 0x05EA
782 static PRBool HebrewToText(PRInt32 ordinal, nsString& result)
784 if (ordinal < 1 || ordinal > 999999) {
785 DecimalToText(ordinal, result);
786 return PR_FALSE;
788 PRBool outputSep = PR_FALSE;
789 nsAutoString allText, thousandsGroup;
790 do {
791 thousandsGroup.Truncate();
792 PRInt32 n3 = ordinal % 1000;
793 // Process digit for 100 - 900
794 for(PRInt32 n1 = 400; n1 > 0; )
796 if( n3 >= n1)
798 n3 -= n1;
799 thousandsGroup.Append(gHebrewDigit[(n1/100)-1+18]);
800 } else {
801 n1 -= 100;
802 } // if
803 } // for
805 // Process digit for 10 - 90
806 PRInt32 n2;
807 if( n3 >= 10 )
809 // Special process for 15 and 16
810 if(( 15 == n3 ) || (16 == n3)) {
811 // Special rule for religious reason...
812 // 15 is represented by 9 and 6, not 10 and 5
813 // 16 is represented by 9 and 7, not 10 and 6
814 n2 = 9;
815 thousandsGroup.Append(gHebrewDigit[ n2 - 1]);
816 } else {
817 n2 = n3 - (n3 % 10);
818 thousandsGroup.Append(gHebrewDigit[(n2/10)-1+9]);
819 } // if
820 n3 -= n2;
821 } // if
823 // Process digit for 1 - 9
824 if ( n3 > 0)
825 thousandsGroup.Append(gHebrewDigit[n3-1]);
826 if (outputSep)
827 thousandsGroup.Append((PRUnichar)HEBREW_GERESH);
828 if (allText.IsEmpty())
829 allText = thousandsGroup;
830 else
831 allText = thousandsGroup + allText;
832 ordinal /= 1000;
833 outputSep = PR_TRUE;
834 } while (ordinal >= 1);
836 result.Append(allText);
837 return PR_TRUE;
841 static PRBool ArmenianToText(PRInt32 ordinal, nsString& result)
843 // XXXbz this system goes out to a lot further than 9999... we should fix
844 // that. This algorithm seems broken in general. There's this business of
845 // "7000" being special and then there's the combining accent we're supposed
846 // to be using...
847 if (ordinal < 1 || ordinal > 9999) { // zero or reach the limit of Armenian numbering system
848 DecimalToText(ordinal, result);
849 return PR_FALSE;
852 PRUnichar buf[NUM_BUF_SIZE];
853 PRInt32 idx = NUM_BUF_SIZE;
854 PRInt32 d = 0;
855 do {
856 PRInt32 cur = ordinal % 10;
857 if (cur > 0)
859 PRUnichar u = 0x0530 + (d * 9) + cur;
860 buf[--idx] = u;
862 ++d;
863 ordinal /= 10;
864 } while (ordinal > 0);
865 result.Append(buf + idx, NUM_BUF_SIZE - idx);
866 return PR_TRUE;
870 static const PRUnichar gGeorgianValue [ 37 ] = { // 4 * 9 + 1 = 37
871 // 1 2 3 4 5 6 7 8 9
872 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10F1, 0x10D7,
873 // 10 20 30 40 50 60 70 80 90
874 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10F2, 0x10DD, 0x10DE, 0x10DF,
875 // 100 200 300 400 500 600 700 800 900
876 0x10E0, 0x10E1, 0x10E2, 0x10F3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8,
877 // 1000 2000 3000 4000 5000 6000 7000 8000 9000
878 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10F4, 0x10EF, 0x10F0,
879 // 10000
880 0x10F5
882 static PRBool GeorgianToText(PRInt32 ordinal, nsString& result)
884 if (ordinal < 1 || ordinal > 19999) { // zero or reach the limit of Georgian numbering system
885 DecimalToText(ordinal, result);
886 return PR_FALSE;
889 PRUnichar buf[NUM_BUF_SIZE];
890 PRInt32 idx = NUM_BUF_SIZE;
891 PRInt32 d = 0;
892 do {
893 PRInt32 cur = ordinal % 10;
894 if (cur > 0)
896 PRUnichar u = gGeorgianValue[(d * 9 ) + ( cur - 1)];
897 buf[--idx] = u;
899 ++d;
900 ordinal /= 10;
901 } while (ordinal > 0);
902 result.Append(buf + idx, NUM_BUF_SIZE - idx);
903 return PR_TRUE;
906 // Convert ordinal to Ethiopic numeric representation.
907 // The detail is available at http://www.ethiopic.org/Numerals/
908 // The algorithm used here is based on the pseudo-code put up there by
909 // Daniel Yacob <yacob@geez.org>.
910 // Another reference is Unicode 3.0 standard section 11.1.
911 #define ETHIOPIC_ONE 0x1369
912 #define ETHIOPIC_TEN 0x1372
913 #define ETHIOPIC_HUNDRED 0x137B
914 #define ETHIOPIC_TEN_THOUSAND 0x137C
916 static PRBool EthiopicToText(PRInt32 ordinal, nsString& result)
918 nsAutoString asciiNumberString; // decimal string representation of ordinal
919 DecimalToText(ordinal, asciiNumberString);
920 if (ordinal < 1) {
921 result.Append(asciiNumberString);
922 return PR_FALSE;
924 PRUint8 asciiStringLength = asciiNumberString.Length();
926 // If number length is odd, add a leading "0"
927 // the leading "0" preconditions the string to always have the
928 // leading tens place populated, this avoids a check within the loop.
929 // If we didn't add the leading "0", decrement asciiStringLength so
930 // it will be equivalent to a zero-based index in both cases.
931 if (asciiStringLength & 1) {
932 asciiNumberString.Insert(NS_LITERAL_STRING("0"), 0);
933 } else {
934 asciiStringLength--;
937 // Iterate from the highest digits to lowest
938 // indexFromLeft indexes digits (0 = most significant)
939 // groupIndexFromRight indexes pairs of digits (0 = least significant)
940 for (PRUint8 indexFromLeft = 0, groupIndexFromRight = asciiStringLength >> 1;
941 indexFromLeft <= asciiStringLength;
942 indexFromLeft += 2, groupIndexFromRight--) {
943 PRUint8 tensValue = asciiNumberString.CharAt(indexFromLeft) & 0x0F;
944 PRUint8 unitsValue = asciiNumberString.CharAt(indexFromLeft + 1) & 0x0F;
945 PRUint8 groupValue = tensValue * 10 + unitsValue;
947 PRBool oddGroup = (groupIndexFromRight & 1);
949 // we want to clear ETHIOPIC_ONE when it is superfluous
950 if (ordinal > 1 &&
951 groupValue == 1 && // one without a leading ten
952 (oddGroup || indexFromLeft == 0)) { // preceding (100) or leading the sequence
953 unitsValue = 0;
956 // put it all together...
957 if (tensValue) {
958 // map onto Ethiopic "tens":
959 result.Append((PRUnichar) (tensValue + ETHIOPIC_TEN - 1));
961 if (unitsValue) {
962 //map onto Ethiopic "units":
963 result.Append((PRUnichar) (unitsValue + ETHIOPIC_ONE - 1));
965 // Add a separator for all even groups except the last,
966 // and for odd groups with non-zero value.
967 if (oddGroup) {
968 if (groupValue) {
969 result.Append((PRUnichar) ETHIOPIC_HUNDRED);
971 } else {
972 if (groupIndexFromRight) {
973 result.Append((PRUnichar) ETHIOPIC_TEN_THOUSAND);
977 return PR_TRUE;
981 /* static */ PRBool
982 nsBulletFrame::AppendCounterText(PRInt32 aListStyleType,
983 PRInt32 aOrdinal,
984 nsString& result)
986 PRBool success;
988 switch (aListStyleType) {
989 case NS_STYLE_LIST_STYLE_NONE: // used by counters code only
990 break;
992 case NS_STYLE_LIST_STYLE_DISC: // used by counters code only
993 // XXX We really need to do this the same way we do list bullets.
994 result.Append(PRUnichar(0x2022));
995 break;
997 case NS_STYLE_LIST_STYLE_CIRCLE: // used by counters code only
998 // XXX We really need to do this the same way we do list bullets.
999 result.Append(PRUnichar(0x25E6));
1000 break;
1002 case NS_STYLE_LIST_STYLE_SQUARE: // used by counters code only
1003 // XXX We really need to do this the same way we do list bullets.
1004 result.Append(PRUnichar(0x25FE));
1005 break;
1007 case NS_STYLE_LIST_STYLE_DECIMAL:
1008 case NS_STYLE_LIST_STYLE_OLD_DECIMAL:
1009 default: // CSS2 say "A users agent that does not recognize a numbering system
1010 // should use 'decimal'
1011 success = DecimalToText(aOrdinal, result);
1012 break;
1014 case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO:
1015 success = DecimalLeadingZeroToText(aOrdinal, result);
1016 break;
1018 case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
1019 case NS_STYLE_LIST_STYLE_OLD_LOWER_ROMAN:
1020 success = RomanToText(aOrdinal, result,
1021 gLowerRomanCharsA, gLowerRomanCharsB);
1022 break;
1023 case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
1024 case NS_STYLE_LIST_STYLE_OLD_UPPER_ROMAN:
1025 success = RomanToText(aOrdinal, result,
1026 gUpperRomanCharsA, gUpperRomanCharsB);
1027 break;
1029 case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
1030 case NS_STYLE_LIST_STYLE_OLD_LOWER_ALPHA:
1031 success = CharListToText(aOrdinal, result, gLowerAlphaChars, ALPHA_SIZE);
1032 break;
1034 case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
1035 case NS_STYLE_LIST_STYLE_OLD_UPPER_ALPHA:
1036 success = CharListToText(aOrdinal, result, gUpperAlphaChars, ALPHA_SIZE);
1037 break;
1039 case NS_STYLE_LIST_STYLE_KATAKANA:
1040 success = CharListToText(aOrdinal, result, gKatakanaChars,
1041 KATAKANA_CHARS_SIZE);
1042 break;
1044 case NS_STYLE_LIST_STYLE_HIRAGANA:
1045 success = CharListToText(aOrdinal, result, gHiraganaChars,
1046 HIRAGANA_CHARS_SIZE);
1047 break;
1049 case NS_STYLE_LIST_STYLE_KATAKANA_IROHA:
1050 success = CharListToText(aOrdinal, result, gKatakanaIrohaChars,
1051 KATAKANA_IROHA_CHARS_SIZE);
1052 break;
1054 case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA:
1055 success = CharListToText(aOrdinal, result, gHiraganaIrohaChars,
1056 HIRAGANA_IROHA_CHARS_SIZE);
1057 break;
1059 case NS_STYLE_LIST_STYLE_LOWER_GREEK:
1060 success = CharListToText(aOrdinal, result, gLowerGreekChars ,
1061 LOWER_GREEK_CHARS_SIZE);
1062 break;
1064 case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC:
1065 case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL:
1066 success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1,
1067 gCJKIdeographicUnit1,
1068 gCJKIdeographic10KUnit1);
1069 break;
1071 case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL:
1072 success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit2,
1073 gCJKIdeographicUnit2,
1074 gCJKIdeographic10KUnit1);
1075 break;
1077 case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL:
1078 success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1,
1079 gCJKIdeographicUnit1,
1080 gCJKIdeographic10KUnit2);
1081 break;
1083 case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL:
1084 success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit3,
1085 gCJKIdeographicUnit2,
1086 gCJKIdeographic10KUnit2);
1087 break;
1089 case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL:
1090 success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1,
1091 gCJKIdeographicUnit1,
1092 gCJKIdeographic10KUnit3);
1093 break;
1095 case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL:
1096 success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit2,
1097 gCJKIdeographicUnit2,
1098 gCJKIdeographic10KUnit3);
1099 break;
1101 case NS_STYLE_LIST_STYLE_HEBREW:
1102 success = HebrewToText(aOrdinal, result);
1103 break;
1105 case NS_STYLE_LIST_STYLE_ARMENIAN:
1106 success = ArmenianToText(aOrdinal, result);
1107 break;
1109 case NS_STYLE_LIST_STYLE_GEORGIAN:
1110 success = GeorgianToText(aOrdinal, result);
1111 break;
1113 case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC:
1114 success = OtherDecimalToText(aOrdinal, 0x0660, result);
1115 break;
1117 case NS_STYLE_LIST_STYLE_MOZ_PERSIAN:
1118 case NS_STYLE_LIST_STYLE_MOZ_URDU:
1119 success = OtherDecimalToText(aOrdinal, 0x06f0, result);
1120 break;
1122 case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI:
1123 success = OtherDecimalToText(aOrdinal, 0x0966, result);
1124 break;
1126 case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI:
1127 success = OtherDecimalToText(aOrdinal, 0x0a66, result);
1128 break;
1130 case NS_STYLE_LIST_STYLE_MOZ_GUJARATI:
1131 success = OtherDecimalToText(aOrdinal, 0x0AE6, result);
1132 break;
1134 case NS_STYLE_LIST_STYLE_MOZ_ORIYA:
1135 success = OtherDecimalToText(aOrdinal, 0x0B66, result);
1136 break;
1138 case NS_STYLE_LIST_STYLE_MOZ_KANNADA:
1139 success = OtherDecimalToText(aOrdinal, 0x0CE6, result);
1140 break;
1142 case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM:
1143 success = OtherDecimalToText(aOrdinal, 0x0D66, result);
1144 break;
1146 case NS_STYLE_LIST_STYLE_MOZ_THAI:
1147 success = OtherDecimalToText(aOrdinal, 0x0E50, result);
1148 break;
1150 case NS_STYLE_LIST_STYLE_MOZ_LAO:
1151 success = OtherDecimalToText(aOrdinal, 0x0ED0, result);
1152 break;
1154 case NS_STYLE_LIST_STYLE_MOZ_MYANMAR:
1155 success = OtherDecimalToText(aOrdinal, 0x1040, result);
1156 break;
1158 case NS_STYLE_LIST_STYLE_MOZ_KHMER:
1159 success = OtherDecimalToText(aOrdinal, 0x17E0, result);
1160 break;
1162 case NS_STYLE_LIST_STYLE_MOZ_BENGALI:
1163 success = OtherDecimalToText(aOrdinal, 0x09E6, result);
1164 break;
1166 case NS_STYLE_LIST_STYLE_MOZ_TELUGU:
1167 success = OtherDecimalToText(aOrdinal, 0x0C66, result);
1168 break;
1170 case NS_STYLE_LIST_STYLE_MOZ_TAMIL:
1171 success = TamilToText(aOrdinal, result);
1172 break;
1174 case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM:
1175 success = CharListToText(aOrdinal, result, gCJKHeavenlyStemChars,
1176 CJK_HEAVENLY_STEM_CHARS_SIZE);
1177 break;
1179 case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH:
1180 success = CharListToText(aOrdinal, result, gCJKEarthlyBranchChars,
1181 CJK_EARTHLY_BRANCH_CHARS_SIZE);
1182 break;
1184 case NS_STYLE_LIST_STYLE_MOZ_HANGUL:
1185 success = CharListToText(aOrdinal, result, gHangulChars, HANGUL_CHARS_SIZE);
1186 break;
1188 case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT:
1189 success = CharListToText(aOrdinal, result, gHangulConsonantChars,
1190 HANGUL_CONSONANT_CHARS_SIZE);
1191 break;
1193 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME:
1194 success = CharListToText(aOrdinal, result, gEthiopicHalehameChars,
1195 ETHIOPIC_HALEHAME_CHARS_SIZE);
1196 break;
1198 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC:
1199 success = EthiopicToText(aOrdinal, result);
1200 break;
1202 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM:
1203 success = CharListToText(aOrdinal, result, gEthiopicHalehameAmChars,
1204 ETHIOPIC_HALEHAME_AM_CHARS_SIZE);
1205 break;
1207 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER:
1208 success = CharListToText(aOrdinal, result, gEthiopicHalehameTiErChars,
1209 ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE);
1210 break;
1212 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET:
1213 success = CharListToText(aOrdinal, result, gEthiopicHalehameTiEtChars,
1214 ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE);
1215 break;
1217 return success;
1220 PRBool
1221 nsBulletFrame::GetListItemText(const nsStyleList& aListStyle,
1222 nsString& result)
1224 const nsStyleVisibility* vis = GetStyleVisibility();
1226 NS_ASSERTION(aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_NONE &&
1227 aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_DISC &&
1228 aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_CIRCLE &&
1229 aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_SQUARE,
1230 "we should be using specialized code for these types");
1231 PRBool success =
1232 AppendCounterText(aListStyle.mListStyleType, mOrdinal, result);
1233 if (success && aListStyle.mListStyleType == NS_STYLE_LIST_STYLE_HEBREW)
1234 mTextIsRTL = PR_TRUE;
1236 // XXX For some of these systems, "." is wrong! This should really be
1237 // pushed down into the individual cases!
1238 nsString suffix = NS_LITERAL_STRING(".");
1240 // We're not going to do proper Bidi reordering on the list item marker, but
1241 // just display the whole thing as RTL or LTR, so we fake reordering by
1242 // appending the suffix to the end of the list item marker if the
1243 // directionality of the characters is the same as the style direction or
1244 // prepending it to the beginning if they are different.
1245 result = (mTextIsRTL == (vis->mDirection == NS_STYLE_DIRECTION_RTL)) ?
1246 result + suffix : suffix + result;
1247 return success;
1250 #define MIN_BULLET_SIZE 1
1253 void
1254 nsBulletFrame::GetDesiredSize(nsPresContext* aCX,
1255 nsIRenderingContext *aRenderingContext,
1256 nsHTMLReflowMetrics& aMetrics)
1258 // Reset our padding. If we need it, we'll set it below.
1259 mPadding.SizeTo(0, 0, 0, 0);
1261 const nsStyleList* myList = GetStyleList();
1262 nscoord ascent;
1264 if (myList->mListStyleImage && mImageRequest) {
1265 PRUint32 status;
1266 mImageRequest->GetImageStatus(&status);
1267 if (status & imgIRequest::STATUS_SIZE_AVAILABLE &&
1268 !(status & imgIRequest::STATUS_ERROR)) {
1269 // auto size the image
1270 mComputedSize.width = mIntrinsicSize.width;
1271 mComputedSize.height = mIntrinsicSize.height;
1273 aMetrics.width = mComputedSize.width;
1274 aMetrics.ascent = aMetrics.height = mComputedSize.height;
1276 return;
1280 // If we're getting our desired size and don't have an image, reset
1281 // mIntrinsicSize to (0,0). Otherwise, if we used to have an image, it
1282 // changed, and the new one is coming in, but we're reflowing before it's
1283 // fully there, we'll end up with mIntrinsicSize not matching our size, but
1284 // won't trigger a reflow in OnStartContainer (because mIntrinsicSize will
1285 // match the image size).
1286 mIntrinsicSize.SizeTo(0, 0);
1288 nsCOMPtr<nsIFontMetrics> fm;
1289 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
1290 nscoord bulletSize;
1292 nsAutoString text;
1293 switch (myList->mListStyleType) {
1294 case NS_STYLE_LIST_STYLE_NONE:
1295 aMetrics.width = 0;
1296 aMetrics.ascent = aMetrics.height = 0;
1297 break;
1299 case NS_STYLE_LIST_STYLE_DISC:
1300 case NS_STYLE_LIST_STYLE_CIRCLE:
1301 case NS_STYLE_LIST_STYLE_SQUARE:
1302 fm->GetMaxAscent(ascent);
1303 bulletSize = PR_MAX(nsPresContext::CSSPixelsToAppUnits(MIN_BULLET_SIZE),
1304 NSToCoordRound(0.8f * (float(ascent) / 2.0f)));
1305 mPadding.bottom = NSToCoordRound(float(ascent) / 8.0f);
1306 aMetrics.width = mPadding.right + bulletSize;
1307 aMetrics.ascent = aMetrics.height = mPadding.bottom + bulletSize;
1308 break;
1310 default:
1311 case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO:
1312 case NS_STYLE_LIST_STYLE_DECIMAL:
1313 case NS_STYLE_LIST_STYLE_OLD_DECIMAL:
1314 case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
1315 case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
1316 case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
1317 case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
1318 case NS_STYLE_LIST_STYLE_OLD_LOWER_ROMAN:
1319 case NS_STYLE_LIST_STYLE_OLD_UPPER_ROMAN:
1320 case NS_STYLE_LIST_STYLE_OLD_LOWER_ALPHA:
1321 case NS_STYLE_LIST_STYLE_OLD_UPPER_ALPHA:
1322 case NS_STYLE_LIST_STYLE_KATAKANA:
1323 case NS_STYLE_LIST_STYLE_HIRAGANA:
1324 case NS_STYLE_LIST_STYLE_KATAKANA_IROHA:
1325 case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA:
1326 case NS_STYLE_LIST_STYLE_LOWER_GREEK:
1327 case NS_STYLE_LIST_STYLE_HEBREW:
1328 case NS_STYLE_LIST_STYLE_ARMENIAN:
1329 case NS_STYLE_LIST_STYLE_GEORGIAN:
1330 case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC:
1331 case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL:
1332 case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL:
1333 case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL:
1334 case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL:
1335 case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL:
1336 case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL:
1337 case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM:
1338 case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH:
1339 case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC:
1340 case NS_STYLE_LIST_STYLE_MOZ_PERSIAN:
1341 case NS_STYLE_LIST_STYLE_MOZ_URDU:
1342 case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI:
1343 case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI:
1344 case NS_STYLE_LIST_STYLE_MOZ_GUJARATI:
1345 case NS_STYLE_LIST_STYLE_MOZ_ORIYA:
1346 case NS_STYLE_LIST_STYLE_MOZ_KANNADA:
1347 case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM:
1348 case NS_STYLE_LIST_STYLE_MOZ_BENGALI:
1349 case NS_STYLE_LIST_STYLE_MOZ_TAMIL:
1350 case NS_STYLE_LIST_STYLE_MOZ_TELUGU:
1351 case NS_STYLE_LIST_STYLE_MOZ_THAI:
1352 case NS_STYLE_LIST_STYLE_MOZ_LAO:
1353 case NS_STYLE_LIST_STYLE_MOZ_MYANMAR:
1354 case NS_STYLE_LIST_STYLE_MOZ_KHMER:
1355 case NS_STYLE_LIST_STYLE_MOZ_HANGUL:
1356 case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT:
1357 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME:
1358 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC:
1359 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM:
1360 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER:
1361 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET:
1362 GetListItemText(*myList, text);
1363 fm->GetHeight(aMetrics.height);
1364 aRenderingContext->SetFont(fm);
1365 aMetrics.width = nsLayoutUtils::GetStringWidth(this, aRenderingContext, text.get(), text.Length());
1366 aMetrics.width += mPadding.right;
1367 fm->GetMaxAscent(aMetrics.ascent);
1368 break;
1372 NS_IMETHODIMP
1373 nsBulletFrame::Reflow(nsPresContext* aPresContext,
1374 nsHTMLReflowMetrics& aMetrics,
1375 const nsHTMLReflowState& aReflowState,
1376 nsReflowStatus& aStatus)
1378 DO_GLOBAL_REFLOW_COUNT("nsBulletFrame");
1379 DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
1381 // Get the base size
1382 GetDesiredSize(aPresContext, aReflowState.rendContext, aMetrics);
1384 // Add in the border and padding; split the top/bottom between the
1385 // ascent and descent to make things look nice
1386 const nsMargin& borderPadding = aReflowState.mComputedBorderPadding;
1387 aMetrics.width += borderPadding.left + borderPadding.right;
1388 aMetrics.height += borderPadding.top + borderPadding.bottom;
1389 aMetrics.ascent += borderPadding.top;
1391 // XXX this is a bit of a hack, we're assuming that no glyphs used for bullets
1392 // overflow their font-boxes. It'll do for now; to fix it for real, we really
1393 // should rewrite all the text-handling code here to use gfxTextRun (bug
1394 // 397294).
1395 aMetrics.mOverflowArea.SetRect(0, 0, aMetrics.width, aMetrics.height);
1397 aStatus = NS_FRAME_COMPLETE;
1398 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
1399 return NS_OK;
1402 /* virtual */ nscoord
1403 nsBulletFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
1405 nsHTMLReflowMetrics metrics;
1406 DISPLAY_MIN_WIDTH(this, metrics.width);
1407 GetDesiredSize(PresContext(), aRenderingContext, metrics);
1408 return metrics.width;
1411 /* virtual */ nscoord
1412 nsBulletFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
1414 nsHTMLReflowMetrics metrics;
1415 DISPLAY_PREF_WIDTH(this, metrics.width);
1416 GetDesiredSize(PresContext(), aRenderingContext, metrics);
1417 return metrics.width;
1421 NS_IMETHODIMP nsBulletFrame::OnStartContainer(imgIRequest *aRequest,
1422 imgIContainer *aImage)
1424 if (!aImage) return NS_ERROR_INVALID_ARG;
1425 if (!aRequest) return NS_ERROR_INVALID_ARG;
1427 PRUint32 status;
1428 aRequest->GetImageStatus(&status);
1429 if (status & imgIRequest::STATUS_ERROR) {
1430 return NS_OK;
1433 nscoord w, h;
1434 aImage->GetWidth(&w);
1435 aImage->GetHeight(&h);
1437 nsPresContext* presContext = PresContext();
1439 nsSize newsize(nsPresContext::CSSPixelsToAppUnits(w),
1440 nsPresContext::CSSPixelsToAppUnits(h));
1442 if (mIntrinsicSize != newsize) {
1443 mIntrinsicSize = newsize;
1445 // Now that the size is available (or an error occurred), trigger
1446 // a reflow of the bullet frame.
1447 nsIPresShell *shell = presContext->GetPresShell();
1448 if (shell) {
1449 shell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
1450 NS_FRAME_IS_DIRTY);
1454 // Handle animations
1455 aImage->SetAnimationMode(presContext->ImageAnimationMode());
1456 // Ensure the animation (if any) is started.
1457 aImage->StartAnimation();
1460 return NS_OK;
1463 NS_IMETHODIMP nsBulletFrame::OnDataAvailable(imgIRequest *aRequest,
1464 gfxIImageFrame *aFrame,
1465 const nsRect *aRect)
1467 // The image has changed.
1468 // Invalidate the entire content area. Maybe it's not optimal but it's simple and
1469 // always correct, and I'll be a stunned mullet if it ever matters for performance
1470 Invalidate(nsRect(0, 0, mRect.width, mRect.height), PR_FALSE);
1472 return NS_OK;
1475 NS_IMETHODIMP nsBulletFrame::OnStopDecode(imgIRequest *aRequest,
1476 nsresult aStatus,
1477 const PRUnichar *aStatusArg)
1479 // XXX should the bulletframe do anything if the image failed to load?
1480 // it didn't in the old code...
1482 #if 0
1483 if (NS_FAILED(aStatus)) {
1484 // We failed to load the image. Notify the pres shell
1485 if (NS_FAILED(aStatus) && (mImageRequest == aRequest || !mImageRequest)) {
1486 imageFailed = PR_TRUE;
1489 #endif
1491 return NS_OK;
1494 NS_IMETHODIMP nsBulletFrame::FrameChanged(imgIContainer *aContainer,
1495 gfxIImageFrame *aNewFrame,
1496 nsRect *aDirtyRect)
1498 // Invalidate the entire content area. Maybe it's not optimal but it's simple and
1499 // always correct.
1500 Invalidate(nsRect(0, 0, mRect.width, mRect.height), PR_FALSE);
1502 return NS_OK;
1505 void
1506 nsBulletFrame::GetLoadGroup(nsPresContext *aPresContext, nsILoadGroup **aLoadGroup)
1508 if (!aPresContext)
1509 return;
1511 NS_PRECONDITION(nsnull != aLoadGroup, "null OUT parameter pointer");
1513 nsIPresShell *shell = aPresContext->GetPresShell();
1515 if (!shell)
1516 return;
1518 nsIDocument *doc = shell->GetDocument();
1519 if (!doc)
1520 return;
1522 *aLoadGroup = doc->GetDocumentLoadGroup().get(); // already_AddRefed
1532 NS_IMPL_ISUPPORTS2(nsBulletListener, imgIDecoderObserver, imgIContainerObserver)
1534 nsBulletListener::nsBulletListener() :
1535 mFrame(nsnull)
1539 nsBulletListener::~nsBulletListener()
1543 NS_IMETHODIMP nsBulletListener::OnStartContainer(imgIRequest *aRequest,
1544 imgIContainer *aImage)
1546 if (!mFrame)
1547 return NS_ERROR_FAILURE;
1549 return mFrame->OnStartContainer(aRequest, aImage);
1552 NS_IMETHODIMP nsBulletListener::OnDataAvailable(imgIRequest *aRequest,
1553 gfxIImageFrame *aFrame,
1554 const nsRect *aRect)
1556 if (!mFrame)
1557 return NS_ERROR_FAILURE;
1559 return mFrame->OnDataAvailable(aRequest, aFrame, aRect);
1562 NS_IMETHODIMP nsBulletListener::OnStopDecode(imgIRequest *aRequest,
1563 nsresult status,
1564 const PRUnichar *statusArg)
1566 if (!mFrame)
1567 return NS_ERROR_FAILURE;
1569 return mFrame->OnStopDecode(aRequest, status, statusArg);
1572 NS_IMETHODIMP nsBulletListener::FrameChanged(imgIContainer *aContainer,
1573 gfxIImageFrame *newframe,
1574 nsRect * dirtyRect)
1576 if (!mFrame)
1577 return NS_ERROR_FAILURE;
1579 return mFrame->FrameChanged(aContainer, newframe, dirtyRect);