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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
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.
21 : *
22 : * Contributor(s):
23 : *
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.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /* rendering object for list-item bullets */
39 :
40 : #include "nsCOMPtr.h"
41 : #include "nsBulletFrame.h"
42 : #include "nsGkAtoms.h"
43 : #include "nsHTMLParts.h"
44 : #include "nsContainerFrame.h"
45 : #include "nsGenericHTMLElement.h"
46 : #include "nsPresContext.h"
47 : #include "nsIPresShell.h"
48 : #include "nsIDocument.h"
49 : #include "nsRenderingContext.h"
50 : #include "nsILoadGroup.h"
51 : #include "nsIURL.h"
52 : #include "nsNetUtil.h"
53 : #include "prprf.h"
54 : #include "nsDisplayList.h"
55 :
56 : #include "imgILoader.h"
57 : #include "imgIContainer.h"
58 :
59 : #include "nsIServiceManager.h"
60 : #include "nsIComponentManager.h"
61 : #include "nsContentUtils.h"
62 :
63 : #ifdef ACCESSIBILITY
64 : #include "nsAccessibilityService.h"
65 : #endif
66 :
67 : using namespace mozilla;
68 :
69 0 : NS_DECLARE_FRAME_PROPERTY(FontSizeInflationProperty, nsnull)
70 :
71 0 : NS_IMPL_FRAMEARENA_HELPERS(nsBulletFrame)
72 :
73 0 : nsBulletFrame::~nsBulletFrame()
74 : {
75 0 : }
76 :
77 : void
78 0 : nsBulletFrame::DestroyFrom(nsIFrame* aDestructRoot)
79 : {
80 : // Stop image loading first
81 0 : if (mImageRequest) {
82 : // Deregister our image request from the refresh driver
83 : nsLayoutUtils::DeregisterImageRequest(PresContext(),
84 : mImageRequest,
85 0 : &mRequestRegistered);
86 0 : mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
87 0 : mImageRequest = nsnull;
88 : }
89 :
90 0 : if (mListener) {
91 0 : mListener->SetFrame(nsnull);
92 : }
93 :
94 : // Let base class do the rest
95 0 : nsFrame::DestroyFrom(aDestructRoot);
96 0 : }
97 :
98 : #ifdef NS_DEBUG
99 : NS_IMETHODIMP
100 0 : nsBulletFrame::GetFrameName(nsAString& aResult) const
101 : {
102 0 : return MakeFrameName(NS_LITERAL_STRING("Bullet"), aResult);
103 : }
104 : #endif
105 :
106 : nsIAtom*
107 0 : nsBulletFrame::GetType() const
108 : {
109 0 : return nsGkAtoms::bulletFrame;
110 : }
111 :
112 : bool
113 0 : nsBulletFrame::IsEmpty()
114 : {
115 0 : return IsSelfEmpty();
116 : }
117 :
118 : bool
119 0 : nsBulletFrame::IsSelfEmpty()
120 : {
121 0 : return GetStyleList()->mListStyleType == NS_STYLE_LIST_STYLE_NONE;
122 : }
123 :
124 : /* virtual */ void
125 0 : nsBulletFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
126 : {
127 0 : nsFrame::DidSetStyleContext(aOldStyleContext);
128 :
129 0 : imgIRequest *newRequest = GetStyleList()->GetListStyleImage();
130 :
131 0 : if (newRequest) {
132 :
133 0 : if (!mListener) {
134 0 : mListener = new nsBulletListener();
135 0 : mListener->SetFrame(this);
136 : }
137 :
138 0 : bool needNewRequest = true;
139 :
140 0 : if (mImageRequest) {
141 : // Reload the image, maybe...
142 0 : nsCOMPtr<nsIURI> oldURI;
143 0 : mImageRequest->GetURI(getter_AddRefs(oldURI));
144 0 : nsCOMPtr<nsIURI> newURI;
145 0 : newRequest->GetURI(getter_AddRefs(newURI));
146 0 : if (oldURI && newURI) {
147 : bool same;
148 0 : newURI->Equals(oldURI, &same);
149 0 : if (same) {
150 0 : needNewRequest = false;
151 : } else {
152 : nsLayoutUtils::DeregisterImageRequest(PresContext(), mImageRequest,
153 0 : &mRequestRegistered);
154 0 : mImageRequest->Cancel(NS_ERROR_FAILURE);
155 0 : mImageRequest = nsnull;
156 : }
157 : }
158 : }
159 :
160 0 : if (needNewRequest) {
161 0 : newRequest->Clone(mListener, getter_AddRefs(mImageRequest));
162 0 : if (mImageRequest) {
163 : nsLayoutUtils::RegisterImageRequestIfAnimated(PresContext(),
164 : mImageRequest,
165 0 : &mRequestRegistered);
166 : }
167 : }
168 : } else {
169 : // No image request on the new style context
170 0 : if (mImageRequest) {
171 : nsLayoutUtils::DeregisterImageRequest(PresContext(), mImageRequest,
172 0 : &mRequestRegistered);
173 :
174 0 : mImageRequest->Cancel(NS_ERROR_FAILURE);
175 0 : mImageRequest = nsnull;
176 : }
177 : }
178 :
179 : #ifdef ACCESSIBILITY
180 : // Update the list bullet accessible. If old style list isn't available then
181 : // no need to update the accessible tree because it's not created yet.
182 0 : if (aOldStyleContext) {
183 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
184 0 : if (accService) {
185 0 : const nsStyleList* oldStyleList = aOldStyleContext->PeekStyleList();
186 0 : if (oldStyleList) {
187 0 : bool hadBullet = oldStyleList->GetListStyleImage() ||
188 0 : oldStyleList->mListStyleType != NS_STYLE_LIST_STYLE_NONE;
189 :
190 0 : const nsStyleList* newStyleList = GetStyleList();
191 0 : bool hasBullet = newStyleList->GetListStyleImage() ||
192 0 : newStyleList->mListStyleType != NS_STYLE_LIST_STYLE_NONE;
193 :
194 0 : if (hadBullet != hasBullet) {
195 : accService->UpdateListBullet(PresContext()->GetPresShell(), mContent,
196 0 : hasBullet);
197 : }
198 : }
199 : }
200 : }
201 : #endif
202 0 : }
203 :
204 : class nsDisplayBullet : public nsDisplayItem {
205 : public:
206 0 : nsDisplayBullet(nsDisplayListBuilder* aBuilder, nsBulletFrame* aFrame) :
207 0 : nsDisplayItem(aBuilder, aFrame) {
208 0 : MOZ_COUNT_CTOR(nsDisplayBullet);
209 0 : }
210 : #ifdef NS_BUILD_REFCNT_LOGGING
211 0 : virtual ~nsDisplayBullet() {
212 0 : MOZ_COUNT_DTOR(nsDisplayBullet);
213 0 : }
214 : #endif
215 :
216 0 : virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder)
217 : {
218 0 : return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
219 : }
220 0 : virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
221 : HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
222 0 : aOutFrames->AppendElement(mFrame);
223 0 : }
224 : virtual void Paint(nsDisplayListBuilder* aBuilder,
225 : nsRenderingContext* aCtx);
226 0 : NS_DISPLAY_DECL_NAME("Bullet", TYPE_BULLET)
227 :
228 0 : virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
229 : {
230 0 : return GetBounds(aBuilder);
231 : }
232 : };
233 :
234 0 : void nsDisplayBullet::Paint(nsDisplayListBuilder* aBuilder,
235 : nsRenderingContext* aCtx)
236 : {
237 : static_cast<nsBulletFrame*>(mFrame)->
238 0 : PaintBullet(*aCtx, ToReferenceFrame(), mVisibleRect);
239 0 : }
240 :
241 : NS_IMETHODIMP
242 0 : nsBulletFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
243 : const nsRect& aDirtyRect,
244 : const nsDisplayListSet& aLists)
245 : {
246 0 : if (!IsVisibleForPainting(aBuilder))
247 0 : return NS_OK;
248 :
249 0 : DO_GLOBAL_REFLOW_COUNT_DSP("nsBulletFrame");
250 :
251 : return aLists.Content()->AppendNewToTop(
252 0 : new (aBuilder) nsDisplayBullet(aBuilder, this));
253 : }
254 :
255 : void
256 0 : nsBulletFrame::PaintBullet(nsRenderingContext& aRenderingContext, nsPoint aPt,
257 : const nsRect& aDirtyRect)
258 : {
259 0 : const nsStyleList* myList = GetStyleList();
260 0 : PRUint8 listStyleType = myList->mListStyleType;
261 :
262 0 : if (myList->GetListStyleImage() && mImageRequest) {
263 : PRUint32 status;
264 0 : mImageRequest->GetImageStatus(&status);
265 0 : if (status & imgIRequest::STATUS_LOAD_COMPLETE &&
266 0 : !(status & imgIRequest::STATUS_ERROR)) {
267 0 : nsCOMPtr<imgIContainer> imageCon;
268 0 : mImageRequest->GetImage(getter_AddRefs(imageCon));
269 0 : if (imageCon) {
270 : nsRect dest(mPadding.left, mPadding.top,
271 : mRect.width - (mPadding.left + mPadding.right),
272 0 : mRect.height - (mPadding.top + mPadding.bottom));
273 : nsLayoutUtils::DrawSingleImage(&aRenderingContext,
274 : imageCon, nsLayoutUtils::GetGraphicsFilterForFrame(this),
275 0 : dest + aPt, aDirtyRect, imgIContainer::FLAG_NONE);
276 : return;
277 : }
278 : }
279 : }
280 :
281 0 : nsRefPtr<nsFontMetrics> fm;
282 0 : aRenderingContext.SetColor(nsLayoutUtils::GetColor(this, eCSSProperty_color));
283 :
284 0 : mTextIsRTL = false;
285 :
286 0 : nsAutoString text;
287 0 : switch (listStyleType) {
288 : case NS_STYLE_LIST_STYLE_NONE:
289 0 : break;
290 :
291 : default:
292 : case NS_STYLE_LIST_STYLE_DISC:
293 : aRenderingContext.FillEllipse(mPadding.left + aPt.x, mPadding.top + aPt.y,
294 : mRect.width - (mPadding.left + mPadding.right),
295 0 : mRect.height - (mPadding.top + mPadding.bottom));
296 0 : break;
297 :
298 : case NS_STYLE_LIST_STYLE_CIRCLE:
299 : aRenderingContext.DrawEllipse(mPadding.left + aPt.x, mPadding.top + aPt.y,
300 : mRect.width - (mPadding.left + mPadding.right),
301 0 : mRect.height - (mPadding.top + mPadding.bottom));
302 0 : break;
303 :
304 : case NS_STYLE_LIST_STYLE_SQUARE:
305 : {
306 0 : nsRect rect(aPt, mRect.Size());
307 0 : rect.Deflate(mPadding);
308 :
309 : // Snap the height and the width of the rectangle to device pixels,
310 : // and then center the result within the original rectangle, so that
311 : // all square bullets at the same font size have the same visual
312 : // size (bug 376690).
313 : // FIXME: We should really only do this if we're not transformed
314 : // (like gfxContext::UserToDevicePixelSnapped does).
315 0 : nsPresContext *pc = PresContext();
316 : nsRect snapRect(rect.x, rect.y,
317 : pc->RoundAppUnitsToNearestDevPixels(rect.width),
318 0 : pc->RoundAppUnitsToNearestDevPixels(rect.height));
319 : snapRect.MoveBy((rect.width - snapRect.width) / 2,
320 0 : (rect.height - snapRect.height) / 2);
321 : aRenderingContext.FillRect(snapRect.x, snapRect.y,
322 0 : snapRect.width, snapRect.height);
323 : }
324 0 : break;
325 :
326 : case NS_STYLE_LIST_STYLE_DECIMAL:
327 : case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO:
328 : case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
329 : case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
330 : case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
331 : case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
332 : case NS_STYLE_LIST_STYLE_LOWER_GREEK:
333 : case NS_STYLE_LIST_STYLE_HEBREW:
334 : case NS_STYLE_LIST_STYLE_ARMENIAN:
335 : case NS_STYLE_LIST_STYLE_GEORGIAN:
336 : case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC:
337 : case NS_STYLE_LIST_STYLE_HIRAGANA:
338 : case NS_STYLE_LIST_STYLE_KATAKANA:
339 : case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA:
340 : case NS_STYLE_LIST_STYLE_KATAKANA_IROHA:
341 : case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL:
342 : case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL:
343 : case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL:
344 : case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL:
345 : case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL:
346 : case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL:
347 : case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM:
348 : case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH:
349 : case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC:
350 : case NS_STYLE_LIST_STYLE_MOZ_PERSIAN:
351 : case NS_STYLE_LIST_STYLE_MOZ_URDU:
352 : case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI:
353 : case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI:
354 : case NS_STYLE_LIST_STYLE_MOZ_GUJARATI:
355 : case NS_STYLE_LIST_STYLE_MOZ_ORIYA:
356 : case NS_STYLE_LIST_STYLE_MOZ_KANNADA:
357 : case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM:
358 : case NS_STYLE_LIST_STYLE_MOZ_BENGALI:
359 : case NS_STYLE_LIST_STYLE_MOZ_TAMIL:
360 : case NS_STYLE_LIST_STYLE_MOZ_TELUGU:
361 : case NS_STYLE_LIST_STYLE_MOZ_THAI:
362 : case NS_STYLE_LIST_STYLE_MOZ_LAO:
363 : case NS_STYLE_LIST_STYLE_MOZ_MYANMAR:
364 : case NS_STYLE_LIST_STYLE_MOZ_KHMER:
365 : case NS_STYLE_LIST_STYLE_MOZ_HANGUL:
366 : case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT:
367 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME:
368 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC:
369 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM:
370 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER:
371 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET:
372 : nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
373 0 : GetFontSizeInflation());
374 0 : GetListItemText(*myList, text);
375 0 : aRenderingContext.SetFont(fm);
376 0 : nscoord ascent = fm->MaxAscent();
377 0 : aRenderingContext.SetTextRunRTL(mTextIsRTL);
378 : aRenderingContext.DrawString(text, mPadding.left + aPt.x,
379 0 : mPadding.top + aPt.y + ascent);
380 0 : break;
381 : }
382 : }
383 :
384 : PRInt32
385 0 : nsBulletFrame::SetListItemOrdinal(PRInt32 aNextOrdinal,
386 : bool* aChanged)
387 : {
388 : // Assume that the ordinal comes from the caller
389 0 : PRInt32 oldOrdinal = mOrdinal;
390 0 : mOrdinal = aNextOrdinal;
391 :
392 : // Try to get value directly from the list-item, if it specifies a
393 : // value attribute. Note: we do this with our parent's content
394 : // because our parent is the list-item.
395 0 : nsIContent* parentContent = mParent->GetContent();
396 0 : if (parentContent) {
397 : nsGenericHTMLElement *hc =
398 0 : nsGenericHTMLElement::FromContent(parentContent);
399 0 : if (hc) {
400 0 : const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::value);
401 0 : if (attr && attr->Type() == nsAttrValue::eInteger) {
402 : // Use ordinal specified by the value attribute
403 0 : mOrdinal = attr->GetIntegerValue();
404 : }
405 : }
406 : }
407 :
408 0 : *aChanged = oldOrdinal != mOrdinal;
409 :
410 0 : return mOrdinal + 1;
411 : }
412 :
413 :
414 : // XXX change roman/alpha to use unsigned math so that maxint and
415 : // maxnegint will work
416 :
417 : /**
418 : * For all functions below, a return value of true means that we
419 : * could represent mOrder in the desired numbering system. false
420 : * means we had to fall back to decimal
421 : */
422 0 : static bool DecimalToText(PRInt32 ordinal, nsString& result)
423 : {
424 : char cbuf[40];
425 0 : PR_snprintf(cbuf, sizeof(cbuf), "%ld", ordinal);
426 0 : result.AppendASCII(cbuf);
427 0 : return true;
428 : }
429 0 : static bool DecimalLeadingZeroToText(PRInt32 ordinal, nsString& result)
430 : {
431 : char cbuf[40];
432 0 : PR_snprintf(cbuf, sizeof(cbuf), "%02ld", ordinal);
433 0 : result.AppendASCII(cbuf);
434 0 : return true;
435 : }
436 0 : static bool OtherDecimalToText(PRInt32 ordinal, PRUnichar zeroChar, nsString& result)
437 : {
438 0 : PRUnichar diff = zeroChar - PRUnichar('0');
439 0 : DecimalToText(ordinal, result);
440 0 : PRUnichar* p = result.BeginWriting();
441 0 : if (ordinal < 0) {
442 : // skip the leading '-'
443 0 : ++p;
444 : }
445 0 : for(; nsnull != *p ; p++)
446 0 : *p += diff;
447 0 : return true;
448 : }
449 0 : static bool TamilToText(PRInt32 ordinal, nsString& result)
450 : {
451 0 : PRUnichar diff = 0x0BE6 - PRUnichar('0');
452 0 : DecimalToText(ordinal, result);
453 0 : if (ordinal < 1 || ordinal > 9999) {
454 : // Can't do those in this system.
455 0 : return false;
456 : }
457 0 : PRUnichar* p = result.BeginWriting();
458 0 : for(; nsnull != *p ; p++)
459 0 : if(*p != PRUnichar('0'))
460 0 : *p += diff;
461 0 : return true;
462 : }
463 :
464 :
465 : static const char gLowerRomanCharsA[] = "ixcm";
466 : static const char gUpperRomanCharsA[] = "IXCM";
467 : static const char gLowerRomanCharsB[] = "vld";
468 : static const char gUpperRomanCharsB[] = "VLD";
469 :
470 0 : static bool RomanToText(PRInt32 ordinal, nsString& result, const char* achars, const char* bchars)
471 : {
472 0 : if (ordinal < 1 || ordinal > 3999) {
473 0 : DecimalToText(ordinal, result);
474 0 : return false;
475 : }
476 0 : nsAutoString addOn, decStr;
477 0 : decStr.AppendInt(ordinal, 10);
478 0 : PRIntn len = decStr.Length();
479 0 : const PRUnichar* dp = decStr.get();
480 0 : const PRUnichar* end = dp + len;
481 0 : PRIntn romanPos = len;
482 : PRIntn n;
483 :
484 0 : for (; dp < end; dp++) {
485 0 : romanPos--;
486 0 : addOn.SetLength(0);
487 0 : switch(*dp) {
488 : case '3':
489 0 : addOn.Append(PRUnichar(achars[romanPos]));
490 : // FALLTHROUGH
491 : case '2':
492 0 : addOn.Append(PRUnichar(achars[romanPos]));
493 : // FALLTHROUGH
494 : case '1':
495 0 : addOn.Append(PRUnichar(achars[romanPos]));
496 0 : break;
497 : case '4':
498 0 : addOn.Append(PRUnichar(achars[romanPos]));
499 : // FALLTHROUGH
500 : case '5': case '6':
501 : case '7': case '8':
502 0 : addOn.Append(PRUnichar(bchars[romanPos]));
503 0 : for(n=0;'5'+n<*dp;n++) {
504 0 : addOn.Append(PRUnichar(achars[romanPos]));
505 : }
506 0 : break;
507 : case '9':
508 0 : addOn.Append(PRUnichar(achars[romanPos]));
509 0 : addOn.Append(PRUnichar(achars[romanPos+1]));
510 0 : break;
511 : default:
512 0 : break;
513 : }
514 0 : result.Append(addOn);
515 : }
516 0 : return true;
517 : }
518 :
519 : #define ALPHA_SIZE 26
520 : static const PRUnichar gLowerAlphaChars[ALPHA_SIZE] =
521 : {
522 : 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, // A B C D E
523 : 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, // F G H I J
524 : 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, // K L M N O
525 : 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, // P Q R S T
526 : 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, // U V W X Y
527 : 0x007A // Z
528 : };
529 :
530 : static const PRUnichar gUpperAlphaChars[ALPHA_SIZE] =
531 : {
532 : 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, // A B C D E
533 : 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, // F G H I J
534 : 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, // K L M N O
535 : 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, // P Q R S T
536 : 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, // U V W X Y
537 : 0x005A // Z
538 : };
539 :
540 :
541 : #define KATAKANA_CHARS_SIZE 48
542 : // Page 94 Writing Systems of The World
543 : // after modification by momoi
544 : static const PRUnichar gKatakanaChars[KATAKANA_CHARS_SIZE] =
545 : {
546 : 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, // a i u e o
547 : 0x30AB, 0x30AD, 0x30AF, 0x30B1, 0x30B3, // ka ki ku ke ko
548 : 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD, // sa shi su se so
549 : 0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, // ta chi tsu te to
550 : 0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, // na ni nu ne no
551 : 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, // ha hi hu he ho
552 : 0x30DE, 0x30DF, 0x30E0, 0x30E1, 0x30E2, // ma mi mu me mo
553 : 0x30E4, 0x30E6, 0x30E8, // ya yu yo
554 : 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, // ra ri ru re ro
555 : 0x30EF, 0x30F0, 0x30F1, 0x30F2, // wa (w)i (w)e (w)o
556 : 0x30F3 // n
557 : };
558 :
559 : #define HIRAGANA_CHARS_SIZE 48
560 : static const PRUnichar gHiraganaChars[HIRAGANA_CHARS_SIZE] =
561 : {
562 : 0x3042, 0x3044, 0x3046, 0x3048, 0x304A, // a i u e o
563 : 0x304B, 0x304D, 0x304F, 0x3051, 0x3053, // ka ki ku ke ko
564 : 0x3055, 0x3057, 0x3059, 0x305B, 0x305D, // sa shi su se so
565 : 0x305F, 0x3061, 0x3064, 0x3066, 0x3068, // ta chi tsu te to
566 : 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, // na ni nu ne no
567 : 0x306F, 0x3072, 0x3075, 0x3078, 0x307B, // ha hi hu he ho
568 : 0x307E, 0x307F, 0x3080, 0x3081, 0x3082, // ma mi mu me mo
569 : 0x3084, 0x3086, 0x3088, // ya yu yo
570 : 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, // ra ri ru re ro
571 : 0x308F, 0x3090, 0x3091, 0x3092, // wa (w)i (w)e (w)o
572 : 0x3093 // n
573 : };
574 :
575 :
576 : #define HIRAGANA_IROHA_CHARS_SIZE 47
577 : // Page 94 Writing Systems of The World
578 : static const PRUnichar gHiraganaIrohaChars[HIRAGANA_IROHA_CHARS_SIZE] =
579 : {
580 : 0x3044, 0x308D, 0x306F, 0x306B, 0x307B, // i ro ha ni ho
581 : 0x3078, 0x3068, 0x3061, 0x308A, 0x306C, // he to chi ri nu
582 : 0x308B, 0x3092, 0x308F, 0x304B, 0x3088, // ru (w)o wa ka yo
583 : 0x305F, 0x308C, 0x305D, 0x3064, 0x306D, // ta re so tsu ne
584 : 0x306A, 0x3089, 0x3080, 0x3046, 0x3090, // na ra mu u (w)i
585 : 0x306E, 0x304A, 0x304F, 0x3084, 0x307E, // no o ku ya ma
586 : 0x3051, 0x3075, 0x3053, 0x3048, 0x3066, // ke hu ko e te
587 : 0x3042, 0x3055, 0x304D, 0x3086, 0x3081, // a sa ki yu me
588 : 0x307F, 0x3057, 0x3091, 0x3072, 0x3082, // mi shi (w)e hi mo
589 : 0x305B, 0x3059 // se su
590 : };
591 :
592 : #define KATAKANA_IROHA_CHARS_SIZE 47
593 : static const PRUnichar gKatakanaIrohaChars[KATAKANA_IROHA_CHARS_SIZE] =
594 : {
595 : 0x30A4, 0x30ED, 0x30CF, 0x30CB, 0x30DB, // i ro ha ni ho
596 : 0x30D8, 0x30C8, 0x30C1, 0x30EA, 0x30CC, // he to chi ri nu
597 : 0x30EB, 0x30F2, 0x30EF, 0x30AB, 0x30E8, // ru (w)o wa ka yo
598 : 0x30BF, 0x30EC, 0x30BD, 0x30C4, 0x30CD, // ta re so tsu ne
599 : 0x30CA, 0x30E9, 0x30E0, 0x30A6, 0x30F0, // na ra mu u (w)i
600 : 0x30CE, 0x30AA, 0x30AF, 0x30E4, 0x30DE, // no o ku ya ma
601 : 0x30B1, 0x30D5, 0x30B3, 0x30A8, 0x30C6, // ke hu ko e te
602 : 0x30A2, 0x30B5, 0x30AD, 0x30E6, 0x30E1, // a sa ki yu me
603 : 0x30DF, 0x30B7, 0x30F1, 0x30D2, 0x30E2, // mi shi (w)e hi mo
604 : 0x30BB, 0x30B9 // se su
605 : };
606 :
607 : #define LOWER_GREEK_CHARS_SIZE 24
608 : // Note: 0x03C2 GREEK FINAL SIGMA is not used in here....
609 : static const PRUnichar gLowerGreekChars[LOWER_GREEK_CHARS_SIZE] =
610 : {
611 : 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, // alpha beta gamma delta epsilon
612 : 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, // zeta eta theta iota kappa
613 : 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, // lamda mu nu xi omicron
614 : 0x03C0, 0x03C1, 0x03C3, 0x03C4, 0x03C5, // pi rho sigma tau upsilon
615 : 0x03C6, 0x03C7, 0x03C8, 0x03C9 // phi chi psi omega
616 : };
617 :
618 : #define CJK_HEAVENLY_STEM_CHARS_SIZE 10
619 : static const PRUnichar gCJKHeavenlyStemChars[CJK_HEAVENLY_STEM_CHARS_SIZE] =
620 : {
621 : 0x7532, 0x4e59, 0x4e19, 0x4e01, 0x620a,
622 : 0x5df1, 0x5e9a, 0x8f9b, 0x58ec, 0x7678
623 : };
624 : #define CJK_EARTHLY_BRANCH_CHARS_SIZE 12
625 : static const PRUnichar gCJKEarthlyBranchChars[CJK_EARTHLY_BRANCH_CHARS_SIZE] =
626 : {
627 : 0x5b50, 0x4e11, 0x5bc5, 0x536f, 0x8fb0, 0x5df3,
628 : 0x5348, 0x672a, 0x7533, 0x9149, 0x620c, 0x4ea5
629 : };
630 : #define HANGUL_CHARS_SIZE 14
631 : static const PRUnichar gHangulChars[HANGUL_CHARS_SIZE] =
632 : {
633 : 0xac00, 0xb098, 0xb2e4, 0xb77c, 0xb9c8, 0xbc14,
634 : 0xc0ac, 0xc544, 0xc790, 0xcc28, 0xce74, 0xd0c0,
635 : 0xd30c, 0xd558
636 : };
637 : #define HANGUL_CONSONANT_CHARS_SIZE 14
638 : static const PRUnichar gHangulConsonantChars[HANGUL_CONSONANT_CHARS_SIZE] =
639 : {
640 : 0x3131, 0x3134, 0x3137, 0x3139, 0x3141, 0x3142,
641 : 0x3145, 0x3147, 0x3148, 0x314a, 0x314b, 0x314c,
642 : 0x314d, 0x314e
643 : };
644 :
645 : // Ge'ez set of Ethiopic ordered list. There are other locale-dependent sets.
646 : // For the time being, let's implement two Ge'ez sets only
647 : // per Momoi san's suggestion in bug 102252.
648 : // For details, refer to http://www.ethiopic.org/Collation/OrderedLists.html.
649 : #define ETHIOPIC_HALEHAME_CHARS_SIZE 26
650 : static const PRUnichar gEthiopicHalehameChars[ETHIOPIC_HALEHAME_CHARS_SIZE] =
651 : {
652 : 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228,
653 : 0x1230, 0x1240, 0x1260, 0x1270, 0x1280, 0x1290,
654 : 0x12a0, 0x12a8, 0x12c8, 0x12d0, 0x12d8, 0x12e8,
655 : 0x12f0, 0x1308, 0x1320, 0x1330, 0x1338, 0x1340,
656 : 0x1348, 0x1350
657 : };
658 : #define ETHIOPIC_HALEHAME_AM_CHARS_SIZE 33
659 : static const PRUnichar gEthiopicHalehameAmChars[ETHIOPIC_HALEHAME_AM_CHARS_SIZE] =
660 : {
661 : 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228,
662 : 0x1230, 0x1238, 0x1240, 0x1260, 0x1270, 0x1278,
663 : 0x1280, 0x1290, 0x1298, 0x12a0, 0x12a8, 0x12b8,
664 : 0x12c8, 0x12d0, 0x12d8, 0x12e0, 0x12e8, 0x12f0,
665 : 0x1300, 0x1308, 0x1320, 0x1328, 0x1330, 0x1338,
666 : 0x1340, 0x1348, 0x1350
667 : };
668 : #define ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE 31
669 : static const PRUnichar gEthiopicHalehameTiErChars[ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE] =
670 : {
671 : 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230,
672 : 0x1238, 0x1240, 0x1250, 0x1260, 0x1270, 0x1278,
673 : 0x1290, 0x1298, 0x12a0, 0x12a8, 0x12b8, 0x12c8,
674 : 0x12d0, 0x12d8, 0x12e0, 0x12e8, 0x12f0, 0x1300,
675 : 0x1308, 0x1320, 0x1328, 0x1330, 0x1338, 0x1348,
676 : 0x1350
677 : };
678 : #define ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE 34
679 : static const PRUnichar gEthiopicHalehameTiEtChars[ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE] =
680 : {
681 : 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228,
682 : 0x1230, 0x1238, 0x1240, 0x1250, 0x1260, 0x1270,
683 : 0x1278, 0x1280, 0x1290, 0x1298, 0x12a0, 0x12a8,
684 : 0x12b8, 0x12c8, 0x12d0, 0x12d8, 0x12e0, 0x12e8,
685 : 0x12f0, 0x1300, 0x1308, 0x1320, 0x1328, 0x1330,
686 : 0x1338, 0x1340, 0x1348, 0x1350
687 : };
688 :
689 :
690 : // We know cjk-ideographic need 31 characters to display 99,999,999,999,999,999
691 : // georgian needs 6 at most
692 : // armenian needs 12 at most
693 : // hebrew may need more...
694 :
695 : #define NUM_BUF_SIZE 34
696 :
697 0 : static bool CharListToText(PRInt32 ordinal, nsString& result, const PRUnichar* chars, PRInt32 aBase)
698 : {
699 : PRUnichar buf[NUM_BUF_SIZE];
700 0 : PRInt32 idx = NUM_BUF_SIZE;
701 0 : if (ordinal < 1) {
702 0 : DecimalToText(ordinal, result);
703 0 : return false;
704 : }
705 0 : do {
706 0 : ordinal--; // a == 0
707 0 : PRInt32 cur = ordinal % aBase;
708 0 : buf[--idx] = chars[cur];
709 0 : ordinal /= aBase ;
710 : } while ( ordinal > 0);
711 0 : result.Append(buf+idx,NUM_BUF_SIZE-idx);
712 0 : return true;
713 : }
714 :
715 :
716 : static const PRUnichar gCJKIdeographicDigit1[10] =
717 : {
718 : 0x96f6, 0x4e00, 0x4e8c, 0x4e09, 0x56db, // 0 - 4
719 : 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d // 5 - 9
720 : };
721 : static const PRUnichar gCJKIdeographicDigit2[10] =
722 : {
723 : 0x96f6, 0x58f9, 0x8cb3, 0x53c3, 0x8086, // 0 - 4
724 : 0x4f0d, 0x9678, 0x67d2, 0x634c, 0x7396 // 5 - 9
725 : };
726 : static const PRUnichar gCJKIdeographicDigit3[10] =
727 : {
728 : 0x96f6, 0x58f9, 0x8d30, 0x53c1, 0x8086, // 0 - 4
729 : 0x4f0d, 0x9646, 0x67d2, 0x634c, 0x7396 // 5 - 9
730 : };
731 : static const PRUnichar gCJKIdeographicUnit1[4] =
732 : {
733 : 0x000, 0x5341, 0x767e, 0x5343
734 : };
735 : static const PRUnichar gCJKIdeographicUnit2[4] =
736 : {
737 : 0x000, 0x62FE, 0x4F70, 0x4EDF
738 : };
739 : static const PRUnichar gCJKIdeographic10KUnit1[4] =
740 : {
741 : 0x000, 0x842c, 0x5104, 0x5146
742 : };
743 : static const PRUnichar gCJKIdeographic10KUnit2[4] =
744 : {
745 : 0x000, 0x4E07, 0x4ebf, 0x5146
746 : };
747 : static const PRUnichar gCJKIdeographic10KUnit3[4] =
748 : {
749 : 0x000, 0x4E07, 0x5104, 0x5146
750 : };
751 :
752 0 : static const bool CJKIdeographicToText(PRInt32 ordinal, nsString& result,
753 : const PRUnichar* digits,
754 : const PRUnichar *unit,
755 : const PRUnichar* unit10k)
756 : {
757 : // In theory, we need the following if condiction,
758 : // However, the limit, 10 ^ 16, is greater than the max of PRUint32
759 : // so we don't really need to test it here.
760 : // if( ordinal > 9999999999999999)
761 : // {
762 : // PR_snprintf(cbuf, sizeof(cbuf), "%ld", ordinal);
763 : // result.Append(cbuf);
764 : // }
765 : // else
766 : // {
767 0 : if (ordinal < 0) {
768 0 : DecimalToText(ordinal, result);
769 0 : return false;
770 : }
771 0 : PRUnichar c10kUnit = 0;
772 0 : PRUnichar cUnit = 0;
773 0 : PRUnichar cDigit = 0;
774 0 : PRUint32 ud = 0;
775 : PRUnichar buf[NUM_BUF_SIZE];
776 0 : PRInt32 idx = NUM_BUF_SIZE;
777 0 : bool bOutputZero = ( 0 == ordinal );
778 0 : do {
779 0 : if(0 == (ud % 4)) {
780 0 : c10kUnit = unit10k[ud/4];
781 : }
782 0 : PRInt32 cur = ordinal % 10;
783 0 : cDigit = digits[cur];
784 0 : if( 0 == cur)
785 : {
786 0 : cUnit = 0;
787 0 : if(bOutputZero) {
788 0 : bOutputZero = false;
789 0 : if(0 != cDigit)
790 0 : buf[--idx] = cDigit;
791 : }
792 : }
793 : else
794 : {
795 0 : bOutputZero = true;
796 0 : cUnit = unit[ud%4];
797 :
798 0 : if(0 != c10kUnit)
799 0 : buf[--idx] = c10kUnit;
800 0 : if(0 != cUnit)
801 0 : buf[--idx] = cUnit;
802 0 : if((0 != cDigit) &&
803 : ( (1 != cur) || (1 != (ud%4)) || ( ordinal > 10)) )
804 0 : buf[--idx] = cDigit;
805 :
806 0 : c10kUnit = 0;
807 : }
808 0 : ordinal /= 10;
809 0 : ++ud;
810 :
811 : } while( ordinal > 0);
812 0 : result.Append(buf+idx,NUM_BUF_SIZE-idx);
813 : // }
814 0 : return true;
815 : }
816 :
817 : #define HEBREW_GERESH 0x05F3
818 : static const PRUnichar gHebrewDigit[22] =
819 : {
820 : // 1 2 3 4 5 6 7 8 9
821 : 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8,
822 : // 10 20 30 40 50 60 70 80 90
823 : 0x05D9, 0x05DB, 0x05DC, 0x05DE, 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6,
824 : // 100 200 300 400
825 : 0x05E7, 0x05E8, 0x05E9, 0x05EA
826 : };
827 :
828 0 : static bool HebrewToText(PRInt32 ordinal, nsString& result)
829 : {
830 0 : if (ordinal < 1 || ordinal > 999999) {
831 0 : DecimalToText(ordinal, result);
832 0 : return false;
833 : }
834 0 : bool outputSep = false;
835 0 : nsAutoString allText, thousandsGroup;
836 0 : do {
837 0 : thousandsGroup.Truncate();
838 0 : PRInt32 n3 = ordinal % 1000;
839 : // Process digit for 100 - 900
840 0 : for(PRInt32 n1 = 400; n1 > 0; )
841 : {
842 0 : if( n3 >= n1)
843 : {
844 0 : n3 -= n1;
845 0 : thousandsGroup.Append(gHebrewDigit[(n1/100)-1+18]);
846 : } else {
847 0 : n1 -= 100;
848 : } // if
849 : } // for
850 :
851 : // Process digit for 10 - 90
852 : PRInt32 n2;
853 0 : if( n3 >= 10 )
854 : {
855 : // Special process for 15 and 16
856 0 : if(( 15 == n3 ) || (16 == n3)) {
857 : // Special rule for religious reason...
858 : // 15 is represented by 9 and 6, not 10 and 5
859 : // 16 is represented by 9 and 7, not 10 and 6
860 0 : n2 = 9;
861 0 : thousandsGroup.Append(gHebrewDigit[ n2 - 1]);
862 : } else {
863 0 : n2 = n3 - (n3 % 10);
864 0 : thousandsGroup.Append(gHebrewDigit[(n2/10)-1+9]);
865 : } // if
866 0 : n3 -= n2;
867 : } // if
868 :
869 : // Process digit for 1 - 9
870 0 : if ( n3 > 0)
871 0 : thousandsGroup.Append(gHebrewDigit[n3-1]);
872 0 : if (outputSep)
873 0 : thousandsGroup.Append((PRUnichar)HEBREW_GERESH);
874 0 : if (allText.IsEmpty())
875 0 : allText = thousandsGroup;
876 : else
877 0 : allText = thousandsGroup + allText;
878 0 : ordinal /= 1000;
879 0 : outputSep = true;
880 : } while (ordinal >= 1);
881 :
882 0 : result.Append(allText);
883 0 : return true;
884 : }
885 :
886 :
887 0 : static bool ArmenianToText(PRInt32 ordinal, nsString& result)
888 : {
889 0 : if (ordinal < 1 || ordinal > 9999) { // zero or reach the limit of Armenian numbering system
890 0 : DecimalToText(ordinal, result);
891 0 : return false;
892 : }
893 :
894 : PRUnichar buf[NUM_BUF_SIZE];
895 0 : PRInt32 idx = NUM_BUF_SIZE;
896 0 : PRInt32 d = 0;
897 0 : do {
898 0 : PRInt32 cur = ordinal % 10;
899 0 : if (cur > 0)
900 : {
901 0 : PRUnichar u = 0x0530 + (d * 9) + cur;
902 0 : buf[--idx] = u;
903 : }
904 0 : ++d;
905 0 : ordinal /= 10;
906 : } while (ordinal > 0);
907 0 : result.Append(buf + idx, NUM_BUF_SIZE - idx);
908 0 : return true;
909 : }
910 :
911 :
912 : static const PRUnichar gGeorgianValue [ 37 ] = { // 4 * 9 + 1 = 37
913 : // 1 2 3 4 5 6 7 8 9
914 : 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10F1, 0x10D7,
915 : // 10 20 30 40 50 60 70 80 90
916 : 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10F2, 0x10DD, 0x10DE, 0x10DF,
917 : // 100 200 300 400 500 600 700 800 900
918 : 0x10E0, 0x10E1, 0x10E2, 0x10F3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8,
919 : // 1000 2000 3000 4000 5000 6000 7000 8000 9000
920 : 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10F4, 0x10EF, 0x10F0,
921 : // 10000
922 : 0x10F5
923 : };
924 0 : static bool GeorgianToText(PRInt32 ordinal, nsString& result)
925 : {
926 0 : if (ordinal < 1 || ordinal > 19999) { // zero or reach the limit of Georgian numbering system
927 0 : DecimalToText(ordinal, result);
928 0 : return false;
929 : }
930 :
931 : PRUnichar buf[NUM_BUF_SIZE];
932 0 : PRInt32 idx = NUM_BUF_SIZE;
933 0 : PRInt32 d = 0;
934 0 : do {
935 0 : PRInt32 cur = ordinal % 10;
936 0 : if (cur > 0)
937 : {
938 0 : PRUnichar u = gGeorgianValue[(d * 9 ) + ( cur - 1)];
939 0 : buf[--idx] = u;
940 : }
941 0 : ++d;
942 0 : ordinal /= 10;
943 : } while (ordinal > 0);
944 0 : result.Append(buf + idx, NUM_BUF_SIZE - idx);
945 0 : return true;
946 : }
947 :
948 : // Convert ordinal to Ethiopic numeric representation.
949 : // The detail is available at http://www.ethiopic.org/Numerals/
950 : // The algorithm used here is based on the pseudo-code put up there by
951 : // Daniel Yacob <yacob@geez.org>.
952 : // Another reference is Unicode 3.0 standard section 11.1.
953 : #define ETHIOPIC_ONE 0x1369
954 : #define ETHIOPIC_TEN 0x1372
955 : #define ETHIOPIC_HUNDRED 0x137B
956 : #define ETHIOPIC_TEN_THOUSAND 0x137C
957 :
958 0 : static bool EthiopicToText(PRInt32 ordinal, nsString& result)
959 : {
960 0 : nsAutoString asciiNumberString; // decimal string representation of ordinal
961 0 : DecimalToText(ordinal, asciiNumberString);
962 0 : if (ordinal < 1) {
963 0 : result.Append(asciiNumberString);
964 0 : return false;
965 : }
966 0 : PRUint8 asciiStringLength = asciiNumberString.Length();
967 :
968 : // If number length is odd, add a leading "0"
969 : // the leading "0" preconditions the string to always have the
970 : // leading tens place populated, this avoids a check within the loop.
971 : // If we didn't add the leading "0", decrement asciiStringLength so
972 : // it will be equivalent to a zero-based index in both cases.
973 0 : if (asciiStringLength & 1) {
974 0 : asciiNumberString.Insert(NS_LITERAL_STRING("0"), 0);
975 : } else {
976 0 : asciiStringLength--;
977 : }
978 :
979 : // Iterate from the highest digits to lowest
980 : // indexFromLeft indexes digits (0 = most significant)
981 : // groupIndexFromRight indexes pairs of digits (0 = least significant)
982 0 : for (PRUint8 indexFromLeft = 0, groupIndexFromRight = asciiStringLength >> 1;
983 : indexFromLeft <= asciiStringLength;
984 : indexFromLeft += 2, groupIndexFromRight--) {
985 0 : PRUint8 tensValue = asciiNumberString.CharAt(indexFromLeft) & 0x0F;
986 0 : PRUint8 unitsValue = asciiNumberString.CharAt(indexFromLeft + 1) & 0x0F;
987 0 : PRUint8 groupValue = tensValue * 10 + unitsValue;
988 :
989 0 : bool oddGroup = (groupIndexFromRight & 1);
990 :
991 : // we want to clear ETHIOPIC_ONE when it is superfluous
992 0 : if (ordinal > 1 &&
993 : groupValue == 1 && // one without a leading ten
994 : (oddGroup || indexFromLeft == 0)) { // preceding (100) or leading the sequence
995 0 : unitsValue = 0;
996 : }
997 :
998 : // put it all together...
999 0 : if (tensValue) {
1000 : // map onto Ethiopic "tens":
1001 0 : result.Append((PRUnichar) (tensValue + ETHIOPIC_TEN - 1));
1002 : }
1003 0 : if (unitsValue) {
1004 : //map onto Ethiopic "units":
1005 0 : result.Append((PRUnichar) (unitsValue + ETHIOPIC_ONE - 1));
1006 : }
1007 : // Add a separator for all even groups except the last,
1008 : // and for odd groups with non-zero value.
1009 0 : if (oddGroup) {
1010 0 : if (groupValue) {
1011 0 : result.Append((PRUnichar) ETHIOPIC_HUNDRED);
1012 : }
1013 : } else {
1014 0 : if (groupIndexFromRight) {
1015 0 : result.Append((PRUnichar) ETHIOPIC_TEN_THOUSAND);
1016 : }
1017 : }
1018 : }
1019 0 : return true;
1020 : }
1021 :
1022 :
1023 : /* static */ bool
1024 0 : nsBulletFrame::AppendCounterText(PRInt32 aListStyleType,
1025 : PRInt32 aOrdinal,
1026 : nsString& result)
1027 : {
1028 0 : bool success = true;
1029 :
1030 0 : switch (aListStyleType) {
1031 : case NS_STYLE_LIST_STYLE_NONE: // used by counters code only
1032 0 : break;
1033 :
1034 : case NS_STYLE_LIST_STYLE_DISC: // used by counters code only
1035 : // XXX We really need to do this the same way we do list bullets.
1036 0 : result.Append(PRUnichar(0x2022));
1037 0 : break;
1038 :
1039 : case NS_STYLE_LIST_STYLE_CIRCLE: // used by counters code only
1040 : // XXX We really need to do this the same way we do list bullets.
1041 0 : result.Append(PRUnichar(0x25E6));
1042 0 : break;
1043 :
1044 : case NS_STYLE_LIST_STYLE_SQUARE: // used by counters code only
1045 : // XXX We really need to do this the same way we do list bullets.
1046 0 : result.Append(PRUnichar(0x25FE));
1047 0 : break;
1048 :
1049 : case NS_STYLE_LIST_STYLE_DECIMAL:
1050 : default: // CSS2 say "A users agent that does not recognize a numbering system
1051 : // should use 'decimal'
1052 0 : success = DecimalToText(aOrdinal, result);
1053 0 : break;
1054 :
1055 : case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO:
1056 0 : success = DecimalLeadingZeroToText(aOrdinal, result);
1057 0 : break;
1058 :
1059 : case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
1060 : success = RomanToText(aOrdinal, result,
1061 0 : gLowerRomanCharsA, gLowerRomanCharsB);
1062 0 : break;
1063 : case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
1064 : success = RomanToText(aOrdinal, result,
1065 0 : gUpperRomanCharsA, gUpperRomanCharsB);
1066 0 : break;
1067 :
1068 : case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
1069 0 : success = CharListToText(aOrdinal, result, gLowerAlphaChars, ALPHA_SIZE);
1070 0 : break;
1071 :
1072 : case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
1073 0 : success = CharListToText(aOrdinal, result, gUpperAlphaChars, ALPHA_SIZE);
1074 0 : break;
1075 :
1076 : case NS_STYLE_LIST_STYLE_KATAKANA:
1077 : success = CharListToText(aOrdinal, result, gKatakanaChars,
1078 0 : KATAKANA_CHARS_SIZE);
1079 0 : break;
1080 :
1081 : case NS_STYLE_LIST_STYLE_HIRAGANA:
1082 : success = CharListToText(aOrdinal, result, gHiraganaChars,
1083 0 : HIRAGANA_CHARS_SIZE);
1084 0 : break;
1085 :
1086 : case NS_STYLE_LIST_STYLE_KATAKANA_IROHA:
1087 : success = CharListToText(aOrdinal, result, gKatakanaIrohaChars,
1088 0 : KATAKANA_IROHA_CHARS_SIZE);
1089 0 : break;
1090 :
1091 : case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA:
1092 : success = CharListToText(aOrdinal, result, gHiraganaIrohaChars,
1093 0 : HIRAGANA_IROHA_CHARS_SIZE);
1094 0 : break;
1095 :
1096 : case NS_STYLE_LIST_STYLE_LOWER_GREEK:
1097 : success = CharListToText(aOrdinal, result, gLowerGreekChars ,
1098 0 : LOWER_GREEK_CHARS_SIZE);
1099 0 : break;
1100 :
1101 : case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC:
1102 : case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL:
1103 : success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1,
1104 : gCJKIdeographicUnit1,
1105 0 : gCJKIdeographic10KUnit1);
1106 0 : break;
1107 :
1108 : case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL:
1109 : success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit2,
1110 : gCJKIdeographicUnit2,
1111 0 : gCJKIdeographic10KUnit1);
1112 0 : break;
1113 :
1114 : case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL:
1115 : success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1,
1116 : gCJKIdeographicUnit1,
1117 0 : gCJKIdeographic10KUnit2);
1118 0 : break;
1119 :
1120 : case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL:
1121 : success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit3,
1122 : gCJKIdeographicUnit2,
1123 0 : gCJKIdeographic10KUnit2);
1124 0 : break;
1125 :
1126 : case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL:
1127 : success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1,
1128 : gCJKIdeographicUnit1,
1129 0 : gCJKIdeographic10KUnit3);
1130 0 : break;
1131 :
1132 : case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL:
1133 : success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit2,
1134 : gCJKIdeographicUnit2,
1135 0 : gCJKIdeographic10KUnit3);
1136 0 : break;
1137 :
1138 : case NS_STYLE_LIST_STYLE_HEBREW:
1139 0 : success = HebrewToText(aOrdinal, result);
1140 0 : break;
1141 :
1142 : case NS_STYLE_LIST_STYLE_ARMENIAN:
1143 0 : success = ArmenianToText(aOrdinal, result);
1144 0 : break;
1145 :
1146 : case NS_STYLE_LIST_STYLE_GEORGIAN:
1147 0 : success = GeorgianToText(aOrdinal, result);
1148 0 : break;
1149 :
1150 : case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC:
1151 0 : success = OtherDecimalToText(aOrdinal, 0x0660, result);
1152 0 : break;
1153 :
1154 : case NS_STYLE_LIST_STYLE_MOZ_PERSIAN:
1155 : case NS_STYLE_LIST_STYLE_MOZ_URDU:
1156 0 : success = OtherDecimalToText(aOrdinal, 0x06f0, result);
1157 0 : break;
1158 :
1159 : case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI:
1160 0 : success = OtherDecimalToText(aOrdinal, 0x0966, result);
1161 0 : break;
1162 :
1163 : case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI:
1164 0 : success = OtherDecimalToText(aOrdinal, 0x0a66, result);
1165 0 : break;
1166 :
1167 : case NS_STYLE_LIST_STYLE_MOZ_GUJARATI:
1168 0 : success = OtherDecimalToText(aOrdinal, 0x0AE6, result);
1169 0 : break;
1170 :
1171 : case NS_STYLE_LIST_STYLE_MOZ_ORIYA:
1172 0 : success = OtherDecimalToText(aOrdinal, 0x0B66, result);
1173 0 : break;
1174 :
1175 : case NS_STYLE_LIST_STYLE_MOZ_KANNADA:
1176 0 : success = OtherDecimalToText(aOrdinal, 0x0CE6, result);
1177 0 : break;
1178 :
1179 : case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM:
1180 0 : success = OtherDecimalToText(aOrdinal, 0x0D66, result);
1181 0 : break;
1182 :
1183 : case NS_STYLE_LIST_STYLE_MOZ_THAI:
1184 0 : success = OtherDecimalToText(aOrdinal, 0x0E50, result);
1185 0 : break;
1186 :
1187 : case NS_STYLE_LIST_STYLE_MOZ_LAO:
1188 0 : success = OtherDecimalToText(aOrdinal, 0x0ED0, result);
1189 0 : break;
1190 :
1191 : case NS_STYLE_LIST_STYLE_MOZ_MYANMAR:
1192 0 : success = OtherDecimalToText(aOrdinal, 0x1040, result);
1193 0 : break;
1194 :
1195 : case NS_STYLE_LIST_STYLE_MOZ_KHMER:
1196 0 : success = OtherDecimalToText(aOrdinal, 0x17E0, result);
1197 0 : break;
1198 :
1199 : case NS_STYLE_LIST_STYLE_MOZ_BENGALI:
1200 0 : success = OtherDecimalToText(aOrdinal, 0x09E6, result);
1201 0 : break;
1202 :
1203 : case NS_STYLE_LIST_STYLE_MOZ_TELUGU:
1204 0 : success = OtherDecimalToText(aOrdinal, 0x0C66, result);
1205 0 : break;
1206 :
1207 : case NS_STYLE_LIST_STYLE_MOZ_TAMIL:
1208 0 : success = TamilToText(aOrdinal, result);
1209 0 : break;
1210 :
1211 : case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM:
1212 : success = CharListToText(aOrdinal, result, gCJKHeavenlyStemChars,
1213 0 : CJK_HEAVENLY_STEM_CHARS_SIZE);
1214 0 : break;
1215 :
1216 : case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH:
1217 : success = CharListToText(aOrdinal, result, gCJKEarthlyBranchChars,
1218 0 : CJK_EARTHLY_BRANCH_CHARS_SIZE);
1219 0 : break;
1220 :
1221 : case NS_STYLE_LIST_STYLE_MOZ_HANGUL:
1222 0 : success = CharListToText(aOrdinal, result, gHangulChars, HANGUL_CHARS_SIZE);
1223 0 : break;
1224 :
1225 : case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT:
1226 : success = CharListToText(aOrdinal, result, gHangulConsonantChars,
1227 0 : HANGUL_CONSONANT_CHARS_SIZE);
1228 0 : break;
1229 :
1230 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME:
1231 : success = CharListToText(aOrdinal, result, gEthiopicHalehameChars,
1232 0 : ETHIOPIC_HALEHAME_CHARS_SIZE);
1233 0 : break;
1234 :
1235 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC:
1236 0 : success = EthiopicToText(aOrdinal, result);
1237 0 : break;
1238 :
1239 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM:
1240 : success = CharListToText(aOrdinal, result, gEthiopicHalehameAmChars,
1241 0 : ETHIOPIC_HALEHAME_AM_CHARS_SIZE);
1242 0 : break;
1243 :
1244 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER:
1245 : success = CharListToText(aOrdinal, result, gEthiopicHalehameTiErChars,
1246 0 : ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE);
1247 0 : break;
1248 :
1249 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET:
1250 : success = CharListToText(aOrdinal, result, gEthiopicHalehameTiEtChars,
1251 0 : ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE);
1252 0 : break;
1253 : }
1254 0 : return success;
1255 : }
1256 :
1257 : bool
1258 0 : nsBulletFrame::GetListItemText(const nsStyleList& aListStyle,
1259 : nsString& result)
1260 : {
1261 0 : const nsStyleVisibility* vis = GetStyleVisibility();
1262 :
1263 0 : NS_ASSERTION(aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_NONE &&
1264 : aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_DISC &&
1265 : aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_CIRCLE &&
1266 : aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_SQUARE,
1267 : "we should be using specialized code for these types");
1268 : bool success =
1269 0 : AppendCounterText(aListStyle.mListStyleType, mOrdinal, result);
1270 0 : if (success && aListStyle.mListStyleType == NS_STYLE_LIST_STYLE_HEBREW)
1271 0 : mTextIsRTL = true;
1272 :
1273 : // XXX For some of these systems, "." is wrong! This should really be
1274 : // pushed down into the individual cases!
1275 0 : nsString suffix = NS_LITERAL_STRING(".");
1276 :
1277 : // We're not going to do proper Bidi reordering on the list item marker, but
1278 : // just display the whole thing as RTL or LTR, so we fake reordering by
1279 : // appending the suffix to the end of the list item marker if the
1280 : // directionality of the characters is the same as the style direction or
1281 : // prepending it to the beginning if they are different.
1282 : result = (mTextIsRTL == (vis->mDirection == NS_STYLE_DIRECTION_RTL)) ?
1283 0 : result + suffix : suffix + result;
1284 0 : return success;
1285 : }
1286 :
1287 : #define MIN_BULLET_SIZE 1
1288 :
1289 :
1290 : void
1291 0 : nsBulletFrame::GetDesiredSize(nsPresContext* aCX,
1292 : nsRenderingContext *aRenderingContext,
1293 : nsHTMLReflowMetrics& aMetrics,
1294 : float aFontSizeInflation)
1295 : {
1296 : // Reset our padding. If we need it, we'll set it below.
1297 0 : mPadding.SizeTo(0, 0, 0, 0);
1298 :
1299 0 : const nsStyleList* myList = GetStyleList();
1300 : nscoord ascent;
1301 :
1302 0 : RemoveStateBits(BULLET_FRAME_IMAGE_LOADING);
1303 :
1304 0 : if (myList->GetListStyleImage() && mImageRequest) {
1305 : PRUint32 status;
1306 0 : mImageRequest->GetImageStatus(&status);
1307 0 : if (status & imgIRequest::STATUS_SIZE_AVAILABLE &&
1308 0 : !(status & imgIRequest::STATUS_ERROR)) {
1309 : // auto size the image
1310 0 : mComputedSize.width = mIntrinsicSize.width;
1311 0 : mComputedSize.height = mIntrinsicSize.height;
1312 :
1313 0 : aMetrics.width = mComputedSize.width;
1314 0 : aMetrics.ascent = aMetrics.height = mComputedSize.height;
1315 :
1316 0 : AddStateBits(BULLET_FRAME_IMAGE_LOADING);
1317 :
1318 0 : return;
1319 : }
1320 : }
1321 :
1322 : // If we're getting our desired size and don't have an image, reset
1323 : // mIntrinsicSize to (0,0). Otherwise, if we used to have an image, it
1324 : // changed, and the new one is coming in, but we're reflowing before it's
1325 : // fully there, we'll end up with mIntrinsicSize not matching our size, but
1326 : // won't trigger a reflow in OnStartContainer (because mIntrinsicSize will
1327 : // match the image size).
1328 0 : mIntrinsicSize.SizeTo(0, 0);
1329 :
1330 0 : nsRefPtr<nsFontMetrics> fm;
1331 : nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
1332 0 : aFontSizeInflation);
1333 : nscoord bulletSize;
1334 :
1335 0 : nsAutoString text;
1336 0 : switch (myList->mListStyleType) {
1337 : case NS_STYLE_LIST_STYLE_NONE:
1338 0 : aMetrics.width = 0;
1339 0 : aMetrics.ascent = aMetrics.height = 0;
1340 0 : break;
1341 :
1342 : case NS_STYLE_LIST_STYLE_DISC:
1343 : case NS_STYLE_LIST_STYLE_CIRCLE:
1344 : case NS_STYLE_LIST_STYLE_SQUARE:
1345 0 : ascent = fm->MaxAscent();
1346 0 : bulletSize = NS_MAX(nsPresContext::CSSPixelsToAppUnits(MIN_BULLET_SIZE),
1347 0 : NSToCoordRound(0.8f * (float(ascent) / 2.0f)));
1348 0 : mPadding.bottom = NSToCoordRound(float(ascent) / 8.0f);
1349 0 : aMetrics.width = mPadding.right + bulletSize;
1350 0 : aMetrics.ascent = aMetrics.height = mPadding.bottom + bulletSize;
1351 0 : break;
1352 :
1353 : default:
1354 : case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO:
1355 : case NS_STYLE_LIST_STYLE_DECIMAL:
1356 : case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
1357 : case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
1358 : case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
1359 : case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
1360 : case NS_STYLE_LIST_STYLE_KATAKANA:
1361 : case NS_STYLE_LIST_STYLE_HIRAGANA:
1362 : case NS_STYLE_LIST_STYLE_KATAKANA_IROHA:
1363 : case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA:
1364 : case NS_STYLE_LIST_STYLE_LOWER_GREEK:
1365 : case NS_STYLE_LIST_STYLE_HEBREW:
1366 : case NS_STYLE_LIST_STYLE_ARMENIAN:
1367 : case NS_STYLE_LIST_STYLE_GEORGIAN:
1368 : case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC:
1369 : case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL:
1370 : case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL:
1371 : case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL:
1372 : case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL:
1373 : case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL:
1374 : case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL:
1375 : case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM:
1376 : case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH:
1377 : case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC:
1378 : case NS_STYLE_LIST_STYLE_MOZ_PERSIAN:
1379 : case NS_STYLE_LIST_STYLE_MOZ_URDU:
1380 : case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI:
1381 : case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI:
1382 : case NS_STYLE_LIST_STYLE_MOZ_GUJARATI:
1383 : case NS_STYLE_LIST_STYLE_MOZ_ORIYA:
1384 : case NS_STYLE_LIST_STYLE_MOZ_KANNADA:
1385 : case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM:
1386 : case NS_STYLE_LIST_STYLE_MOZ_BENGALI:
1387 : case NS_STYLE_LIST_STYLE_MOZ_TAMIL:
1388 : case NS_STYLE_LIST_STYLE_MOZ_TELUGU:
1389 : case NS_STYLE_LIST_STYLE_MOZ_THAI:
1390 : case NS_STYLE_LIST_STYLE_MOZ_LAO:
1391 : case NS_STYLE_LIST_STYLE_MOZ_MYANMAR:
1392 : case NS_STYLE_LIST_STYLE_MOZ_KHMER:
1393 : case NS_STYLE_LIST_STYLE_MOZ_HANGUL:
1394 : case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT:
1395 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME:
1396 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC:
1397 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM:
1398 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER:
1399 : case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET:
1400 0 : GetListItemText(*myList, text);
1401 0 : aMetrics.height = fm->MaxHeight();
1402 0 : aRenderingContext->SetFont(fm);
1403 : aMetrics.width =
1404 : nsLayoutUtils::GetStringWidth(this, aRenderingContext,
1405 0 : text.get(), text.Length());
1406 0 : aMetrics.width += mPadding.right;
1407 0 : aMetrics.ascent = fm->MaxAscent();
1408 0 : break;
1409 : }
1410 : }
1411 :
1412 : NS_IMETHODIMP
1413 0 : nsBulletFrame::Reflow(nsPresContext* aPresContext,
1414 : nsHTMLReflowMetrics& aMetrics,
1415 : const nsHTMLReflowState& aReflowState,
1416 : nsReflowStatus& aStatus)
1417 : {
1418 0 : DO_GLOBAL_REFLOW_COUNT("nsBulletFrame");
1419 0 : DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
1420 :
1421 : float inflation =
1422 0 : nsLayoutUtils::FontSizeInflationFor(this, nsLayoutUtils::eInReflow);
1423 0 : SetFontSizeInflation(inflation);
1424 :
1425 : // Get the base size
1426 0 : GetDesiredSize(aPresContext, aReflowState.rendContext, aMetrics, inflation);
1427 :
1428 : // Add in the border and padding; split the top/bottom between the
1429 : // ascent and descent to make things look nice
1430 0 : const nsMargin& borderPadding = aReflowState.mComputedBorderPadding;
1431 0 : aMetrics.width += borderPadding.left + borderPadding.right;
1432 0 : aMetrics.height += borderPadding.top + borderPadding.bottom;
1433 0 : aMetrics.ascent += borderPadding.top;
1434 :
1435 : // XXX this is a bit of a hack, we're assuming that no glyphs used for bullets
1436 : // overflow their font-boxes. It'll do for now; to fix it for real, we really
1437 : // should rewrite all the text-handling code here to use gfxTextRun (bug
1438 : // 397294).
1439 0 : aMetrics.SetOverflowAreasToDesiredBounds();
1440 :
1441 0 : aStatus = NS_FRAME_COMPLETE;
1442 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
1443 0 : return NS_OK;
1444 : }
1445 :
1446 : /* virtual */ nscoord
1447 0 : nsBulletFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
1448 : {
1449 0 : nsHTMLReflowMetrics metrics;
1450 0 : DISPLAY_MIN_WIDTH(this, metrics.width);
1451 0 : GetDesiredSize(PresContext(), aRenderingContext, metrics, 1.0f);
1452 0 : return metrics.width;
1453 : }
1454 :
1455 : /* virtual */ nscoord
1456 0 : nsBulletFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
1457 : {
1458 0 : nsHTMLReflowMetrics metrics;
1459 0 : DISPLAY_PREF_WIDTH(this, metrics.width);
1460 0 : GetDesiredSize(PresContext(), aRenderingContext, metrics, 1.0f);
1461 0 : return metrics.width;
1462 : }
1463 :
1464 :
1465 0 : NS_IMETHODIMP nsBulletFrame::OnStartContainer(imgIRequest *aRequest,
1466 : imgIContainer *aImage)
1467 : {
1468 0 : if (!aImage) return NS_ERROR_INVALID_ARG;
1469 0 : if (!aRequest) return NS_ERROR_INVALID_ARG;
1470 :
1471 : PRUint32 status;
1472 0 : aRequest->GetImageStatus(&status);
1473 0 : if (status & imgIRequest::STATUS_ERROR) {
1474 0 : return NS_OK;
1475 : }
1476 :
1477 : nscoord w, h;
1478 0 : aImage->GetWidth(&w);
1479 0 : aImage->GetHeight(&h);
1480 :
1481 0 : nsPresContext* presContext = PresContext();
1482 :
1483 : nsSize newsize(nsPresContext::CSSPixelsToAppUnits(w),
1484 0 : nsPresContext::CSSPixelsToAppUnits(h));
1485 :
1486 0 : if (mIntrinsicSize != newsize) {
1487 0 : mIntrinsicSize = newsize;
1488 :
1489 : // Now that the size is available (or an error occurred), trigger
1490 : // a reflow of the bullet frame.
1491 0 : nsIPresShell *shell = presContext->GetPresShell();
1492 0 : if (shell) {
1493 : shell->FrameNeedsReflow(this, nsIPresShell::eStyleChange,
1494 0 : NS_FRAME_IS_DIRTY);
1495 : }
1496 : }
1497 :
1498 : // Handle animations
1499 0 : aImage->SetAnimationMode(presContext->ImageAnimationMode());
1500 : // Ensure the animation (if any) is started. Note: There is no
1501 : // corresponding call to Decrement for this. This Increment will be
1502 : // 'cleaned up' by the Request when it is destroyed, but only then.
1503 0 : aRequest->IncrementAnimationConsumers();
1504 :
1505 0 : return NS_OK;
1506 : }
1507 :
1508 0 : NS_IMETHODIMP nsBulletFrame::OnDataAvailable(imgIRequest *aRequest,
1509 : bool aCurrentFrame,
1510 : const nsIntRect *aRect)
1511 : {
1512 : // The image has changed.
1513 : // Invalidate the entire content area. Maybe it's not optimal but it's simple and
1514 : // always correct, and I'll be a stunned mullet if it ever matters for performance
1515 0 : Invalidate(nsRect(0, 0, mRect.width, mRect.height));
1516 :
1517 0 : return NS_OK;
1518 : }
1519 :
1520 0 : NS_IMETHODIMP nsBulletFrame::OnStopDecode(imgIRequest *aRequest,
1521 : nsresult aStatus,
1522 : const PRUnichar *aStatusArg)
1523 : {
1524 : // XXX should the bulletframe do anything if the image failed to load?
1525 : // it didn't in the old code...
1526 :
1527 : #if 0
1528 : if (NS_FAILED(aStatus)) {
1529 : // We failed to load the image. Notify the pres shell
1530 : if (NS_FAILED(aStatus) && (mImageRequest == aRequest || !mImageRequest)) {
1531 : imageFailed = true;
1532 : }
1533 : }
1534 : #endif
1535 :
1536 0 : return NS_OK;
1537 : }
1538 :
1539 0 : NS_IMETHODIMP nsBulletFrame::OnImageIsAnimated(imgIRequest* aRequest)
1540 : {
1541 : // Register the image request with the refresh driver now that we know it's
1542 : // animated.
1543 0 : if (aRequest == mImageRequest) {
1544 : nsLayoutUtils::RegisterImageRequest(PresContext(), mImageRequest,
1545 0 : &mRequestRegistered);
1546 : }
1547 :
1548 0 : return NS_OK;
1549 : }
1550 :
1551 0 : NS_IMETHODIMP nsBulletFrame::FrameChanged(imgIRequest *aRequest,
1552 : imgIContainer *aContainer,
1553 : const nsIntRect *aDirtyRect)
1554 : {
1555 : // Invalidate the entire content area. Maybe it's not optimal but it's simple and
1556 : // always correct.
1557 0 : Invalidate(nsRect(0, 0, mRect.width, mRect.height));
1558 :
1559 0 : return NS_OK;
1560 : }
1561 :
1562 : void
1563 0 : nsBulletFrame::GetLoadGroup(nsPresContext *aPresContext, nsILoadGroup **aLoadGroup)
1564 : {
1565 0 : if (!aPresContext)
1566 0 : return;
1567 :
1568 0 : NS_PRECONDITION(nsnull != aLoadGroup, "null OUT parameter pointer");
1569 :
1570 0 : nsIPresShell *shell = aPresContext->GetPresShell();
1571 :
1572 0 : if (!shell)
1573 0 : return;
1574 :
1575 0 : nsIDocument *doc = shell->GetDocument();
1576 0 : if (!doc)
1577 0 : return;
1578 :
1579 0 : *aLoadGroup = doc->GetDocumentLoadGroup().get(); // already_AddRefed
1580 : }
1581 :
1582 : union VoidPtrOrFloat {
1583 0 : VoidPtrOrFloat() : p(nsnull) {}
1584 :
1585 : void *p;
1586 : float f;
1587 : };
1588 :
1589 : float
1590 0 : nsBulletFrame::GetFontSizeInflation() const
1591 : {
1592 0 : if (!HasFontSizeInflation()) {
1593 0 : return 1.0f;
1594 : }
1595 0 : VoidPtrOrFloat u;
1596 0 : u.p = Properties().Get(FontSizeInflationProperty());
1597 0 : return u.f;
1598 : }
1599 :
1600 : void
1601 0 : nsBulletFrame::SetFontSizeInflation(float aInflation)
1602 : {
1603 0 : if (aInflation == 1.0f) {
1604 0 : if (HasFontSizeInflation()) {
1605 0 : RemoveStateBits(BULLET_FRAME_HAS_FONT_INFLATION);
1606 0 : Properties().Delete(FontSizeInflationProperty());
1607 : }
1608 0 : return;
1609 : }
1610 :
1611 0 : AddStateBits(BULLET_FRAME_HAS_FONT_INFLATION);
1612 0 : VoidPtrOrFloat u;
1613 0 : u.f = aInflation;
1614 0 : Properties().Set(FontSizeInflationProperty(), u.p);
1615 : }
1616 :
1617 : nscoord
1618 0 : nsBulletFrame::GetBaseline() const
1619 : {
1620 0 : nscoord ascent = 0, bottomPadding;
1621 0 : if (GetStateBits() & BULLET_FRAME_IMAGE_LOADING) {
1622 0 : ascent = GetRect().height;
1623 : } else {
1624 0 : nsRefPtr<nsFontMetrics> fm;
1625 : nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
1626 0 : GetFontSizeInflation());
1627 0 : const nsStyleList* myList = GetStyleList();
1628 0 : switch (myList->mListStyleType) {
1629 : case NS_STYLE_LIST_STYLE_NONE:
1630 0 : break;
1631 :
1632 : case NS_STYLE_LIST_STYLE_DISC:
1633 : case NS_STYLE_LIST_STYLE_CIRCLE:
1634 : case NS_STYLE_LIST_STYLE_SQUARE:
1635 0 : ascent = fm->MaxAscent();
1636 0 : bottomPadding = NSToCoordRound(float(ascent) / 8.0f);
1637 0 : ascent = NS_MAX(nsPresContext::CSSPixelsToAppUnits(MIN_BULLET_SIZE),
1638 0 : NSToCoordRound(0.8f * (float(ascent) / 2.0f)));
1639 0 : ascent += bottomPadding;
1640 0 : break;
1641 :
1642 : default:
1643 0 : ascent = fm->MaxAscent();
1644 0 : break;
1645 : }
1646 : }
1647 0 : return ascent + GetUsedBorderAndPadding().top;
1648 : }
1649 :
1650 :
1651 :
1652 :
1653 :
1654 :
1655 :
1656 :
1657 0 : NS_IMPL_ISUPPORTS2(nsBulletListener, imgIDecoderObserver, imgIContainerObserver)
1658 :
1659 0 : nsBulletListener::nsBulletListener() :
1660 0 : mFrame(nsnull)
1661 : {
1662 0 : }
1663 :
1664 0 : nsBulletListener::~nsBulletListener()
1665 : {
1666 0 : }
1667 :
1668 0 : NS_IMETHODIMP nsBulletListener::OnStartContainer(imgIRequest *aRequest,
1669 : imgIContainer *aImage)
1670 : {
1671 0 : if (!mFrame)
1672 0 : return NS_ERROR_FAILURE;
1673 :
1674 0 : return mFrame->OnStartContainer(aRequest, aImage);
1675 : }
1676 :
1677 0 : NS_IMETHODIMP nsBulletListener::OnDataAvailable(imgIRequest *aRequest,
1678 : bool aCurrentFrame,
1679 : const nsIntRect *aRect)
1680 : {
1681 0 : if (!mFrame)
1682 0 : return NS_OK;
1683 :
1684 0 : return mFrame->OnDataAvailable(aRequest, aCurrentFrame, aRect);
1685 : }
1686 :
1687 0 : NS_IMETHODIMP nsBulletListener::OnStopDecode(imgIRequest *aRequest,
1688 : nsresult status,
1689 : const PRUnichar *statusArg)
1690 : {
1691 0 : if (!mFrame)
1692 0 : return NS_OK;
1693 :
1694 0 : return mFrame->OnStopDecode(aRequest, status, statusArg);
1695 : }
1696 :
1697 0 : NS_IMETHODIMP nsBulletListener::OnImageIsAnimated(imgIRequest *aRequest)
1698 : {
1699 0 : if (!mFrame)
1700 0 : return NS_OK;
1701 :
1702 0 : return mFrame->OnImageIsAnimated(aRequest);
1703 : }
1704 :
1705 0 : NS_IMETHODIMP nsBulletListener::FrameChanged(imgIRequest *aRequest,
1706 : imgIContainer *aContainer,
1707 : const nsIntRect *aDirtyRect)
1708 : {
1709 0 : if (!mFrame)
1710 0 : return NS_OK;
1711 :
1712 0 : return mFrame->FrameChanged(aRequest, aContainer, aDirtyRect);
1713 : }
|