Use 'Is' in noun-phrase-named predicate (518103 followup, r=jorendorff/Waldo).
[mozilla-central.git] / layout / generic / nsBulletFrame.cpp
blobfe67ded66c8ddc3b04b7b362c9e4f1034d91836c
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, PRBool aCurrentFrame,
75 const nsIntRect *aRect);
76 NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult status,
77 const PRUnichar *statusArg);
78 // imgIContainerObserver (override nsStubImageDecoderObserver)
79 NS_IMETHOD FrameChanged(imgIContainer *aContainer, nsIntRect *dirtyRect);
81 void SetFrame(nsBulletFrame *frame) { mFrame = frame; }
83 private:
84 nsBulletFrame *mFrame;
87 NS_IMPL_FRAMEARENA_HELPERS(nsBulletFrame)
89 nsBulletFrame::~nsBulletFrame()
93 void
94 nsBulletFrame::Destroy()
96 // Stop image loading first
97 if (mImageRequest) {
98 mImageRequest->CancelAndForgetObserver(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 /* virtual */ void
136 nsBulletFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
138 nsFrame::DidSetStyleContext(aOldStyleContext);
140 imgIRequest *newRequest = GetStyleList()->mListStyleImage;
142 if (newRequest) {
144 if (!mListener) {
145 nsBulletListener *listener;
146 NS_NEWXPCOM(listener, nsBulletListener);
147 NS_ADDREF(listener);
148 listener->SetFrame(this);
149 listener->QueryInterface(NS_GET_IID(imgIDecoderObserver), getter_AddRefs(mListener));
150 NS_ASSERTION(mListener, "queryinterface for the listener failed");
151 NS_RELEASE(listener);
154 PRBool needNewRequest = PR_TRUE;
156 if (mImageRequest) {
157 // Reload the image, maybe...
158 nsCOMPtr<nsIURI> oldURI;
159 mImageRequest->GetURI(getter_AddRefs(oldURI));
160 nsCOMPtr<nsIURI> newURI;
161 newRequest->GetURI(getter_AddRefs(newURI));
162 if (oldURI && newURI) {
163 PRBool same;
164 newURI->Equals(oldURI, &same);
165 if (same) {
166 needNewRequest = PR_FALSE;
167 } else {
168 mImageRequest->Cancel(NS_ERROR_FAILURE);
169 mImageRequest = nsnull;
174 if (needNewRequest) {
175 newRequest->Clone(mListener, getter_AddRefs(mImageRequest));
177 } else {
178 // No image request on the new style context
179 if (mImageRequest) {
180 mImageRequest->Cancel(NS_ERROR_FAILURE);
181 mImageRequest = nsnull;
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::DrawSingleImage(&aRenderingContext,
243 imageCon, nsLayoutUtils::GetGraphicsFilterForFrame(this),
244 dest + aPt, aDirtyRect, imgIContainer::FLAG_NONE);
245 return;
250 const nsStyleColor* myColor = GetStyleColor();
252 nsCOMPtr<nsIFontMetrics> fm;
253 aRenderingContext.SetColor(myColor->mColor);
255 mTextIsRTL = PR_FALSE;
257 nsAutoString text;
258 switch (listStyleType) {
259 case NS_STYLE_LIST_STYLE_NONE:
260 break;
262 default:
263 case NS_STYLE_LIST_STYLE_DISC:
264 aRenderingContext.FillEllipse(mPadding.left + aPt.x, mPadding.top + aPt.y,
265 mRect.width - (mPadding.left + mPadding.right),
266 mRect.height - (mPadding.top + mPadding.bottom));
267 break;
269 case NS_STYLE_LIST_STYLE_CIRCLE:
270 aRenderingContext.DrawEllipse(mPadding.left + aPt.x, mPadding.top + aPt.y,
271 mRect.width - (mPadding.left + mPadding.right),
272 mRect.height - (mPadding.top + mPadding.bottom));
273 break;
275 case NS_STYLE_LIST_STYLE_SQUARE:
276 aRenderingContext.FillRect(mPadding.left + aPt.x, mPadding.top + aPt.y,
277 mRect.width - (mPadding.left + mPadding.right),
278 mRect.height - (mPadding.top + mPadding.bottom));
279 break;
281 case NS_STYLE_LIST_STYLE_DECIMAL:
282 case NS_STYLE_LIST_STYLE_OLD_DECIMAL:
283 case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO:
284 case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
285 case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
286 case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
287 case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
288 case NS_STYLE_LIST_STYLE_OLD_LOWER_ROMAN:
289 case NS_STYLE_LIST_STYLE_OLD_UPPER_ROMAN:
290 case NS_STYLE_LIST_STYLE_OLD_LOWER_ALPHA:
291 case NS_STYLE_LIST_STYLE_OLD_UPPER_ALPHA:
292 case NS_STYLE_LIST_STYLE_LOWER_GREEK:
293 case NS_STYLE_LIST_STYLE_HEBREW:
294 case NS_STYLE_LIST_STYLE_ARMENIAN:
295 case NS_STYLE_LIST_STYLE_GEORGIAN:
296 case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC:
297 case NS_STYLE_LIST_STYLE_HIRAGANA:
298 case NS_STYLE_LIST_STYLE_KATAKANA:
299 case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA:
300 case NS_STYLE_LIST_STYLE_KATAKANA_IROHA:
301 case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL:
302 case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL:
303 case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL:
304 case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL:
305 case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL:
306 case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL:
307 case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM:
308 case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH:
309 case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC:
310 case NS_STYLE_LIST_STYLE_MOZ_PERSIAN:
311 case NS_STYLE_LIST_STYLE_MOZ_URDU:
312 case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI:
313 case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI:
314 case NS_STYLE_LIST_STYLE_MOZ_GUJARATI:
315 case NS_STYLE_LIST_STYLE_MOZ_ORIYA:
316 case NS_STYLE_LIST_STYLE_MOZ_KANNADA:
317 case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM:
318 case NS_STYLE_LIST_STYLE_MOZ_BENGALI:
319 case NS_STYLE_LIST_STYLE_MOZ_TAMIL:
320 case NS_STYLE_LIST_STYLE_MOZ_TELUGU:
321 case NS_STYLE_LIST_STYLE_MOZ_THAI:
322 case NS_STYLE_LIST_STYLE_MOZ_LAO:
323 case NS_STYLE_LIST_STYLE_MOZ_MYANMAR:
324 case NS_STYLE_LIST_STYLE_MOZ_KHMER:
325 case NS_STYLE_LIST_STYLE_MOZ_HANGUL:
326 case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT:
327 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME:
328 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC:
329 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM:
330 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER:
331 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET:
332 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
333 GetListItemText(*myList, text);
334 aRenderingContext.SetFont(fm);
335 nscoord ascent;
336 fm->GetMaxAscent(ascent);
337 aRenderingContext.SetTextRunRTL(mTextIsRTL);
338 aRenderingContext.DrawString(text, mPadding.left + aPt.x,
339 mPadding.top + aPt.y + ascent);
340 break;
344 PRInt32
345 nsBulletFrame::SetListItemOrdinal(PRInt32 aNextOrdinal,
346 PRBool* aChanged)
348 // Assume that the ordinal comes from the caller
349 PRInt32 oldOrdinal = mOrdinal;
350 mOrdinal = aNextOrdinal;
352 // Try to get value directly from the list-item, if it specifies a
353 // value attribute. Note: we do this with our parent's content
354 // because our parent is the list-item.
355 nsIContent* parentContent = mParent->GetContent();
356 if (parentContent) {
357 nsGenericHTMLElement *hc =
358 nsGenericHTMLElement::FromContent(parentContent);
359 if (hc) {
360 const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::value);
361 if (attr && attr->Type() == nsAttrValue::eInteger) {
362 // Use ordinal specified by the value attribute
363 mOrdinal = attr->GetIntegerValue();
368 *aChanged = oldOrdinal != mOrdinal;
370 return mOrdinal + 1;
374 // XXX change roman/alpha to use unsigned math so that maxint and
375 // maxnegint will work
378 * For all functions below, a return value of PR_TRUE means that we
379 * could represent mOrder in the desired numbering system. PR_FALSE
380 * means we had to fall back to decimal
382 static PRBool DecimalToText(PRInt32 ordinal, nsString& result)
384 char cbuf[40];
385 PR_snprintf(cbuf, sizeof(cbuf), "%ld", ordinal);
386 result.AppendASCII(cbuf);
387 return PR_TRUE;
389 static PRBool DecimalLeadingZeroToText(PRInt32 ordinal, nsString& result)
391 char cbuf[40];
392 PR_snprintf(cbuf, sizeof(cbuf), "%02ld", ordinal);
393 result.AppendASCII(cbuf);
394 return PR_TRUE;
396 static PRBool OtherDecimalToText(PRInt32 ordinal, PRUnichar zeroChar, nsString& result)
398 PRUnichar diff = zeroChar - PRUnichar('0');
399 DecimalToText(ordinal, result);
400 PRUnichar* p = result.BeginWriting();
401 if (ordinal < 0) {
402 // skip the leading '-'
403 ++p;
405 for(; nsnull != *p ; p++)
406 *p += diff;
407 return PR_TRUE;
409 static PRBool TamilToText(PRInt32 ordinal, nsString& result)
411 PRUnichar diff = 0x0BE6 - PRUnichar('0');
412 DecimalToText(ordinal, result);
413 if (ordinal < 1 || ordinal > 9999) {
414 // Can't do those in this system.
415 return PR_FALSE;
417 PRUnichar* p = result.BeginWriting();
418 for(; nsnull != *p ; p++)
419 if(*p != PRUnichar('0'))
420 *p += diff;
421 return PR_TRUE;
425 static const char gLowerRomanCharsA[] = "ixcm";
426 static const char gUpperRomanCharsA[] = "IXCM";
427 static const char gLowerRomanCharsB[] = "vld";
428 static const char gUpperRomanCharsB[] = "VLD";
430 static PRBool RomanToText(PRInt32 ordinal, nsString& result, const char* achars, const char* bchars)
432 if (ordinal < 1 || ordinal > 3999) {
433 DecimalToText(ordinal, result);
434 return PR_FALSE;
436 nsAutoString addOn, decStr;
437 decStr.AppendInt(ordinal, 10);
438 PRIntn len = decStr.Length();
439 const PRUnichar* dp = decStr.get();
440 const PRUnichar* end = dp + len;
441 PRIntn romanPos = len;
442 PRIntn n;
444 for (; dp < end; dp++) {
445 romanPos--;
446 addOn.SetLength(0);
447 switch(*dp) {
448 case '3': addOn.Append(PRUnichar(achars[romanPos]));
449 case '2': addOn.Append(PRUnichar(achars[romanPos]));
450 case '1': addOn.Append(PRUnichar(achars[romanPos]));
451 break;
452 case '4':
453 addOn.Append(PRUnichar(achars[romanPos]));
454 // FALLTHROUGH
455 case '5': case '6':
456 case '7': case '8':
457 addOn.Append(PRUnichar(bchars[romanPos]));
458 for(n=0;'5'+n<*dp;n++) {
459 addOn.Append(PRUnichar(achars[romanPos]));
461 break;
462 case '9':
463 addOn.Append(PRUnichar(achars[romanPos]));
464 addOn.Append(PRUnichar(achars[romanPos+1]));
465 break;
466 default:
467 break;
469 result.Append(addOn);
471 return PR_TRUE;
474 #define ALPHA_SIZE 26
475 static const PRUnichar gLowerAlphaChars[ALPHA_SIZE] =
477 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, // A B C D E
478 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, // F G H I J
479 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, // K L M N O
480 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, // P Q R S T
481 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, // U V W X Y
482 0x007A // Z
485 static const PRUnichar gUpperAlphaChars[ALPHA_SIZE] =
487 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, // A B C D E
488 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, // F G H I J
489 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, // K L M N O
490 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, // P Q R S T
491 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, // U V W X Y
492 0x005A // Z
496 #define KATAKANA_CHARS_SIZE 48
497 // Page 94 Writing Systems of The World
498 // after modification by momoi
499 static const PRUnichar gKatakanaChars[KATAKANA_CHARS_SIZE] =
501 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, // a i u e o
502 0x30AB, 0x30AD, 0x30AF, 0x30B1, 0x30B3, // ka ki ku ke ko
503 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD, // sa shi su se so
504 0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, // ta chi tsu te to
505 0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, // na ni nu ne no
506 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, // ha hi hu he ho
507 0x30DE, 0x30DF, 0x30E0, 0x30E1, 0x30E2, // ma mi mu me mo
508 0x30E4, 0x30E6, 0x30E8, // ya yu yo
509 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, // ra ri ru re ro
510 0x30EF, 0x30F0, 0x30F1, 0x30F2, // wa (w)i (w)e (w)o
511 0x30F3 // n
514 #define HIRAGANA_CHARS_SIZE 48
515 static const PRUnichar gHiraganaChars[HIRAGANA_CHARS_SIZE] =
517 0x3042, 0x3044, 0x3046, 0x3048, 0x304A, // a i u e o
518 0x304B, 0x304D, 0x304F, 0x3051, 0x3053, // ka ki ku ke ko
519 0x3055, 0x3057, 0x3059, 0x305B, 0x305D, // sa shi su se so
520 0x305F, 0x3061, 0x3064, 0x3066, 0x3068, // ta chi tsu te to
521 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, // na ni nu ne no
522 0x306F, 0x3072, 0x3075, 0x3078, 0x307B, // ha hi hu he ho
523 0x307E, 0x307F, 0x3080, 0x3081, 0x3082, // ma mi mu me mo
524 0x3084, 0x3086, 0x3088, // ya yu yo
525 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, // ra ri ru re ro
526 0x308F, 0x3090, 0x3091, 0x3092, // wa (w)i (w)e (w)o
527 0x3093 // n
531 #define HIRAGANA_IROHA_CHARS_SIZE 47
532 // Page 94 Writing Systems of The World
533 static const PRUnichar gHiraganaIrohaChars[HIRAGANA_IROHA_CHARS_SIZE] =
535 0x3044, 0x308D, 0x306F, 0x306B, 0x307B, // i ro ha ni ho
536 0x3078, 0x3068, 0x3061, 0x308A, 0x306C, // he to chi ri nu
537 0x308B, 0x3092, 0x308F, 0x304B, 0x3088, // ru (w)o wa ka yo
538 0x305F, 0x308C, 0x305D, 0x3064, 0x306D, // ta re so tsu ne
539 0x306A, 0x3089, 0x3080, 0x3046, 0x3090, // na ra mu u (w)i
540 0x306E, 0x304A, 0x304F, 0x3084, 0x307E, // no o ku ya ma
541 0x3051, 0x3075, 0x3053, 0x3048, 0x3066, // ke hu ko e te
542 0x3042, 0x3055, 0x304D, 0x3086, 0x3081, // a sa ki yu me
543 0x307F, 0x3057, 0x3091, 0x3072, 0x3082, // mi shi (w)e hi mo
544 0x305B, 0x3059 // se su
547 #define KATAKANA_IROHA_CHARS_SIZE 47
548 static const PRUnichar gKatakanaIrohaChars[KATAKANA_IROHA_CHARS_SIZE] =
550 0x30A4, 0x30ED, 0x30CF, 0x30CB, 0x30DB, // i ro ha ni ho
551 0x30D8, 0x30C8, 0x30C1, 0x30EA, 0x30CC, // he to chi ri nu
552 0x30EB, 0x30F2, 0x30EF, 0x30AB, 0x30E8, // ru (w)o wa ka yo
553 0x30BF, 0x30EC, 0x30BD, 0x30C4, 0x30CD, // ta re so tsu ne
554 0x30CA, 0x30E9, 0x30E0, 0x30A6, 0x30F0, // na ra mu u (w)i
555 0x30CE, 0x30AA, 0x30AF, 0x30E4, 0x30DE, // no o ku ya ma
556 0x30B1, 0x30D5, 0x30B3, 0x30A8, 0x30C6, // ke hu ko e te
557 0x30A2, 0x30B5, 0x30AD, 0x30E6, 0x30E1, // a sa ki yu me
558 0x30DF, 0x30B7, 0x30F1, 0x30D2, 0x30E2, // mi shi (w)e hi mo
559 0x30BB, 0x30B9 // se su
562 #define LOWER_GREEK_CHARS_SIZE 24
563 // Note: 0x03C2 GREEK FINAL SIGMA is not used in here....
564 static const PRUnichar gLowerGreekChars[LOWER_GREEK_CHARS_SIZE] =
566 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, // alpha beta gamma delta epsilon
567 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, // zeta eta theta iota kappa
568 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, // lamda mu nu xi omicron
569 0x03C0, 0x03C1, 0x03C3, 0x03C4, 0x03C5, // pi rho sigma tau upsilon
570 0x03C6, 0x03C7, 0x03C8, 0x03C9 // phi chi psi omega
573 #define CJK_HEAVENLY_STEM_CHARS_SIZE 10
574 static const PRUnichar gCJKHeavenlyStemChars[CJK_HEAVENLY_STEM_CHARS_SIZE] =
576 0x7532, 0x4e59, 0x4e19, 0x4e01, 0x620a,
577 0x5df1, 0x5e9a, 0x8f9b, 0x58ec, 0x7678
579 #define CJK_EARTHLY_BRANCH_CHARS_SIZE 12
580 static const PRUnichar gCJKEarthlyBranchChars[CJK_EARTHLY_BRANCH_CHARS_SIZE] =
582 0x5b50, 0x4e11, 0x5bc5, 0x536f, 0x8fb0, 0x5df3,
583 0x5348, 0x672a, 0x7533, 0x9149, 0x620c, 0x4ea5
585 #define HANGUL_CHARS_SIZE 14
586 static const PRUnichar gHangulChars[HANGUL_CHARS_SIZE] =
588 0xac00, 0xb098, 0xb2e4, 0xb77c, 0xb9c8, 0xbc14,
589 0xc0ac, 0xc544, 0xc790, 0xcc28, 0xce74, 0xd0c0,
590 0xd30c, 0xd558
592 #define HANGUL_CONSONANT_CHARS_SIZE 14
593 static const PRUnichar gHangulConsonantChars[HANGUL_CONSONANT_CHARS_SIZE] =
595 0x3131, 0x3134, 0x3137, 0x3139, 0x3141, 0x3142,
596 0x3145, 0x3147, 0x3148, 0x314a, 0x314b, 0x314c,
597 0x314d, 0x314e
600 // Ge'ez set of Ethiopic ordered list. There are other locale-dependent sets.
601 // For the time being, let's implement two Ge'ez sets only
602 // per Momoi san's suggestion in bug 102252.
603 // For details, refer to http://www.ethiopic.org/Collation/OrderedLists.html.
604 #define ETHIOPIC_HALEHAME_CHARS_SIZE 26
605 static const PRUnichar gEthiopicHalehameChars[ETHIOPIC_HALEHAME_CHARS_SIZE] =
607 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228,
608 0x1230, 0x1240, 0x1260, 0x1270, 0x1280, 0x1290,
609 0x12a0, 0x12a8, 0x12c8, 0x12d0, 0x12d8, 0x12e8,
610 0x12f0, 0x1308, 0x1320, 0x1330, 0x1338, 0x1340,
611 0x1348, 0x1350
613 #define ETHIOPIC_HALEHAME_AM_CHARS_SIZE 33
614 static const PRUnichar gEthiopicHalehameAmChars[ETHIOPIC_HALEHAME_AM_CHARS_SIZE] =
616 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228,
617 0x1230, 0x1238, 0x1240, 0x1260, 0x1270, 0x1278,
618 0x1280, 0x1290, 0x1298, 0x12a0, 0x12a8, 0x12b8,
619 0x12c8, 0x12d0, 0x12d8, 0x12e0, 0x12e8, 0x12f0,
620 0x1300, 0x1308, 0x1320, 0x1328, 0x1330, 0x1338,
621 0x1340, 0x1348, 0x1350
623 #define ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE 31
624 static const PRUnichar gEthiopicHalehameTiErChars[ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE] =
626 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230,
627 0x1238, 0x1240, 0x1250, 0x1260, 0x1270, 0x1278,
628 0x1290, 0x1298, 0x12a0, 0x12a8, 0x12b8, 0x12c8,
629 0x12d0, 0x12d8, 0x12e0, 0x12e8, 0x12f0, 0x1300,
630 0x1308, 0x1320, 0x1328, 0x1330, 0x1338, 0x1348,
631 0x1350
633 #define ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE 34
634 static const PRUnichar gEthiopicHalehameTiEtChars[ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE] =
636 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228,
637 0x1230, 0x1238, 0x1240, 0x1250, 0x1260, 0x1270,
638 0x1278, 0x1280, 0x1290, 0x1298, 0x12a0, 0x12a8,
639 0x12b8, 0x12c8, 0x12d0, 0x12d8, 0x12e0, 0x12e8,
640 0x12f0, 0x1300, 0x1308, 0x1320, 0x1328, 0x1330,
641 0x1338, 0x1340, 0x1348, 0x1350
645 // We know cjk-ideographic need 31 characters to display 99,999,999,999,999,999
646 // georgian needs 6 at most
647 // armenian needs 12 at most
648 // hebrew may need more...
650 #define NUM_BUF_SIZE 34
652 static PRBool CharListToText(PRInt32 ordinal, nsString& result, const PRUnichar* chars, PRInt32 aBase)
654 PRUnichar buf[NUM_BUF_SIZE];
655 PRInt32 idx = NUM_BUF_SIZE;
656 if (ordinal < 1) {
657 DecimalToText(ordinal, result);
658 return PR_FALSE;
660 do {
661 ordinal--; // a == 0
662 PRInt32 cur = ordinal % aBase;
663 buf[--idx] = chars[cur];
664 ordinal /= aBase ;
665 } while ( ordinal > 0);
666 result.Append(buf+idx,NUM_BUF_SIZE-idx);
667 return PR_TRUE;
671 static const PRUnichar gCJKIdeographicDigit1[10] =
673 0x96f6, 0x4e00, 0x4e8c, 0x4e09, 0x56db, // 0 - 4
674 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d // 5 - 9
676 static const PRUnichar gCJKIdeographicDigit2[10] =
678 0x96f6, 0x58f9, 0x8cb3, 0x53c3, 0x8086, // 0 - 4
679 0x4f0d, 0x9678, 0x67d2, 0x634c, 0x7396 // 5 - 9
681 static const PRUnichar gCJKIdeographicDigit3[10] =
683 0x96f6, 0x58f9, 0x8d30, 0x53c1, 0x8086, // 0 - 4
684 0x4f0d, 0x9646, 0x67d2, 0x634c, 0x7396 // 5 - 9
686 static const PRUnichar gCJKIdeographicUnit1[4] =
688 0x000, 0x5341, 0x767e, 0x5343
690 static const PRUnichar gCJKIdeographicUnit2[4] =
692 0x000, 0x62FE, 0x4F70, 0x4EDF
694 static const PRUnichar gCJKIdeographic10KUnit1[4] =
696 0x000, 0x842c, 0x5104, 0x5146
698 static const PRUnichar gCJKIdeographic10KUnit2[4] =
700 0x000, 0x4E07, 0x4ebf, 0x5146
702 static const PRUnichar gCJKIdeographic10KUnit3[4] =
704 0x000, 0x4E07, 0x5104, 0x5146
707 static const PRBool CJKIdeographicToText(PRInt32 ordinal, nsString& result,
708 const PRUnichar* digits,
709 const PRUnichar *unit,
710 const PRUnichar* unit10k)
712 // In theory, we need the following if condiction,
713 // However, the limit, 10 ^ 16, is greater than the max of PRUint32
714 // so we don't really need to test it here.
715 // if( ordinal > 9999999999999999)
716 // {
717 // PR_snprintf(cbuf, sizeof(cbuf), "%ld", ordinal);
718 // result.Append(cbuf);
719 // }
720 // else
721 // {
722 if (ordinal < 0) {
723 DecimalToText(ordinal, result);
724 return PR_FALSE;
726 PRUnichar c10kUnit = 0;
727 PRUnichar cUnit = 0;
728 PRUnichar cDigit = 0;
729 PRUint32 ud = 0;
730 PRUnichar buf[NUM_BUF_SIZE];
731 PRInt32 idx = NUM_BUF_SIZE;
732 PRBool bOutputZero = ( 0 == ordinal );
733 do {
734 if(0 == (ud % 4)) {
735 c10kUnit = unit10k[ud/4];
737 PRInt32 cur = ordinal % 10;
738 cDigit = digits[cur];
739 if( 0 == cur)
741 cUnit = 0;
742 if(bOutputZero) {
743 bOutputZero = PR_FALSE;
744 if(0 != cDigit)
745 buf[--idx] = cDigit;
748 else
750 bOutputZero = PR_TRUE;
751 cUnit = unit[ud%4];
753 if(0 != c10kUnit)
754 buf[--idx] = c10kUnit;
755 if(0 != cUnit)
756 buf[--idx] = cUnit;
757 if((0 != cDigit) &&
758 ( (1 != cur) || (1 != (ud%4)) || ( ordinal > 10)) )
759 buf[--idx] = cDigit;
761 c10kUnit = 0;
763 ordinal /= 10;
764 ++ud;
766 } while( ordinal > 0);
767 result.Append(buf+idx,NUM_BUF_SIZE-idx);
768 // }
769 return PR_TRUE;
772 #define HEBREW_GERESH 0x05F3
773 static const PRUnichar gHebrewDigit[22] =
775 // 1 2 3 4 5 6 7 8 9
776 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8,
777 // 10 20 30 40 50 60 70 80 90
778 0x05D9, 0x05DB, 0x05DC, 0x05DE, 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6,
779 // 100 200 300 400
780 0x05E7, 0x05E8, 0x05E9, 0x05EA
783 static PRBool HebrewToText(PRInt32 ordinal, nsString& result)
785 if (ordinal < 1 || ordinal > 999999) {
786 DecimalToText(ordinal, result);
787 return PR_FALSE;
789 PRBool outputSep = PR_FALSE;
790 nsAutoString allText, thousandsGroup;
791 do {
792 thousandsGroup.Truncate();
793 PRInt32 n3 = ordinal % 1000;
794 // Process digit for 100 - 900
795 for(PRInt32 n1 = 400; n1 > 0; )
797 if( n3 >= n1)
799 n3 -= n1;
800 thousandsGroup.Append(gHebrewDigit[(n1/100)-1+18]);
801 } else {
802 n1 -= 100;
803 } // if
804 } // for
806 // Process digit for 10 - 90
807 PRInt32 n2;
808 if( n3 >= 10 )
810 // Special process for 15 and 16
811 if(( 15 == n3 ) || (16 == n3)) {
812 // Special rule for religious reason...
813 // 15 is represented by 9 and 6, not 10 and 5
814 // 16 is represented by 9 and 7, not 10 and 6
815 n2 = 9;
816 thousandsGroup.Append(gHebrewDigit[ n2 - 1]);
817 } else {
818 n2 = n3 - (n3 % 10);
819 thousandsGroup.Append(gHebrewDigit[(n2/10)-1+9]);
820 } // if
821 n3 -= n2;
822 } // if
824 // Process digit for 1 - 9
825 if ( n3 > 0)
826 thousandsGroup.Append(gHebrewDigit[n3-1]);
827 if (outputSep)
828 thousandsGroup.Append((PRUnichar)HEBREW_GERESH);
829 if (allText.IsEmpty())
830 allText = thousandsGroup;
831 else
832 allText = thousandsGroup + allText;
833 ordinal /= 1000;
834 outputSep = PR_TRUE;
835 } while (ordinal >= 1);
837 result.Append(allText);
838 return PR_TRUE;
842 static PRBool ArmenianToText(PRInt32 ordinal, nsString& result)
844 if (ordinal < 1 || ordinal > 9999) { // zero or reach the limit of Armenian numbering system
845 DecimalToText(ordinal, result);
846 return PR_FALSE;
849 PRUnichar buf[NUM_BUF_SIZE];
850 PRInt32 idx = NUM_BUF_SIZE;
851 PRInt32 d = 0;
852 do {
853 PRInt32 cur = ordinal % 10;
854 if (cur > 0)
856 PRUnichar u = 0x0530 + (d * 9) + cur;
857 buf[--idx] = u;
859 ++d;
860 ordinal /= 10;
861 } while (ordinal > 0);
862 result.Append(buf + idx, NUM_BUF_SIZE - idx);
863 return PR_TRUE;
867 static const PRUnichar gGeorgianValue [ 37 ] = { // 4 * 9 + 1 = 37
868 // 1 2 3 4 5 6 7 8 9
869 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10F1, 0x10D7,
870 // 10 20 30 40 50 60 70 80 90
871 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10F2, 0x10DD, 0x10DE, 0x10DF,
872 // 100 200 300 400 500 600 700 800 900
873 0x10E0, 0x10E1, 0x10E2, 0x10F3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8,
874 // 1000 2000 3000 4000 5000 6000 7000 8000 9000
875 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10F4, 0x10EF, 0x10F0,
876 // 10000
877 0x10F5
879 static PRBool GeorgianToText(PRInt32 ordinal, nsString& result)
881 if (ordinal < 1 || ordinal > 19999) { // zero or reach the limit of Georgian numbering system
882 DecimalToText(ordinal, result);
883 return PR_FALSE;
886 PRUnichar buf[NUM_BUF_SIZE];
887 PRInt32 idx = NUM_BUF_SIZE;
888 PRInt32 d = 0;
889 do {
890 PRInt32 cur = ordinal % 10;
891 if (cur > 0)
893 PRUnichar u = gGeorgianValue[(d * 9 ) + ( cur - 1)];
894 buf[--idx] = u;
896 ++d;
897 ordinal /= 10;
898 } while (ordinal > 0);
899 result.Append(buf + idx, NUM_BUF_SIZE - idx);
900 return PR_TRUE;
903 // Convert ordinal to Ethiopic numeric representation.
904 // The detail is available at http://www.ethiopic.org/Numerals/
905 // The algorithm used here is based on the pseudo-code put up there by
906 // Daniel Yacob <yacob@geez.org>.
907 // Another reference is Unicode 3.0 standard section 11.1.
908 #define ETHIOPIC_ONE 0x1369
909 #define ETHIOPIC_TEN 0x1372
910 #define ETHIOPIC_HUNDRED 0x137B
911 #define ETHIOPIC_TEN_THOUSAND 0x137C
913 static PRBool EthiopicToText(PRInt32 ordinal, nsString& result)
915 nsAutoString asciiNumberString; // decimal string representation of ordinal
916 DecimalToText(ordinal, asciiNumberString);
917 if (ordinal < 1) {
918 result.Append(asciiNumberString);
919 return PR_FALSE;
921 PRUint8 asciiStringLength = asciiNumberString.Length();
923 // If number length is odd, add a leading "0"
924 // the leading "0" preconditions the string to always have the
925 // leading tens place populated, this avoids a check within the loop.
926 // If we didn't add the leading "0", decrement asciiStringLength so
927 // it will be equivalent to a zero-based index in both cases.
928 if (asciiStringLength & 1) {
929 asciiNumberString.Insert(NS_LITERAL_STRING("0"), 0);
930 } else {
931 asciiStringLength--;
934 // Iterate from the highest digits to lowest
935 // indexFromLeft indexes digits (0 = most significant)
936 // groupIndexFromRight indexes pairs of digits (0 = least significant)
937 for (PRUint8 indexFromLeft = 0, groupIndexFromRight = asciiStringLength >> 1;
938 indexFromLeft <= asciiStringLength;
939 indexFromLeft += 2, groupIndexFromRight--) {
940 PRUint8 tensValue = asciiNumberString.CharAt(indexFromLeft) & 0x0F;
941 PRUint8 unitsValue = asciiNumberString.CharAt(indexFromLeft + 1) & 0x0F;
942 PRUint8 groupValue = tensValue * 10 + unitsValue;
944 PRBool oddGroup = (groupIndexFromRight & 1);
946 // we want to clear ETHIOPIC_ONE when it is superfluous
947 if (ordinal > 1 &&
948 groupValue == 1 && // one without a leading ten
949 (oddGroup || indexFromLeft == 0)) { // preceding (100) or leading the sequence
950 unitsValue = 0;
953 // put it all together...
954 if (tensValue) {
955 // map onto Ethiopic "tens":
956 result.Append((PRUnichar) (tensValue + ETHIOPIC_TEN - 1));
958 if (unitsValue) {
959 //map onto Ethiopic "units":
960 result.Append((PRUnichar) (unitsValue + ETHIOPIC_ONE - 1));
962 // Add a separator for all even groups except the last,
963 // and for odd groups with non-zero value.
964 if (oddGroup) {
965 if (groupValue) {
966 result.Append((PRUnichar) ETHIOPIC_HUNDRED);
968 } else {
969 if (groupIndexFromRight) {
970 result.Append((PRUnichar) ETHIOPIC_TEN_THOUSAND);
974 return PR_TRUE;
978 /* static */ PRBool
979 nsBulletFrame::AppendCounterText(PRInt32 aListStyleType,
980 PRInt32 aOrdinal,
981 nsString& result)
983 PRBool success;
985 switch (aListStyleType) {
986 case NS_STYLE_LIST_STYLE_NONE: // used by counters code only
987 break;
989 case NS_STYLE_LIST_STYLE_DISC: // used by counters code only
990 // XXX We really need to do this the same way we do list bullets.
991 result.Append(PRUnichar(0x2022));
992 break;
994 case NS_STYLE_LIST_STYLE_CIRCLE: // used by counters code only
995 // XXX We really need to do this the same way we do list bullets.
996 result.Append(PRUnichar(0x25E6));
997 break;
999 case NS_STYLE_LIST_STYLE_SQUARE: // used by counters code only
1000 // XXX We really need to do this the same way we do list bullets.
1001 result.Append(PRUnichar(0x25FE));
1002 break;
1004 case NS_STYLE_LIST_STYLE_DECIMAL:
1005 case NS_STYLE_LIST_STYLE_OLD_DECIMAL:
1006 default: // CSS2 say "A users agent that does not recognize a numbering system
1007 // should use 'decimal'
1008 success = DecimalToText(aOrdinal, result);
1009 break;
1011 case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO:
1012 success = DecimalLeadingZeroToText(aOrdinal, result);
1013 break;
1015 case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
1016 case NS_STYLE_LIST_STYLE_OLD_LOWER_ROMAN:
1017 success = RomanToText(aOrdinal, result,
1018 gLowerRomanCharsA, gLowerRomanCharsB);
1019 break;
1020 case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
1021 case NS_STYLE_LIST_STYLE_OLD_UPPER_ROMAN:
1022 success = RomanToText(aOrdinal, result,
1023 gUpperRomanCharsA, gUpperRomanCharsB);
1024 break;
1026 case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
1027 case NS_STYLE_LIST_STYLE_OLD_LOWER_ALPHA:
1028 success = CharListToText(aOrdinal, result, gLowerAlphaChars, ALPHA_SIZE);
1029 break;
1031 case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
1032 case NS_STYLE_LIST_STYLE_OLD_UPPER_ALPHA:
1033 success = CharListToText(aOrdinal, result, gUpperAlphaChars, ALPHA_SIZE);
1034 break;
1036 case NS_STYLE_LIST_STYLE_KATAKANA:
1037 success = CharListToText(aOrdinal, result, gKatakanaChars,
1038 KATAKANA_CHARS_SIZE);
1039 break;
1041 case NS_STYLE_LIST_STYLE_HIRAGANA:
1042 success = CharListToText(aOrdinal, result, gHiraganaChars,
1043 HIRAGANA_CHARS_SIZE);
1044 break;
1046 case NS_STYLE_LIST_STYLE_KATAKANA_IROHA:
1047 success = CharListToText(aOrdinal, result, gKatakanaIrohaChars,
1048 KATAKANA_IROHA_CHARS_SIZE);
1049 break;
1051 case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA:
1052 success = CharListToText(aOrdinal, result, gHiraganaIrohaChars,
1053 HIRAGANA_IROHA_CHARS_SIZE);
1054 break;
1056 case NS_STYLE_LIST_STYLE_LOWER_GREEK:
1057 success = CharListToText(aOrdinal, result, gLowerGreekChars ,
1058 LOWER_GREEK_CHARS_SIZE);
1059 break;
1061 case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC:
1062 case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL:
1063 success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1,
1064 gCJKIdeographicUnit1,
1065 gCJKIdeographic10KUnit1);
1066 break;
1068 case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL:
1069 success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit2,
1070 gCJKIdeographicUnit2,
1071 gCJKIdeographic10KUnit1);
1072 break;
1074 case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL:
1075 success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1,
1076 gCJKIdeographicUnit1,
1077 gCJKIdeographic10KUnit2);
1078 break;
1080 case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL:
1081 success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit3,
1082 gCJKIdeographicUnit2,
1083 gCJKIdeographic10KUnit2);
1084 break;
1086 case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL:
1087 success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1,
1088 gCJKIdeographicUnit1,
1089 gCJKIdeographic10KUnit3);
1090 break;
1092 case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL:
1093 success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit2,
1094 gCJKIdeographicUnit2,
1095 gCJKIdeographic10KUnit3);
1096 break;
1098 case NS_STYLE_LIST_STYLE_HEBREW:
1099 success = HebrewToText(aOrdinal, result);
1100 break;
1102 case NS_STYLE_LIST_STYLE_ARMENIAN:
1103 success = ArmenianToText(aOrdinal, result);
1104 break;
1106 case NS_STYLE_LIST_STYLE_GEORGIAN:
1107 success = GeorgianToText(aOrdinal, result);
1108 break;
1110 case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC:
1111 success = OtherDecimalToText(aOrdinal, 0x0660, result);
1112 break;
1114 case NS_STYLE_LIST_STYLE_MOZ_PERSIAN:
1115 case NS_STYLE_LIST_STYLE_MOZ_URDU:
1116 success = OtherDecimalToText(aOrdinal, 0x06f0, result);
1117 break;
1119 case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI:
1120 success = OtherDecimalToText(aOrdinal, 0x0966, result);
1121 break;
1123 case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI:
1124 success = OtherDecimalToText(aOrdinal, 0x0a66, result);
1125 break;
1127 case NS_STYLE_LIST_STYLE_MOZ_GUJARATI:
1128 success = OtherDecimalToText(aOrdinal, 0x0AE6, result);
1129 break;
1131 case NS_STYLE_LIST_STYLE_MOZ_ORIYA:
1132 success = OtherDecimalToText(aOrdinal, 0x0B66, result);
1133 break;
1135 case NS_STYLE_LIST_STYLE_MOZ_KANNADA:
1136 success = OtherDecimalToText(aOrdinal, 0x0CE6, result);
1137 break;
1139 case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM:
1140 success = OtherDecimalToText(aOrdinal, 0x0D66, result);
1141 break;
1143 case NS_STYLE_LIST_STYLE_MOZ_THAI:
1144 success = OtherDecimalToText(aOrdinal, 0x0E50, result);
1145 break;
1147 case NS_STYLE_LIST_STYLE_MOZ_LAO:
1148 success = OtherDecimalToText(aOrdinal, 0x0ED0, result);
1149 break;
1151 case NS_STYLE_LIST_STYLE_MOZ_MYANMAR:
1152 success = OtherDecimalToText(aOrdinal, 0x1040, result);
1153 break;
1155 case NS_STYLE_LIST_STYLE_MOZ_KHMER:
1156 success = OtherDecimalToText(aOrdinal, 0x17E0, result);
1157 break;
1159 case NS_STYLE_LIST_STYLE_MOZ_BENGALI:
1160 success = OtherDecimalToText(aOrdinal, 0x09E6, result);
1161 break;
1163 case NS_STYLE_LIST_STYLE_MOZ_TELUGU:
1164 success = OtherDecimalToText(aOrdinal, 0x0C66, result);
1165 break;
1167 case NS_STYLE_LIST_STYLE_MOZ_TAMIL:
1168 success = TamilToText(aOrdinal, result);
1169 break;
1171 case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM:
1172 success = CharListToText(aOrdinal, result, gCJKHeavenlyStemChars,
1173 CJK_HEAVENLY_STEM_CHARS_SIZE);
1174 break;
1176 case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH:
1177 success = CharListToText(aOrdinal, result, gCJKEarthlyBranchChars,
1178 CJK_EARTHLY_BRANCH_CHARS_SIZE);
1179 break;
1181 case NS_STYLE_LIST_STYLE_MOZ_HANGUL:
1182 success = CharListToText(aOrdinal, result, gHangulChars, HANGUL_CHARS_SIZE);
1183 break;
1185 case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT:
1186 success = CharListToText(aOrdinal, result, gHangulConsonantChars,
1187 HANGUL_CONSONANT_CHARS_SIZE);
1188 break;
1190 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME:
1191 success = CharListToText(aOrdinal, result, gEthiopicHalehameChars,
1192 ETHIOPIC_HALEHAME_CHARS_SIZE);
1193 break;
1195 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC:
1196 success = EthiopicToText(aOrdinal, result);
1197 break;
1199 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM:
1200 success = CharListToText(aOrdinal, result, gEthiopicHalehameAmChars,
1201 ETHIOPIC_HALEHAME_AM_CHARS_SIZE);
1202 break;
1204 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER:
1205 success = CharListToText(aOrdinal, result, gEthiopicHalehameTiErChars,
1206 ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE);
1207 break;
1209 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET:
1210 success = CharListToText(aOrdinal, result, gEthiopicHalehameTiEtChars,
1211 ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE);
1212 break;
1214 return success;
1217 PRBool
1218 nsBulletFrame::GetListItemText(const nsStyleList& aListStyle,
1219 nsString& result)
1221 const nsStyleVisibility* vis = GetStyleVisibility();
1223 NS_ASSERTION(aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_NONE &&
1224 aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_DISC &&
1225 aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_CIRCLE &&
1226 aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_SQUARE,
1227 "we should be using specialized code for these types");
1228 PRBool success =
1229 AppendCounterText(aListStyle.mListStyleType, mOrdinal, result);
1230 if (success && aListStyle.mListStyleType == NS_STYLE_LIST_STYLE_HEBREW)
1231 mTextIsRTL = PR_TRUE;
1233 // XXX For some of these systems, "." is wrong! This should really be
1234 // pushed down into the individual cases!
1235 nsString suffix = NS_LITERAL_STRING(".");
1237 // We're not going to do proper Bidi reordering on the list item marker, but
1238 // just display the whole thing as RTL or LTR, so we fake reordering by
1239 // appending the suffix to the end of the list item marker if the
1240 // directionality of the characters is the same as the style direction or
1241 // prepending it to the beginning if they are different.
1242 result = (mTextIsRTL == (vis->mDirection == NS_STYLE_DIRECTION_RTL)) ?
1243 result + suffix : suffix + result;
1244 return success;
1247 #define MIN_BULLET_SIZE 1
1250 void
1251 nsBulletFrame::GetDesiredSize(nsPresContext* aCX,
1252 nsIRenderingContext *aRenderingContext,
1253 nsHTMLReflowMetrics& aMetrics)
1255 // Reset our padding. If we need it, we'll set it below.
1256 mPadding.SizeTo(0, 0, 0, 0);
1258 const nsStyleList* myList = GetStyleList();
1259 nscoord ascent;
1261 if (myList->mListStyleImage && mImageRequest) {
1262 PRUint32 status;
1263 mImageRequest->GetImageStatus(&status);
1264 if (status & imgIRequest::STATUS_SIZE_AVAILABLE &&
1265 !(status & imgIRequest::STATUS_ERROR)) {
1266 // auto size the image
1267 mComputedSize.width = mIntrinsicSize.width;
1268 mComputedSize.height = mIntrinsicSize.height;
1270 aMetrics.width = mComputedSize.width;
1271 aMetrics.ascent = aMetrics.height = mComputedSize.height;
1273 return;
1277 // If we're getting our desired size and don't have an image, reset
1278 // mIntrinsicSize to (0,0). Otherwise, if we used to have an image, it
1279 // changed, and the new one is coming in, but we're reflowing before it's
1280 // fully there, we'll end up with mIntrinsicSize not matching our size, but
1281 // won't trigger a reflow in OnStartContainer (because mIntrinsicSize will
1282 // match the image size).
1283 mIntrinsicSize.SizeTo(0, 0);
1285 nsCOMPtr<nsIFontMetrics> fm;
1286 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
1287 nscoord bulletSize;
1289 nsAutoString text;
1290 switch (myList->mListStyleType) {
1291 case NS_STYLE_LIST_STYLE_NONE:
1292 aMetrics.width = 0;
1293 aMetrics.ascent = aMetrics.height = 0;
1294 break;
1296 case NS_STYLE_LIST_STYLE_DISC:
1297 case NS_STYLE_LIST_STYLE_CIRCLE:
1298 case NS_STYLE_LIST_STYLE_SQUARE:
1299 fm->GetMaxAscent(ascent);
1300 bulletSize = NS_MAX(nsPresContext::CSSPixelsToAppUnits(MIN_BULLET_SIZE),
1301 NSToCoordRound(0.8f * (float(ascent) / 2.0f)));
1302 mPadding.bottom = NSToCoordRound(float(ascent) / 8.0f);
1303 aMetrics.width = mPadding.right + bulletSize;
1304 aMetrics.ascent = aMetrics.height = mPadding.bottom + bulletSize;
1305 break;
1307 default:
1308 case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO:
1309 case NS_STYLE_LIST_STYLE_DECIMAL:
1310 case NS_STYLE_LIST_STYLE_OLD_DECIMAL:
1311 case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
1312 case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
1313 case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
1314 case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
1315 case NS_STYLE_LIST_STYLE_OLD_LOWER_ROMAN:
1316 case NS_STYLE_LIST_STYLE_OLD_UPPER_ROMAN:
1317 case NS_STYLE_LIST_STYLE_OLD_LOWER_ALPHA:
1318 case NS_STYLE_LIST_STYLE_OLD_UPPER_ALPHA:
1319 case NS_STYLE_LIST_STYLE_KATAKANA:
1320 case NS_STYLE_LIST_STYLE_HIRAGANA:
1321 case NS_STYLE_LIST_STYLE_KATAKANA_IROHA:
1322 case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA:
1323 case NS_STYLE_LIST_STYLE_LOWER_GREEK:
1324 case NS_STYLE_LIST_STYLE_HEBREW:
1325 case NS_STYLE_LIST_STYLE_ARMENIAN:
1326 case NS_STYLE_LIST_STYLE_GEORGIAN:
1327 case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC:
1328 case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL:
1329 case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL:
1330 case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL:
1331 case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL:
1332 case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL:
1333 case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL:
1334 case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM:
1335 case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH:
1336 case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC:
1337 case NS_STYLE_LIST_STYLE_MOZ_PERSIAN:
1338 case NS_STYLE_LIST_STYLE_MOZ_URDU:
1339 case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI:
1340 case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI:
1341 case NS_STYLE_LIST_STYLE_MOZ_GUJARATI:
1342 case NS_STYLE_LIST_STYLE_MOZ_ORIYA:
1343 case NS_STYLE_LIST_STYLE_MOZ_KANNADA:
1344 case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM:
1345 case NS_STYLE_LIST_STYLE_MOZ_BENGALI:
1346 case NS_STYLE_LIST_STYLE_MOZ_TAMIL:
1347 case NS_STYLE_LIST_STYLE_MOZ_TELUGU:
1348 case NS_STYLE_LIST_STYLE_MOZ_THAI:
1349 case NS_STYLE_LIST_STYLE_MOZ_LAO:
1350 case NS_STYLE_LIST_STYLE_MOZ_MYANMAR:
1351 case NS_STYLE_LIST_STYLE_MOZ_KHMER:
1352 case NS_STYLE_LIST_STYLE_MOZ_HANGUL:
1353 case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT:
1354 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME:
1355 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC:
1356 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM:
1357 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER:
1358 case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET:
1359 GetListItemText(*myList, text);
1360 fm->GetHeight(aMetrics.height);
1361 aRenderingContext->SetFont(fm);
1362 aMetrics.width = nsLayoutUtils::GetStringWidth(this, aRenderingContext, text.get(), text.Length());
1363 aMetrics.width += mPadding.right;
1364 fm->GetMaxAscent(aMetrics.ascent);
1365 break;
1369 NS_IMETHODIMP
1370 nsBulletFrame::Reflow(nsPresContext* aPresContext,
1371 nsHTMLReflowMetrics& aMetrics,
1372 const nsHTMLReflowState& aReflowState,
1373 nsReflowStatus& aStatus)
1375 DO_GLOBAL_REFLOW_COUNT("nsBulletFrame");
1376 DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
1378 // Get the base size
1379 GetDesiredSize(aPresContext, aReflowState.rendContext, aMetrics);
1381 // Add in the border and padding; split the top/bottom between the
1382 // ascent and descent to make things look nice
1383 const nsMargin& borderPadding = aReflowState.mComputedBorderPadding;
1384 aMetrics.width += borderPadding.left + borderPadding.right;
1385 aMetrics.height += borderPadding.top + borderPadding.bottom;
1386 aMetrics.ascent += borderPadding.top;
1388 // XXX this is a bit of a hack, we're assuming that no glyphs used for bullets
1389 // overflow their font-boxes. It'll do for now; to fix it for real, we really
1390 // should rewrite all the text-handling code here to use gfxTextRun (bug
1391 // 397294).
1392 aMetrics.mOverflowArea.SetRect(0, 0, aMetrics.width, aMetrics.height);
1394 aStatus = NS_FRAME_COMPLETE;
1395 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
1396 return NS_OK;
1399 /* virtual */ nscoord
1400 nsBulletFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
1402 nsHTMLReflowMetrics metrics;
1403 DISPLAY_MIN_WIDTH(this, metrics.width);
1404 GetDesiredSize(PresContext(), aRenderingContext, metrics);
1405 return metrics.width;
1408 /* virtual */ nscoord
1409 nsBulletFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
1411 nsHTMLReflowMetrics metrics;
1412 DISPLAY_PREF_WIDTH(this, metrics.width);
1413 GetDesiredSize(PresContext(), aRenderingContext, metrics);
1414 return metrics.width;
1418 NS_IMETHODIMP nsBulletFrame::OnStartContainer(imgIRequest *aRequest,
1419 imgIContainer *aImage)
1421 if (!aImage) return NS_ERROR_INVALID_ARG;
1422 if (!aRequest) return NS_ERROR_INVALID_ARG;
1424 PRUint32 status;
1425 aRequest->GetImageStatus(&status);
1426 if (status & imgIRequest::STATUS_ERROR) {
1427 return NS_OK;
1430 nscoord w, h;
1431 aImage->GetWidth(&w);
1432 aImage->GetHeight(&h);
1434 nsPresContext* presContext = PresContext();
1436 nsSize newsize(nsPresContext::CSSPixelsToAppUnits(w),
1437 nsPresContext::CSSPixelsToAppUnits(h));
1439 if (mIntrinsicSize != newsize) {
1440 mIntrinsicSize = newsize;
1442 // Now that the size is available (or an error occurred), trigger
1443 // a reflow of the bullet frame.
1444 nsIPresShell *shell = presContext->GetPresShell();
1445 if (shell) {
1446 shell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
1447 NS_FRAME_IS_DIRTY);
1451 // Handle animations
1452 aImage->SetAnimationMode(presContext->ImageAnimationMode());
1453 // Ensure the animation (if any) is started.
1454 aImage->StartAnimation();
1457 return NS_OK;
1460 NS_IMETHODIMP nsBulletFrame::OnDataAvailable(imgIRequest *aRequest,
1461 PRBool aCurrentFrame,
1462 const nsIntRect *aRect)
1464 // The image has changed.
1465 // Invalidate the entire content area. Maybe it's not optimal but it's simple and
1466 // always correct, and I'll be a stunned mullet if it ever matters for performance
1467 Invalidate(nsRect(0, 0, mRect.width, mRect.height));
1469 return NS_OK;
1472 NS_IMETHODIMP nsBulletFrame::OnStopDecode(imgIRequest *aRequest,
1473 nsresult aStatus,
1474 const PRUnichar *aStatusArg)
1476 // XXX should the bulletframe do anything if the image failed to load?
1477 // it didn't in the old code...
1479 #if 0
1480 if (NS_FAILED(aStatus)) {
1481 // We failed to load the image. Notify the pres shell
1482 if (NS_FAILED(aStatus) && (mImageRequest == aRequest || !mImageRequest)) {
1483 imageFailed = PR_TRUE;
1486 #endif
1488 return NS_OK;
1491 NS_IMETHODIMP nsBulletFrame::FrameChanged(imgIContainer *aContainer,
1492 nsIntRect *aDirtyRect)
1494 // Invalidate the entire content area. Maybe it's not optimal but it's simple and
1495 // always correct.
1496 Invalidate(nsRect(0, 0, mRect.width, mRect.height));
1498 return NS_OK;
1501 void
1502 nsBulletFrame::GetLoadGroup(nsPresContext *aPresContext, nsILoadGroup **aLoadGroup)
1504 if (!aPresContext)
1505 return;
1507 NS_PRECONDITION(nsnull != aLoadGroup, "null OUT parameter pointer");
1509 nsIPresShell *shell = aPresContext->GetPresShell();
1511 if (!shell)
1512 return;
1514 nsIDocument *doc = shell->GetDocument();
1515 if (!doc)
1516 return;
1518 *aLoadGroup = doc->GetDocumentLoadGroup().get(); // already_AddRefed
1528 NS_IMPL_ISUPPORTS2(nsBulletListener, imgIDecoderObserver, imgIContainerObserver)
1530 nsBulletListener::nsBulletListener() :
1531 mFrame(nsnull)
1535 nsBulletListener::~nsBulletListener()
1539 NS_IMETHODIMP nsBulletListener::OnStartContainer(imgIRequest *aRequest,
1540 imgIContainer *aImage)
1542 if (!mFrame)
1543 return NS_ERROR_FAILURE;
1545 return mFrame->OnStartContainer(aRequest, aImage);
1548 NS_IMETHODIMP nsBulletListener::OnDataAvailable(imgIRequest *aRequest,
1549 PRBool aCurrentFrame,
1550 const nsIntRect *aRect)
1552 if (!mFrame)
1553 return NS_ERROR_FAILURE;
1555 return mFrame->OnDataAvailable(aRequest, aCurrentFrame, aRect);
1558 NS_IMETHODIMP nsBulletListener::OnStopDecode(imgIRequest *aRequest,
1559 nsresult status,
1560 const PRUnichar *statusArg)
1562 if (!mFrame)
1563 return NS_ERROR_FAILURE;
1565 return mFrame->OnStopDecode(aRequest, status, statusArg);
1568 NS_IMETHODIMP nsBulletListener::FrameChanged(imgIContainer *aContainer,
1569 nsIntRect *dirtyRect)
1571 if (!mFrame)
1572 return NS_ERROR_FAILURE;
1574 return mFrame->FrameChanged(aContainer, dirtyRect);