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