1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/generic/nsBulletFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1913 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* rendering object for list-item bullets */ 1.10 + 1.11 +#include "nsBulletFrame.h" 1.12 + 1.13 +#include "mozilla/MathAlgorithms.h" 1.14 +#include "nsCOMPtr.h" 1.15 +#include "nsGkAtoms.h" 1.16 +#include "nsGenericHTMLElement.h" 1.17 +#include "nsAttrValueInlines.h" 1.18 +#include "nsPresContext.h" 1.19 +#include "nsIPresShell.h" 1.20 +#include "nsIDocument.h" 1.21 +#include "nsRenderingContext.h" 1.22 +#include "prprf.h" 1.23 +#include "nsDisplayList.h" 1.24 +#include "nsCounterManager.h" 1.25 + 1.26 +#include "imgIContainer.h" 1.27 +#include "imgRequestProxy.h" 1.28 +#include "nsIURI.h" 1.29 + 1.30 +#include <algorithm> 1.31 + 1.32 +#ifdef ACCESSIBILITY 1.33 +#include "nsAccessibilityService.h" 1.34 +#endif 1.35 + 1.36 +using namespace mozilla; 1.37 + 1.38 +NS_DECLARE_FRAME_PROPERTY(FontSizeInflationProperty, nullptr) 1.39 + 1.40 +NS_IMPL_FRAMEARENA_HELPERS(nsBulletFrame) 1.41 + 1.42 +#ifdef DEBUG 1.43 +NS_QUERYFRAME_HEAD(nsBulletFrame) 1.44 + NS_QUERYFRAME_ENTRY(nsBulletFrame) 1.45 +NS_QUERYFRAME_TAIL_INHERITING(nsFrame) 1.46 +#endif 1.47 + 1.48 +nsBulletFrame::~nsBulletFrame() 1.49 +{ 1.50 +} 1.51 + 1.52 +void 1.53 +nsBulletFrame::DestroyFrom(nsIFrame* aDestructRoot) 1.54 +{ 1.55 + // Stop image loading first 1.56 + if (mImageRequest) { 1.57 + // Deregister our image request from the refresh driver 1.58 + nsLayoutUtils::DeregisterImageRequest(PresContext(), 1.59 + mImageRequest, 1.60 + &mRequestRegistered); 1.61 + mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE); 1.62 + mImageRequest = nullptr; 1.63 + } 1.64 + 1.65 + if (mListener) { 1.66 + mListener->SetFrame(nullptr); 1.67 + } 1.68 + 1.69 + // Let base class do the rest 1.70 + nsFrame::DestroyFrom(aDestructRoot); 1.71 +} 1.72 + 1.73 +#ifdef DEBUG_FRAME_DUMP 1.74 +nsresult 1.75 +nsBulletFrame::GetFrameName(nsAString& aResult) const 1.76 +{ 1.77 + return MakeFrameName(NS_LITERAL_STRING("Bullet"), aResult); 1.78 +} 1.79 +#endif 1.80 + 1.81 +nsIAtom* 1.82 +nsBulletFrame::GetType() const 1.83 +{ 1.84 + return nsGkAtoms::bulletFrame; 1.85 +} 1.86 + 1.87 +bool 1.88 +nsBulletFrame::IsEmpty() 1.89 +{ 1.90 + return IsSelfEmpty(); 1.91 +} 1.92 + 1.93 +bool 1.94 +nsBulletFrame::IsSelfEmpty() 1.95 +{ 1.96 + return StyleList()->mListStyleType == NS_STYLE_LIST_STYLE_NONE; 1.97 +} 1.98 + 1.99 +/* virtual */ void 1.100 +nsBulletFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) 1.101 +{ 1.102 + nsFrame::DidSetStyleContext(aOldStyleContext); 1.103 + 1.104 + imgRequestProxy *newRequest = StyleList()->GetListStyleImage(); 1.105 + 1.106 + if (newRequest) { 1.107 + 1.108 + if (!mListener) { 1.109 + mListener = new nsBulletListener(); 1.110 + mListener->SetFrame(this); 1.111 + } 1.112 + 1.113 + bool needNewRequest = true; 1.114 + 1.115 + if (mImageRequest) { 1.116 + // Reload the image, maybe... 1.117 + nsCOMPtr<nsIURI> oldURI; 1.118 + mImageRequest->GetURI(getter_AddRefs(oldURI)); 1.119 + nsCOMPtr<nsIURI> newURI; 1.120 + newRequest->GetURI(getter_AddRefs(newURI)); 1.121 + if (oldURI && newURI) { 1.122 + bool same; 1.123 + newURI->Equals(oldURI, &same); 1.124 + if (same) { 1.125 + needNewRequest = false; 1.126 + } 1.127 + } 1.128 + } 1.129 + 1.130 + if (needNewRequest) { 1.131 + nsRefPtr<imgRequestProxy> oldRequest = mImageRequest; 1.132 + newRequest->Clone(mListener, getter_AddRefs(mImageRequest)); 1.133 + 1.134 + // Deregister the old request. We wait until after Clone is done in case 1.135 + // the old request and the new request are the same underlying image 1.136 + // accessed via different URLs. 1.137 + if (oldRequest) { 1.138 + nsLayoutUtils::DeregisterImageRequest(PresContext(), oldRequest, 1.139 + &mRequestRegistered); 1.140 + oldRequest->CancelAndForgetObserver(NS_ERROR_FAILURE); 1.141 + oldRequest = nullptr; 1.142 + } 1.143 + 1.144 + // Register the new request. 1.145 + if (mImageRequest) { 1.146 + nsLayoutUtils::RegisterImageRequestIfAnimated(PresContext(), 1.147 + mImageRequest, 1.148 + &mRequestRegistered); 1.149 + } 1.150 + } 1.151 + } else { 1.152 + // No image request on the new style context 1.153 + if (mImageRequest) { 1.154 + nsLayoutUtils::DeregisterImageRequest(PresContext(), mImageRequest, 1.155 + &mRequestRegistered); 1.156 + 1.157 + mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE); 1.158 + mImageRequest = nullptr; 1.159 + } 1.160 + } 1.161 + 1.162 +#ifdef ACCESSIBILITY 1.163 + // Update the list bullet accessible. If old style list isn't available then 1.164 + // no need to update the accessible tree because it's not created yet. 1.165 + if (aOldStyleContext) { 1.166 + nsAccessibilityService* accService = nsIPresShell::AccService(); 1.167 + if (accService) { 1.168 + const nsStyleList* oldStyleList = aOldStyleContext->PeekStyleList(); 1.169 + if (oldStyleList) { 1.170 + bool hadBullet = oldStyleList->GetListStyleImage() || 1.171 + oldStyleList->mListStyleType != NS_STYLE_LIST_STYLE_NONE; 1.172 + 1.173 + const nsStyleList* newStyleList = StyleList(); 1.174 + bool hasBullet = newStyleList->GetListStyleImage() || 1.175 + newStyleList->mListStyleType != NS_STYLE_LIST_STYLE_NONE; 1.176 + 1.177 + if (hadBullet != hasBullet) { 1.178 + accService->UpdateListBullet(PresContext()->GetPresShell(), mContent, 1.179 + hasBullet); 1.180 + } 1.181 + } 1.182 + } 1.183 + } 1.184 +#endif 1.185 +} 1.186 + 1.187 +class nsDisplayBulletGeometry : public nsDisplayItemGenericGeometry 1.188 +{ 1.189 +public: 1.190 + nsDisplayBulletGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder) 1.191 + : nsDisplayItemGenericGeometry(aItem, aBuilder) 1.192 + { 1.193 + nsBulletFrame* f = static_cast<nsBulletFrame*>(aItem->Frame()); 1.194 + mOrdinal = f->GetOrdinal(); 1.195 + } 1.196 + 1.197 + int32_t mOrdinal; 1.198 +}; 1.199 + 1.200 +class nsDisplayBullet : public nsDisplayItem { 1.201 +public: 1.202 + nsDisplayBullet(nsDisplayListBuilder* aBuilder, nsBulletFrame* aFrame) : 1.203 + nsDisplayItem(aBuilder, aFrame) { 1.204 + MOZ_COUNT_CTOR(nsDisplayBullet); 1.205 + } 1.206 +#ifdef NS_BUILD_REFCNT_LOGGING 1.207 + virtual ~nsDisplayBullet() { 1.208 + MOZ_COUNT_DTOR(nsDisplayBullet); 1.209 + } 1.210 +#endif 1.211 + 1.212 + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, 1.213 + bool* aSnap) MOZ_OVERRIDE 1.214 + { 1.215 + *aSnap = false; 1.216 + return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); 1.217 + } 1.218 + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, 1.219 + HitTestState* aState, 1.220 + nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE { 1.221 + aOutFrames->AppendElement(mFrame); 1.222 + } 1.223 + virtual void Paint(nsDisplayListBuilder* aBuilder, 1.224 + nsRenderingContext* aCtx) MOZ_OVERRIDE; 1.225 + NS_DISPLAY_DECL_NAME("Bullet", TYPE_BULLET) 1.226 + 1.227 + virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE 1.228 + { 1.229 + bool snap; 1.230 + return GetBounds(aBuilder, &snap); 1.231 + } 1.232 + 1.233 + virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE 1.234 + { 1.235 + return new nsDisplayBulletGeometry(this, aBuilder); 1.236 + } 1.237 + 1.238 + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, 1.239 + const nsDisplayItemGeometry* aGeometry, 1.240 + nsRegion *aInvalidRegion) MOZ_OVERRIDE 1.241 + { 1.242 + const nsDisplayBulletGeometry* geometry = static_cast<const nsDisplayBulletGeometry*>(aGeometry); 1.243 + nsBulletFrame* f = static_cast<nsBulletFrame*>(mFrame); 1.244 + 1.245 + if (f->GetOrdinal() != geometry->mOrdinal) { 1.246 + bool snap; 1.247 + aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &snap)); 1.248 + return; 1.249 + } 1.250 + 1.251 + nsCOMPtr<imgIContainer> image = f->GetImage(); 1.252 + if (aBuilder->ShouldSyncDecodeImages() && image && !image->IsDecoded()) { 1.253 + // If we are going to do a sync decode and we are not decoded then we are 1.254 + // going to be drawing something different from what is currently there, 1.255 + // so we add our bounds to the invalid region. 1.256 + bool snap; 1.257 + aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap)); 1.258 + } 1.259 + 1.260 + return nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion); 1.261 + } 1.262 +}; 1.263 + 1.264 +void nsDisplayBullet::Paint(nsDisplayListBuilder* aBuilder, 1.265 + nsRenderingContext* aCtx) 1.266 +{ 1.267 + uint32_t flags = imgIContainer::FLAG_NONE; 1.268 + if (aBuilder->ShouldSyncDecodeImages()) { 1.269 + flags |= imgIContainer::FLAG_SYNC_DECODE; 1.270 + } 1.271 + static_cast<nsBulletFrame*>(mFrame)-> 1.272 + PaintBullet(*aCtx, ToReferenceFrame(), mVisibleRect, flags); 1.273 +} 1.274 + 1.275 +void 1.276 +nsBulletFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.277 + const nsRect& aDirtyRect, 1.278 + const nsDisplayListSet& aLists) 1.279 +{ 1.280 + if (!IsVisibleForPainting(aBuilder)) 1.281 + return; 1.282 + 1.283 + DO_GLOBAL_REFLOW_COUNT_DSP("nsBulletFrame"); 1.284 + 1.285 + aLists.Content()->AppendNewToTop( 1.286 + new (aBuilder) nsDisplayBullet(aBuilder, this)); 1.287 +} 1.288 + 1.289 +void 1.290 +nsBulletFrame::PaintBullet(nsRenderingContext& aRenderingContext, nsPoint aPt, 1.291 + const nsRect& aDirtyRect, uint32_t aFlags) 1.292 +{ 1.293 + const nsStyleList* myList = StyleList(); 1.294 + uint8_t listStyleType = myList->mListStyleType; 1.295 + 1.296 + if (myList->GetListStyleImage() && mImageRequest) { 1.297 + uint32_t status; 1.298 + mImageRequest->GetImageStatus(&status); 1.299 + if (status & imgIRequest::STATUS_LOAD_COMPLETE && 1.300 + !(status & imgIRequest::STATUS_ERROR)) { 1.301 + nsCOMPtr<imgIContainer> imageCon; 1.302 + mImageRequest->GetImage(getter_AddRefs(imageCon)); 1.303 + if (imageCon) { 1.304 + nsRect dest(mPadding.left, mPadding.top, 1.305 + mRect.width - (mPadding.left + mPadding.right), 1.306 + mRect.height - (mPadding.top + mPadding.bottom)); 1.307 + nsLayoutUtils::DrawSingleImage(&aRenderingContext, 1.308 + imageCon, nsLayoutUtils::GetGraphicsFilterForFrame(this), 1.309 + dest + aPt, aDirtyRect, nullptr, aFlags); 1.310 + return; 1.311 + } 1.312 + } 1.313 + } 1.314 + 1.315 + nsRefPtr<nsFontMetrics> fm; 1.316 + aRenderingContext.SetColor(nsLayoutUtils::GetColor(this, eCSSProperty_color)); 1.317 + 1.318 + mTextIsRTL = false; 1.319 + 1.320 + nsAutoString text; 1.321 + switch (listStyleType) { 1.322 + case NS_STYLE_LIST_STYLE_NONE: 1.323 + break; 1.324 + 1.325 + default: 1.326 + case NS_STYLE_LIST_STYLE_DISC: 1.327 + aRenderingContext.FillEllipse(mPadding.left + aPt.x, mPadding.top + aPt.y, 1.328 + mRect.width - (mPadding.left + mPadding.right), 1.329 + mRect.height - (mPadding.top + mPadding.bottom)); 1.330 + break; 1.331 + 1.332 + case NS_STYLE_LIST_STYLE_CIRCLE: 1.333 + aRenderingContext.DrawEllipse(mPadding.left + aPt.x, mPadding.top + aPt.y, 1.334 + mRect.width - (mPadding.left + mPadding.right), 1.335 + mRect.height - (mPadding.top + mPadding.bottom)); 1.336 + break; 1.337 + 1.338 + case NS_STYLE_LIST_STYLE_SQUARE: 1.339 + { 1.340 + nsRect rect(aPt, mRect.Size()); 1.341 + rect.Deflate(mPadding); 1.342 + 1.343 + // Snap the height and the width of the rectangle to device pixels, 1.344 + // and then center the result within the original rectangle, so that 1.345 + // all square bullets at the same font size have the same visual 1.346 + // size (bug 376690). 1.347 + // FIXME: We should really only do this if we're not transformed 1.348 + // (like gfxContext::UserToDevicePixelSnapped does). 1.349 + nsPresContext *pc = PresContext(); 1.350 + nsRect snapRect(rect.x, rect.y, 1.351 + pc->RoundAppUnitsToNearestDevPixels(rect.width), 1.352 + pc->RoundAppUnitsToNearestDevPixels(rect.height)); 1.353 + snapRect.MoveBy((rect.width - snapRect.width) / 2, 1.354 + (rect.height - snapRect.height) / 2); 1.355 + aRenderingContext.FillRect(snapRect.x, snapRect.y, 1.356 + snapRect.width, snapRect.height); 1.357 + } 1.358 + break; 1.359 + 1.360 + case NS_STYLE_LIST_STYLE_DECIMAL: 1.361 + case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO: 1.362 + case NS_STYLE_LIST_STYLE_CJK_DECIMAL: 1.363 + case NS_STYLE_LIST_STYLE_LOWER_ROMAN: 1.364 + case NS_STYLE_LIST_STYLE_UPPER_ROMAN: 1.365 + case NS_STYLE_LIST_STYLE_LOWER_ALPHA: 1.366 + case NS_STYLE_LIST_STYLE_UPPER_ALPHA: 1.367 + case NS_STYLE_LIST_STYLE_LOWER_GREEK: 1.368 + case NS_STYLE_LIST_STYLE_HEBREW: 1.369 + case NS_STYLE_LIST_STYLE_ARMENIAN: 1.370 + case NS_STYLE_LIST_STYLE_GEORGIAN: 1.371 + case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC: 1.372 + case NS_STYLE_LIST_STYLE_HIRAGANA: 1.373 + case NS_STYLE_LIST_STYLE_KATAKANA: 1.374 + case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA: 1.375 + case NS_STYLE_LIST_STYLE_KATAKANA_IROHA: 1.376 + case NS_STYLE_LIST_STYLE_JAPANESE_INFORMAL: 1.377 + case NS_STYLE_LIST_STYLE_JAPANESE_FORMAL: 1.378 + case NS_STYLE_LIST_STYLE_KOREAN_HANGUL_FORMAL: 1.379 + case NS_STYLE_LIST_STYLE_KOREAN_HANJA_INFORMAL: 1.380 + case NS_STYLE_LIST_STYLE_KOREAN_HANJA_FORMAL: 1.381 + case NS_STYLE_LIST_STYLE_SIMP_CHINESE_INFORMAL: 1.382 + case NS_STYLE_LIST_STYLE_SIMP_CHINESE_FORMAL: 1.383 + case NS_STYLE_LIST_STYLE_TRAD_CHINESE_INFORMAL: 1.384 + case NS_STYLE_LIST_STYLE_TRAD_CHINESE_FORMAL: 1.385 + case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL: 1.386 + case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL: 1.387 + case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL: 1.388 + case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL: 1.389 + case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL: 1.390 + case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL: 1.391 + case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM: 1.392 + case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH: 1.393 + case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC: 1.394 + case NS_STYLE_LIST_STYLE_MOZ_PERSIAN: 1.395 + case NS_STYLE_LIST_STYLE_MOZ_URDU: 1.396 + case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI: 1.397 + case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI: 1.398 + case NS_STYLE_LIST_STYLE_MOZ_GUJARATI: 1.399 + case NS_STYLE_LIST_STYLE_MOZ_ORIYA: 1.400 + case NS_STYLE_LIST_STYLE_MOZ_KANNADA: 1.401 + case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM: 1.402 + case NS_STYLE_LIST_STYLE_MOZ_BENGALI: 1.403 + case NS_STYLE_LIST_STYLE_MOZ_TAMIL: 1.404 + case NS_STYLE_LIST_STYLE_MOZ_TELUGU: 1.405 + case NS_STYLE_LIST_STYLE_MOZ_THAI: 1.406 + case NS_STYLE_LIST_STYLE_MOZ_LAO: 1.407 + case NS_STYLE_LIST_STYLE_MOZ_MYANMAR: 1.408 + case NS_STYLE_LIST_STYLE_MOZ_KHMER: 1.409 + case NS_STYLE_LIST_STYLE_MOZ_HANGUL: 1.410 + case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT: 1.411 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME: 1.412 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC: 1.413 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM: 1.414 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER: 1.415 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET: 1.416 + nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), 1.417 + GetFontSizeInflation()); 1.418 + GetListItemText(*myList, text); 1.419 + aRenderingContext.SetFont(fm); 1.420 + nscoord ascent = fm->MaxAscent(); 1.421 + aRenderingContext.SetTextRunRTL(mTextIsRTL); 1.422 + aRenderingContext.DrawString(text, mPadding.left + aPt.x, 1.423 + mPadding.top + aPt.y + ascent); 1.424 + break; 1.425 + } 1.426 +} 1.427 + 1.428 +int32_t 1.429 +nsBulletFrame::SetListItemOrdinal(int32_t aNextOrdinal, 1.430 + bool* aChanged, 1.431 + int32_t aIncrement) 1.432 +{ 1.433 + MOZ_ASSERT(aIncrement == 1 || aIncrement == -1, 1.434 + "We shouldn't have weird increments here"); 1.435 + 1.436 + // Assume that the ordinal comes from the caller 1.437 + int32_t oldOrdinal = mOrdinal; 1.438 + mOrdinal = aNextOrdinal; 1.439 + 1.440 + // Try to get value directly from the list-item, if it specifies a 1.441 + // value attribute. Note: we do this with our parent's content 1.442 + // because our parent is the list-item. 1.443 + nsIContent* parentContent = mParent->GetContent(); 1.444 + if (parentContent) { 1.445 + nsGenericHTMLElement *hc = 1.446 + nsGenericHTMLElement::FromContent(parentContent); 1.447 + if (hc) { 1.448 + const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::value); 1.449 + if (attr && attr->Type() == nsAttrValue::eInteger) { 1.450 + // Use ordinal specified by the value attribute 1.451 + mOrdinal = attr->GetIntegerValue(); 1.452 + } 1.453 + } 1.454 + } 1.455 + 1.456 + *aChanged = oldOrdinal != mOrdinal; 1.457 + 1.458 + return nsCounterManager::IncrementCounter(mOrdinal, aIncrement); 1.459 +} 1.460 + 1.461 + 1.462 +// XXX change roman/alpha to use unsigned math so that maxint and 1.463 +// maxnegint will work 1.464 + 1.465 +/** 1.466 + * For all functions below, a return value of true means that we 1.467 + * could represent mOrder in the desired numbering system. false 1.468 + * means we had to fall back to decimal 1.469 + */ 1.470 +static bool DecimalToText(int32_t ordinal, nsString& result) 1.471 +{ 1.472 + char cbuf[40]; 1.473 + PR_snprintf(cbuf, sizeof(cbuf), "%ld", ordinal); 1.474 + result.AppendASCII(cbuf); 1.475 + return true; 1.476 +} 1.477 +static bool DecimalLeadingZeroToText(int32_t ordinal, nsString& result) 1.478 +{ 1.479 + char cbuf[40]; 1.480 + PR_snprintf(cbuf, sizeof(cbuf), "%02ld", ordinal); 1.481 + result.AppendASCII(cbuf); 1.482 + return true; 1.483 +} 1.484 +static bool OtherDecimalToText(int32_t ordinal, char16_t zeroChar, nsString& result) 1.485 +{ 1.486 + char16_t diff = zeroChar - char16_t('0'); 1.487 + // We're going to be appending to whatever is in "result" already, so make 1.488 + // sure to only munge the new bits. Note that we can't just grab the pointer 1.489 + // to the new stuff here, since appending to the string can realloc. 1.490 + size_t offset = result.Length(); 1.491 + DecimalToText(ordinal, result); 1.492 + char16_t* p = result.BeginWriting() + offset; 1.493 + if (ordinal < 0) { 1.494 + // skip the leading '-' 1.495 + ++p; 1.496 + } 1.497 + for(; '\0' != *p ; p++) 1.498 + *p += diff; 1.499 + return true; 1.500 +} 1.501 +static bool TamilToText(int32_t ordinal, nsString& result) 1.502 +{ 1.503 + if (ordinal < 1 || ordinal > 9999) { 1.504 + // Can't do those in this system. 1.505 + return false; 1.506 + } 1.507 + char16_t diff = 0x0BE6 - char16_t('0'); 1.508 + // We're going to be appending to whatever is in "result" already, so make 1.509 + // sure to only munge the new bits. Note that we can't just grab the pointer 1.510 + // to the new stuff here, since appending to the string can realloc. 1.511 + size_t offset = result.Length(); 1.512 + DecimalToText(ordinal, result); 1.513 + char16_t* p = result.BeginWriting() + offset; 1.514 + for(; '\0' != *p ; p++) 1.515 + if(*p != char16_t('0')) 1.516 + *p += diff; 1.517 + return true; 1.518 +} 1.519 + 1.520 + 1.521 +static const char gLowerRomanCharsA[] = "ixcm"; 1.522 +static const char gUpperRomanCharsA[] = "IXCM"; 1.523 +static const char gLowerRomanCharsB[] = "vld"; 1.524 +static const char gUpperRomanCharsB[] = "VLD"; 1.525 + 1.526 +static bool RomanToText(int32_t ordinal, nsString& result, const char* achars, const char* bchars) 1.527 +{ 1.528 + if (ordinal < 1 || ordinal > 3999) { 1.529 + return false; 1.530 + } 1.531 + nsAutoString addOn, decStr; 1.532 + decStr.AppendInt(ordinal, 10); 1.533 + int len = decStr.Length(); 1.534 + const char16_t* dp = decStr.get(); 1.535 + const char16_t* end = dp + len; 1.536 + int romanPos = len; 1.537 + int n; 1.538 + 1.539 + for (; dp < end; dp++) { 1.540 + romanPos--; 1.541 + addOn.SetLength(0); 1.542 + switch(*dp) { 1.543 + case '3': 1.544 + addOn.Append(char16_t(achars[romanPos])); 1.545 + // FALLTHROUGH 1.546 + case '2': 1.547 + addOn.Append(char16_t(achars[romanPos])); 1.548 + // FALLTHROUGH 1.549 + case '1': 1.550 + addOn.Append(char16_t(achars[romanPos])); 1.551 + break; 1.552 + case '4': 1.553 + addOn.Append(char16_t(achars[romanPos])); 1.554 + // FALLTHROUGH 1.555 + case '5': case '6': 1.556 + case '7': case '8': 1.557 + addOn.Append(char16_t(bchars[romanPos])); 1.558 + for(n=0;'5'+n<*dp;n++) { 1.559 + addOn.Append(char16_t(achars[romanPos])); 1.560 + } 1.561 + break; 1.562 + case '9': 1.563 + addOn.Append(char16_t(achars[romanPos])); 1.564 + addOn.Append(char16_t(achars[romanPos+1])); 1.565 + break; 1.566 + default: 1.567 + break; 1.568 + } 1.569 + result.Append(addOn); 1.570 + } 1.571 + return true; 1.572 +} 1.573 + 1.574 +#define ALPHA_SIZE 26 1.575 +static const char16_t gLowerAlphaChars[ALPHA_SIZE] = 1.576 +{ 1.577 +0x0061, 0x0062, 0x0063, 0x0064, 0x0065, // A B C D E 1.578 +0x0066, 0x0067, 0x0068, 0x0069, 0x006A, // F G H I J 1.579 +0x006B, 0x006C, 0x006D, 0x006E, 0x006F, // K L M N O 1.580 +0x0070, 0x0071, 0x0072, 0x0073, 0x0074, // P Q R S T 1.581 +0x0075, 0x0076, 0x0077, 0x0078, 0x0079, // U V W X Y 1.582 +0x007A // Z 1.583 +}; 1.584 + 1.585 +static const char16_t gUpperAlphaChars[ALPHA_SIZE] = 1.586 +{ 1.587 +0x0041, 0x0042, 0x0043, 0x0044, 0x0045, // A B C D E 1.588 +0x0046, 0x0047, 0x0048, 0x0049, 0x004A, // F G H I J 1.589 +0x004B, 0x004C, 0x004D, 0x004E, 0x004F, // K L M N O 1.590 +0x0050, 0x0051, 0x0052, 0x0053, 0x0054, // P Q R S T 1.591 +0x0055, 0x0056, 0x0057, 0x0058, 0x0059, // U V W X Y 1.592 +0x005A // Z 1.593 +}; 1.594 + 1.595 + 1.596 +#define KATAKANA_CHARS_SIZE 48 1.597 +// Page 94 Writing Systems of The World 1.598 +// after modification by momoi 1.599 +static const char16_t gKatakanaChars[KATAKANA_CHARS_SIZE] = 1.600 +{ 1.601 +0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, // a i u e o 1.602 +0x30AB, 0x30AD, 0x30AF, 0x30B1, 0x30B3, // ka ki ku ke ko 1.603 +0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD, // sa shi su se so 1.604 +0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, // ta chi tsu te to 1.605 +0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, // na ni nu ne no 1.606 +0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, // ha hi hu he ho 1.607 +0x30DE, 0x30DF, 0x30E0, 0x30E1, 0x30E2, // ma mi mu me mo 1.608 +0x30E4, 0x30E6, 0x30E8, // ya yu yo 1.609 +0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, // ra ri ru re ro 1.610 +0x30EF, 0x30F0, 0x30F1, 0x30F2, // wa (w)i (w)e (w)o 1.611 +0x30F3 // n 1.612 +}; 1.613 + 1.614 +#define HIRAGANA_CHARS_SIZE 48 1.615 +static const char16_t gHiraganaChars[HIRAGANA_CHARS_SIZE] = 1.616 +{ 1.617 +0x3042, 0x3044, 0x3046, 0x3048, 0x304A, // a i u e o 1.618 +0x304B, 0x304D, 0x304F, 0x3051, 0x3053, // ka ki ku ke ko 1.619 +0x3055, 0x3057, 0x3059, 0x305B, 0x305D, // sa shi su se so 1.620 +0x305F, 0x3061, 0x3064, 0x3066, 0x3068, // ta chi tsu te to 1.621 +0x306A, 0x306B, 0x306C, 0x306D, 0x306E, // na ni nu ne no 1.622 +0x306F, 0x3072, 0x3075, 0x3078, 0x307B, // ha hi hu he ho 1.623 +0x307E, 0x307F, 0x3080, 0x3081, 0x3082, // ma mi mu me mo 1.624 +0x3084, 0x3086, 0x3088, // ya yu yo 1.625 +0x3089, 0x308A, 0x308B, 0x308C, 0x308D, // ra ri ru re ro 1.626 +0x308F, 0x3090, 0x3091, 0x3092, // wa (w)i (w)e (w)o 1.627 +0x3093 // n 1.628 +}; 1.629 + 1.630 + 1.631 +#define HIRAGANA_IROHA_CHARS_SIZE 47 1.632 +// Page 94 Writing Systems of The World 1.633 +static const char16_t gHiraganaIrohaChars[HIRAGANA_IROHA_CHARS_SIZE] = 1.634 +{ 1.635 +0x3044, 0x308D, 0x306F, 0x306B, 0x307B, // i ro ha ni ho 1.636 +0x3078, 0x3068, 0x3061, 0x308A, 0x306C, // he to chi ri nu 1.637 +0x308B, 0x3092, 0x308F, 0x304B, 0x3088, // ru (w)o wa ka yo 1.638 +0x305F, 0x308C, 0x305D, 0x3064, 0x306D, // ta re so tsu ne 1.639 +0x306A, 0x3089, 0x3080, 0x3046, 0x3090, // na ra mu u (w)i 1.640 +0x306E, 0x304A, 0x304F, 0x3084, 0x307E, // no o ku ya ma 1.641 +0x3051, 0x3075, 0x3053, 0x3048, 0x3066, // ke hu ko e te 1.642 +0x3042, 0x3055, 0x304D, 0x3086, 0x3081, // a sa ki yu me 1.643 +0x307F, 0x3057, 0x3091, 0x3072, 0x3082, // mi shi (w)e hi mo 1.644 +0x305B, 0x3059 // se su 1.645 +}; 1.646 + 1.647 +#define KATAKANA_IROHA_CHARS_SIZE 47 1.648 +static const char16_t gKatakanaIrohaChars[KATAKANA_IROHA_CHARS_SIZE] = 1.649 +{ 1.650 +0x30A4, 0x30ED, 0x30CF, 0x30CB, 0x30DB, // i ro ha ni ho 1.651 +0x30D8, 0x30C8, 0x30C1, 0x30EA, 0x30CC, // he to chi ri nu 1.652 +0x30EB, 0x30F2, 0x30EF, 0x30AB, 0x30E8, // ru (w)o wa ka yo 1.653 +0x30BF, 0x30EC, 0x30BD, 0x30C4, 0x30CD, // ta re so tsu ne 1.654 +0x30CA, 0x30E9, 0x30E0, 0x30A6, 0x30F0, // na ra mu u (w)i 1.655 +0x30CE, 0x30AA, 0x30AF, 0x30E4, 0x30DE, // no o ku ya ma 1.656 +0x30B1, 0x30D5, 0x30B3, 0x30A8, 0x30C6, // ke hu ko e te 1.657 +0x30A2, 0x30B5, 0x30AD, 0x30E6, 0x30E1, // a sa ki yu me 1.658 +0x30DF, 0x30B7, 0x30F1, 0x30D2, 0x30E2, // mi shi (w)e hi mo 1.659 +0x30BB, 0x30B9 // se su 1.660 +}; 1.661 + 1.662 +#define LOWER_GREEK_CHARS_SIZE 24 1.663 +// Note: 0x03C2 GREEK FINAL SIGMA is not used in here.... 1.664 +static const char16_t gLowerGreekChars[LOWER_GREEK_CHARS_SIZE] = 1.665 +{ 1.666 +0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, // alpha beta gamma delta epsilon 1.667 +0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, // zeta eta theta iota kappa 1.668 +0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, // lamda mu nu xi omicron 1.669 +0x03C0, 0x03C1, 0x03C3, 0x03C4, 0x03C5, // pi rho sigma tau upsilon 1.670 +0x03C6, 0x03C7, 0x03C8, 0x03C9 // phi chi psi omega 1.671 +}; 1.672 + 1.673 +#define CJK_HEAVENLY_STEM_CHARS_SIZE 10 1.674 +static const char16_t gCJKHeavenlyStemChars[CJK_HEAVENLY_STEM_CHARS_SIZE] = 1.675 +{ 1.676 +0x7532, 0x4e59, 0x4e19, 0x4e01, 0x620a, 1.677 +0x5df1, 0x5e9a, 0x8f9b, 0x58ec, 0x7678 1.678 +}; 1.679 +#define CJK_EARTHLY_BRANCH_CHARS_SIZE 12 1.680 +static const char16_t gCJKEarthlyBranchChars[CJK_EARTHLY_BRANCH_CHARS_SIZE] = 1.681 +{ 1.682 +0x5b50, 0x4e11, 0x5bc5, 0x536f, 0x8fb0, 0x5df3, 1.683 +0x5348, 0x672a, 0x7533, 0x9149, 0x620c, 0x4ea5 1.684 +}; 1.685 +#define HANGUL_CHARS_SIZE 14 1.686 +static const char16_t gHangulChars[HANGUL_CHARS_SIZE] = 1.687 +{ 1.688 +0xac00, 0xb098, 0xb2e4, 0xb77c, 0xb9c8, 0xbc14, 1.689 +0xc0ac, 0xc544, 0xc790, 0xcc28, 0xce74, 0xd0c0, 1.690 +0xd30c, 0xd558 1.691 +}; 1.692 +#define HANGUL_CONSONANT_CHARS_SIZE 14 1.693 +static const char16_t gHangulConsonantChars[HANGUL_CONSONANT_CHARS_SIZE] = 1.694 +{ 1.695 +0x3131, 0x3134, 0x3137, 0x3139, 0x3141, 0x3142, 1.696 +0x3145, 0x3147, 0x3148, 0x314a, 0x314b, 0x314c, 1.697 +0x314d, 0x314e 1.698 +}; 1.699 + 1.700 +// Ge'ez set of Ethiopic ordered list. There are other locale-dependent sets. 1.701 +// For the time being, let's implement two Ge'ez sets only 1.702 +// per Momoi san's suggestion in bug 102252. 1.703 +// For details, refer to http://www.ethiopic.org/Collation/OrderedLists.html. 1.704 +#define ETHIOPIC_HALEHAME_CHARS_SIZE 26 1.705 +static const char16_t gEthiopicHalehameChars[ETHIOPIC_HALEHAME_CHARS_SIZE] = 1.706 +{ 1.707 +0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 1.708 +0x1230, 0x1240, 0x1260, 0x1270, 0x1280, 0x1290, 1.709 +0x12a0, 0x12a8, 0x12c8, 0x12d0, 0x12d8, 0x12e8, 1.710 +0x12f0, 0x1308, 0x1320, 0x1330, 0x1338, 0x1340, 1.711 +0x1348, 0x1350 1.712 +}; 1.713 +#define ETHIOPIC_HALEHAME_AM_CHARS_SIZE 33 1.714 +static const char16_t gEthiopicHalehameAmChars[ETHIOPIC_HALEHAME_AM_CHARS_SIZE] = 1.715 +{ 1.716 +0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 1.717 +0x1230, 0x1238, 0x1240, 0x1260, 0x1270, 0x1278, 1.718 +0x1280, 0x1290, 0x1298, 0x12a0, 0x12a8, 0x12b8, 1.719 +0x12c8, 0x12d0, 0x12d8, 0x12e0, 0x12e8, 0x12f0, 1.720 +0x1300, 0x1308, 0x1320, 0x1328, 0x1330, 0x1338, 1.721 +0x1340, 0x1348, 0x1350 1.722 +}; 1.723 +#define ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE 31 1.724 +static const char16_t gEthiopicHalehameTiErChars[ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE] = 1.725 +{ 1.726 +0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 1.727 +0x1238, 0x1240, 0x1250, 0x1260, 0x1270, 0x1278, 1.728 +0x1290, 0x1298, 0x12a0, 0x12a8, 0x12b8, 0x12c8, 1.729 +0x12d0, 0x12d8, 0x12e0, 0x12e8, 0x12f0, 0x1300, 1.730 +0x1308, 0x1320, 0x1328, 0x1330, 0x1338, 0x1348, 1.731 +0x1350 1.732 +}; 1.733 +#define ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE 34 1.734 +static const char16_t gEthiopicHalehameTiEtChars[ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE] = 1.735 +{ 1.736 +0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 1.737 +0x1230, 0x1238, 0x1240, 0x1250, 0x1260, 0x1270, 1.738 +0x1278, 0x1280, 0x1290, 0x1298, 0x12a0, 0x12a8, 1.739 +0x12b8, 0x12c8, 0x12d0, 0x12d8, 0x12e0, 0x12e8, 1.740 +0x12f0, 0x1300, 0x1308, 0x1320, 0x1328, 0x1330, 1.741 +0x1338, 0x1340, 0x1348, 0x1350 1.742 +}; 1.743 + 1.744 + 1.745 +// We know cjk-ideographic need 31 characters to display 99,999,999,999,999,999 1.746 +// georgian needs 6 at most 1.747 +// armenian needs 12 at most 1.748 +// hebrew may need more... 1.749 + 1.750 +#define NUM_BUF_SIZE 34 1.751 + 1.752 +static bool CharListToText(int32_t ordinal, nsString& result, const char16_t* chars, int32_t aBase) 1.753 +{ 1.754 + char16_t buf[NUM_BUF_SIZE]; 1.755 + int32_t idx = NUM_BUF_SIZE; 1.756 + if (ordinal < 1) { 1.757 + return false; 1.758 + } 1.759 + do { 1.760 + ordinal--; // a == 0 1.761 + int32_t cur = ordinal % aBase; 1.762 + buf[--idx] = chars[cur]; 1.763 + ordinal /= aBase ; 1.764 + } while ( ordinal > 0); 1.765 + result.Append(buf+idx,NUM_BUF_SIZE-idx); 1.766 + return true; 1.767 +} 1.768 + 1.769 +static const char16_t gCJKDecimalChars[10] = 1.770 +{ 1.771 + 0x3007, 0x4e00, 0x4e8c, 0x4e09, 0x56db, 1.772 + 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d 1.773 +}; 1.774 +static bool CharListDecimalToText(int32_t ordinal, nsString& result, const char16_t* chars) 1.775 +{ 1.776 + if (ordinal < 0) { 1.777 + return false; 1.778 + } 1.779 + char16_t buf[NUM_BUF_SIZE]; 1.780 + int32_t idx = NUM_BUF_SIZE; 1.781 + do { 1.782 + buf[--idx] = chars[ordinal % 10]; 1.783 + ordinal /= 10; 1.784 + } while (ordinal > 0); 1.785 + result.Append(buf + idx, NUM_BUF_SIZE - idx); 1.786 + return true; 1.787 +} 1.788 + 1.789 +enum CJKIdeographicLang { 1.790 + CHINESE, KOREAN, JAPANESE 1.791 +}; 1.792 +struct CJKIdeographicData { 1.793 + const char16_t *negative; 1.794 + char16_t digit[10]; 1.795 + char16_t unit[3]; 1.796 + char16_t unit10K[2]; 1.797 + uint8_t lang; 1.798 + bool informal; 1.799 +}; 1.800 +static const char16_t gJapaneseNegative[] = { 1.801 + 0x30de, 0x30a4, 0x30ca, 0x30b9, 0x0000 1.802 +}; 1.803 +static const CJKIdeographicData gDataJapaneseInformal = { 1.804 + gJapaneseNegative, // negative 1.805 + { // digit 1.806 + 0x3007, 0x4e00, 0x4e8c, 0x4e09, 0x56db, 1.807 + 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d 1.808 + }, 1.809 + { 0x5341, 0x767e, 0x5343 }, // unit 1.810 + { 0x4e07, 0x5104 }, // unit10K 1.811 + JAPANESE, // lang 1.812 + true // informal 1.813 +}; 1.814 +static const CJKIdeographicData gDataJapaneseFormal = { 1.815 + gJapaneseNegative, // negative 1.816 + { // digit 1.817 + 0x96f6, 0x58f1, 0x5f10, 0x53c2, 0x56db, 1.818 + 0x4f0d, 0x516d, 0x4e03, 0x516b, 0x4e5d 1.819 + }, 1.820 + { 0x62fe, 0x767e, 0x9621 }, // unit 1.821 + { 0x842c, 0x5104 }, // unit10K 1.822 + JAPANESE, // lang 1.823 + false // informal 1.824 +}; 1.825 +static const char16_t gKoreanNegative[] = { 1.826 + 0xb9c8, 0xc774, 0xb108, 0xc2a4, 0x0020, 0x0000 1.827 +}; 1.828 +static const CJKIdeographicData gDataKoreanHangulFormal = { 1.829 + gKoreanNegative, // negative 1.830 + { // digit 1.831 + 0xc601, 0xc77c, 0xc774, 0xc0bc, 0xc0ac, 1.832 + 0xc624, 0xc721, 0xce60, 0xd314, 0xad6c 1.833 + }, 1.834 + { 0xc2ed, 0xbc31, 0xcc9c }, // unit 1.835 + { 0xb9cc, 0xc5b5 }, // unit10K 1.836 + KOREAN, // lang 1.837 + false // informal 1.838 +}; 1.839 +static const CJKIdeographicData gDataKoreanHanjaInformal = { 1.840 + gKoreanNegative, // negative 1.841 + { // digit 1.842 + 0x96f6, 0x4e00, 0x4e8c, 0x4e09, 0x56db, 1.843 + 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d 1.844 + }, 1.845 + { 0x5341, 0x767e, 0x5343 }, // unit 1.846 + { 0x842c, 0x5104 }, // unit10K 1.847 + KOREAN, // lang 1.848 + true // informal 1.849 +}; 1.850 +static const CJKIdeographicData gDataKoreanHanjaFormal = { 1.851 + gKoreanNegative, // negative 1.852 + { // digit 1.853 + 0x96f6, 0x58f9, 0x8cb3, 0x53c3, 0x56db, 1.854 + 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d 1.855 + }, 1.856 + { 0x62fe, 0x767e, 0x4edf }, // unit 1.857 + { 0x842c, 0x5104 }, // unit10K 1.858 + KOREAN, // lang 1.859 + false // informal 1.860 +}; 1.861 +static const char16_t gSimpChineseNegative[] = { 1.862 + 0x8d1f, 0x0000 1.863 +}; 1.864 +static const CJKIdeographicData gDataSimpChineseInformal = { 1.865 + gSimpChineseNegative, // negative 1.866 + { // digit 1.867 + 0x96f6, 0x4e00, 0x4e8c, 0x4e09, 0x56db, 1.868 + 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d 1.869 + }, 1.870 + { 0x5341, 0x767e, 0x5343 }, // unit 1.871 + { 0x4e07, 0x4ebf }, // unit10K 1.872 + CHINESE, // lang 1.873 + true // informal 1.874 +}; 1.875 +static const CJKIdeographicData gDataSimpChineseFormal = { 1.876 + gSimpChineseNegative, // negative 1.877 + { // digit 1.878 + 0x96f6, 0x58f9, 0x8d30, 0x53c1, 0x8086, 1.879 + 0x4f0d, 0x9646, 0x67d2, 0x634c, 0x7396 1.880 + }, 1.881 + { 0x62fe, 0x4f70, 0x4edf }, // unit 1.882 + { 0x4e07, 0x4ebf }, // unit10K 1.883 + CHINESE, // lang 1.884 + false // informal 1.885 +}; 1.886 +static const char16_t gTradChineseNegative[] = { 1.887 + 0x8ca0, 0x0000 1.888 +}; 1.889 +static const CJKIdeographicData gDataTradChineseInformal = { 1.890 + gTradChineseNegative, // negative 1.891 + { // digit 1.892 + 0x96f6, 0x4e00, 0x4e8c, 0x4e09, 0x56db, 1.893 + 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d 1.894 + }, 1.895 + { 0x5341, 0x767e, 0x5343 }, // unit 1.896 + { 0x842c, 0x5104 }, // unit10K 1.897 + CHINESE, // lang 1.898 + true // informal 1.899 +}; 1.900 +static const CJKIdeographicData gDataTradChineseFormal = { 1.901 + gTradChineseNegative, // negative 1.902 + { // digit 1.903 + 0x96f6, 0x58f9, 0x8cb3, 0x53c3, 0x8086, 1.904 + 0x4f0d, 0x9678, 0x67d2, 0x634c, 0x7396 1.905 + }, 1.906 + { 0x62fe, 0x4f70, 0x4edf }, // unit 1.907 + { 0x842c, 0x5104 }, // unit10K 1.908 + CHINESE, // lang 1.909 + false // informal 1.910 +}; 1.911 + 1.912 +static const bool CJKIdeographicToText(int32_t aOrdinal, nsString& result, 1.913 + const CJKIdeographicData& data) 1.914 +{ 1.915 + char16_t buf[NUM_BUF_SIZE]; 1.916 + int32_t idx = NUM_BUF_SIZE; 1.917 + int32_t pos = 0; 1.918 + bool isNegative = (aOrdinal < 0); 1.919 + bool needZero = (aOrdinal == 0); 1.920 + int32_t unitidx = 0, unit10Kidx = 0; 1.921 + uint32_t ordinal = mozilla::Abs(aOrdinal); 1.922 + do { 1.923 + unitidx = pos % 4; 1.924 + if (unitidx == 0) { 1.925 + unit10Kidx = pos / 4; 1.926 + } 1.927 + int32_t cur = ordinal % 10; 1.928 + if (cur == 0) { 1.929 + if (needZero) { 1.930 + needZero = false; 1.931 + buf[--idx] = data.digit[0]; 1.932 + } 1.933 + } else { 1.934 + if (data.lang == CHINESE) { 1.935 + needZero = true; 1.936 + } 1.937 + if (unit10Kidx != 0) { 1.938 + if (data.lang == KOREAN && idx != NUM_BUF_SIZE) { 1.939 + buf[--idx] = ' '; 1.940 + } 1.941 + buf[--idx] = data.unit10K[unit10Kidx - 1]; 1.942 + } 1.943 + if (unitidx != 0) { 1.944 + buf[--idx] = data.unit[unitidx - 1]; 1.945 + } 1.946 + if (cur != 1) { 1.947 + buf[--idx] = data.digit[cur]; 1.948 + } else { 1.949 + bool needOne = true; 1.950 + if (data.informal) { 1.951 + switch (data.lang) { 1.952 + case CHINESE: 1.953 + if (unitidx == 1 && 1.954 + (ordinal == 1 || (pos > 4 && ordinal % 1000 == 1))) { 1.955 + needOne = false; 1.956 + } 1.957 + break; 1.958 + case JAPANESE: 1.959 + if (unitidx > 0 && 1.960 + (unitidx != 3 || (pos == 3 && ordinal == 1))) { 1.961 + needOne = false; 1.962 + } 1.963 + break; 1.964 + case KOREAN: 1.965 + if (unitidx > 0 || (pos == 4 && (ordinal % 1000) == 1)) { 1.966 + needOne = false; 1.967 + } 1.968 + break; 1.969 + } 1.970 + } 1.971 + if (needOne) { 1.972 + buf[--idx] = data.digit[1]; 1.973 + } 1.974 + } 1.975 + unit10Kidx = 0; 1.976 + } 1.977 + ordinal /= 10; 1.978 + pos++; 1.979 + } while (ordinal > 0); 1.980 + if (isNegative) { 1.981 + result.Append(data.negative); 1.982 + } 1.983 + result.Append(buf + idx, NUM_BUF_SIZE - idx); 1.984 + return true; 1.985 +} 1.986 + 1.987 +#define HEBREW_GERESH 0x05F3 1.988 +static const char16_t gHebrewDigit[22] = 1.989 +{ 1.990 +// 1 2 3 4 5 6 7 8 9 1.991 +0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 1.992 +// 10 20 30 40 50 60 70 80 90 1.993 +0x05D9, 0x05DB, 0x05DC, 0x05DE, 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6, 1.994 +// 100 200 300 400 1.995 +0x05E7, 0x05E8, 0x05E9, 0x05EA 1.996 +}; 1.997 + 1.998 +static bool HebrewToText(int32_t ordinal, nsString& result) 1.999 +{ 1.1000 + if (ordinal < 1 || ordinal > 999999) { 1.1001 + return false; 1.1002 + } 1.1003 + bool outputSep = false; 1.1004 + nsAutoString allText, thousandsGroup; 1.1005 + do { 1.1006 + thousandsGroup.Truncate(); 1.1007 + int32_t n3 = ordinal % 1000; 1.1008 + // Process digit for 100 - 900 1.1009 + for(int32_t n1 = 400; n1 > 0; ) 1.1010 + { 1.1011 + if( n3 >= n1) 1.1012 + { 1.1013 + n3 -= n1; 1.1014 + thousandsGroup.Append(gHebrewDigit[(n1/100)-1+18]); 1.1015 + } else { 1.1016 + n1 -= 100; 1.1017 + } // if 1.1018 + } // for 1.1019 + 1.1020 + // Process digit for 10 - 90 1.1021 + int32_t n2; 1.1022 + if( n3 >= 10 ) 1.1023 + { 1.1024 + // Special process for 15 and 16 1.1025 + if(( 15 == n3 ) || (16 == n3)) { 1.1026 + // Special rule for religious reason... 1.1027 + // 15 is represented by 9 and 6, not 10 and 5 1.1028 + // 16 is represented by 9 and 7, not 10 and 6 1.1029 + n2 = 9; 1.1030 + thousandsGroup.Append(gHebrewDigit[ n2 - 1]); 1.1031 + } else { 1.1032 + n2 = n3 - (n3 % 10); 1.1033 + thousandsGroup.Append(gHebrewDigit[(n2/10)-1+9]); 1.1034 + } // if 1.1035 + n3 -= n2; 1.1036 + } // if 1.1037 + 1.1038 + // Process digit for 1 - 9 1.1039 + if ( n3 > 0) 1.1040 + thousandsGroup.Append(gHebrewDigit[n3-1]); 1.1041 + if (outputSep) 1.1042 + thousandsGroup.Append((char16_t)HEBREW_GERESH); 1.1043 + if (allText.IsEmpty()) 1.1044 + allText = thousandsGroup; 1.1045 + else 1.1046 + allText = thousandsGroup + allText; 1.1047 + ordinal /= 1000; 1.1048 + outputSep = true; 1.1049 + } while (ordinal >= 1); 1.1050 + 1.1051 + result.Append(allText); 1.1052 + return true; 1.1053 +} 1.1054 + 1.1055 + 1.1056 +static bool ArmenianToText(int32_t ordinal, nsString& result) 1.1057 +{ 1.1058 + if (ordinal < 1 || ordinal > 9999) { // zero or reach the limit of Armenian numbering system 1.1059 + return false; 1.1060 + } 1.1061 + 1.1062 + char16_t buf[NUM_BUF_SIZE]; 1.1063 + int32_t idx = NUM_BUF_SIZE; 1.1064 + int32_t d = 0; 1.1065 + do { 1.1066 + int32_t cur = ordinal % 10; 1.1067 + if (cur > 0) 1.1068 + { 1.1069 + char16_t u = 0x0530 + (d * 9) + cur; 1.1070 + buf[--idx] = u; 1.1071 + } 1.1072 + ++d; 1.1073 + ordinal /= 10; 1.1074 + } while (ordinal > 0); 1.1075 + result.Append(buf + idx, NUM_BUF_SIZE - idx); 1.1076 + return true; 1.1077 +} 1.1078 + 1.1079 + 1.1080 +static const char16_t gGeorgianValue [ 37 ] = { // 4 * 9 + 1 = 37 1.1081 +// 1 2 3 4 5 6 7 8 9 1.1082 + 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10F1, 0x10D7, 1.1083 +// 10 20 30 40 50 60 70 80 90 1.1084 + 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10F2, 0x10DD, 0x10DE, 0x10DF, 1.1085 +// 100 200 300 400 500 600 700 800 900 1.1086 + 0x10E0, 0x10E1, 0x10E2, 0x10F3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8, 1.1087 +// 1000 2000 3000 4000 5000 6000 7000 8000 9000 1.1088 + 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10F4, 0x10EF, 0x10F0, 1.1089 +// 10000 1.1090 + 0x10F5 1.1091 +}; 1.1092 +static bool GeorgianToText(int32_t ordinal, nsString& result) 1.1093 +{ 1.1094 + if (ordinal < 1 || ordinal > 19999) { // zero or reach the limit of Georgian numbering system 1.1095 + return false; 1.1096 + } 1.1097 + 1.1098 + char16_t buf[NUM_BUF_SIZE]; 1.1099 + int32_t idx = NUM_BUF_SIZE; 1.1100 + int32_t d = 0; 1.1101 + do { 1.1102 + int32_t cur = ordinal % 10; 1.1103 + if (cur > 0) 1.1104 + { 1.1105 + char16_t u = gGeorgianValue[(d * 9 ) + ( cur - 1)]; 1.1106 + buf[--idx] = u; 1.1107 + } 1.1108 + ++d; 1.1109 + ordinal /= 10; 1.1110 + } while (ordinal > 0); 1.1111 + result.Append(buf + idx, NUM_BUF_SIZE - idx); 1.1112 + return true; 1.1113 +} 1.1114 + 1.1115 +// Convert ordinal to Ethiopic numeric representation. 1.1116 +// The detail is available at http://www.ethiopic.org/Numerals/ 1.1117 +// The algorithm used here is based on the pseudo-code put up there by 1.1118 +// Daniel Yacob <yacob@geez.org>. 1.1119 +// Another reference is Unicode 3.0 standard section 11.1. 1.1120 +#define ETHIOPIC_ONE 0x1369 1.1121 +#define ETHIOPIC_TEN 0x1372 1.1122 +#define ETHIOPIC_HUNDRED 0x137B 1.1123 +#define ETHIOPIC_TEN_THOUSAND 0x137C 1.1124 + 1.1125 +static bool EthiopicToText(int32_t ordinal, nsString& result) 1.1126 +{ 1.1127 + if (ordinal < 1) { 1.1128 + return false; 1.1129 + } 1.1130 + nsAutoString asciiNumberString; // decimal string representation of ordinal 1.1131 + DecimalToText(ordinal, asciiNumberString); 1.1132 + uint8_t asciiStringLength = asciiNumberString.Length(); 1.1133 + 1.1134 + // If number length is odd, add a leading "0" 1.1135 + // the leading "0" preconditions the string to always have the 1.1136 + // leading tens place populated, this avoids a check within the loop. 1.1137 + // If we didn't add the leading "0", decrement asciiStringLength so 1.1138 + // it will be equivalent to a zero-based index in both cases. 1.1139 + if (asciiStringLength & 1) { 1.1140 + asciiNumberString.Insert(NS_LITERAL_STRING("0"), 0); 1.1141 + } else { 1.1142 + asciiStringLength--; 1.1143 + } 1.1144 + 1.1145 + // Iterate from the highest digits to lowest 1.1146 + // indexFromLeft indexes digits (0 = most significant) 1.1147 + // groupIndexFromRight indexes pairs of digits (0 = least significant) 1.1148 + for (uint8_t indexFromLeft = 0, groupIndexFromRight = asciiStringLength >> 1; 1.1149 + indexFromLeft <= asciiStringLength; 1.1150 + indexFromLeft += 2, groupIndexFromRight--) { 1.1151 + uint8_t tensValue = asciiNumberString.CharAt(indexFromLeft) & 0x0F; 1.1152 + uint8_t unitsValue = asciiNumberString.CharAt(indexFromLeft + 1) & 0x0F; 1.1153 + uint8_t groupValue = tensValue * 10 + unitsValue; 1.1154 + 1.1155 + bool oddGroup = (groupIndexFromRight & 1); 1.1156 + 1.1157 + // we want to clear ETHIOPIC_ONE when it is superfluous 1.1158 + if (ordinal > 1 && 1.1159 + groupValue == 1 && // one without a leading ten 1.1160 + (oddGroup || indexFromLeft == 0)) { // preceding (100) or leading the sequence 1.1161 + unitsValue = 0; 1.1162 + } 1.1163 + 1.1164 + // put it all together... 1.1165 + if (tensValue) { 1.1166 + // map onto Ethiopic "tens": 1.1167 + result.Append((char16_t) (tensValue + ETHIOPIC_TEN - 1)); 1.1168 + } 1.1169 + if (unitsValue) { 1.1170 + //map onto Ethiopic "units": 1.1171 + result.Append((char16_t) (unitsValue + ETHIOPIC_ONE - 1)); 1.1172 + } 1.1173 + // Add a separator for all even groups except the last, 1.1174 + // and for odd groups with non-zero value. 1.1175 + if (oddGroup) { 1.1176 + if (groupValue) { 1.1177 + result.Append((char16_t) ETHIOPIC_HUNDRED); 1.1178 + } 1.1179 + } else { 1.1180 + if (groupIndexFromRight) { 1.1181 + result.Append((char16_t) ETHIOPIC_TEN_THOUSAND); 1.1182 + } 1.1183 + } 1.1184 + } 1.1185 + return true; 1.1186 +} 1.1187 + 1.1188 + 1.1189 +/* static */ void 1.1190 +nsBulletFrame::AppendCounterText(int32_t aListStyleType, 1.1191 + int32_t aOrdinal, 1.1192 + nsString& result, 1.1193 + bool& isRTL) 1.1194 +{ 1.1195 + bool success = true; 1.1196 + int32_t fallback = NS_STYLE_LIST_STYLE_DECIMAL; 1.1197 + isRTL = false; 1.1198 + 1.1199 + switch (aListStyleType) { 1.1200 + case NS_STYLE_LIST_STYLE_NONE: // used by counters code only 1.1201 + break; 1.1202 + 1.1203 + case NS_STYLE_LIST_STYLE_DISC: // used by counters code only 1.1204 + // XXX We really need to do this the same way we do list bullets. 1.1205 + result.Append(char16_t(0x2022)); 1.1206 + break; 1.1207 + 1.1208 + case NS_STYLE_LIST_STYLE_CIRCLE: // used by counters code only 1.1209 + // XXX We really need to do this the same way we do list bullets. 1.1210 + result.Append(char16_t(0x25E6)); 1.1211 + break; 1.1212 + 1.1213 + case NS_STYLE_LIST_STYLE_SQUARE: // used by counters code only 1.1214 + // XXX We really need to do this the same way we do list bullets. 1.1215 + result.Append(char16_t(0x25FE)); 1.1216 + break; 1.1217 + 1.1218 + case NS_STYLE_LIST_STYLE_DECIMAL: 1.1219 + default: // CSS2 say "A users agent that does not recognize a numbering system 1.1220 + // should use 'decimal' 1.1221 + success = DecimalToText(aOrdinal, result); 1.1222 + NS_ASSERTION(success, "DecimalToText must never fail"); 1.1223 + break; 1.1224 + 1.1225 + case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO: 1.1226 + success = DecimalLeadingZeroToText(aOrdinal, result); 1.1227 + break; 1.1228 + 1.1229 + case NS_STYLE_LIST_STYLE_CJK_DECIMAL: 1.1230 + success = CharListDecimalToText(aOrdinal, result, gCJKDecimalChars); 1.1231 + break; 1.1232 + 1.1233 + case NS_STYLE_LIST_STYLE_LOWER_ROMAN: 1.1234 + success = RomanToText(aOrdinal, result, 1.1235 + gLowerRomanCharsA, gLowerRomanCharsB); 1.1236 + break; 1.1237 + case NS_STYLE_LIST_STYLE_UPPER_ROMAN: 1.1238 + success = RomanToText(aOrdinal, result, 1.1239 + gUpperRomanCharsA, gUpperRomanCharsB); 1.1240 + break; 1.1241 + 1.1242 + case NS_STYLE_LIST_STYLE_LOWER_ALPHA: 1.1243 + success = CharListToText(aOrdinal, result, gLowerAlphaChars, ALPHA_SIZE); 1.1244 + break; 1.1245 + 1.1246 + case NS_STYLE_LIST_STYLE_UPPER_ALPHA: 1.1247 + success = CharListToText(aOrdinal, result, gUpperAlphaChars, ALPHA_SIZE); 1.1248 + break; 1.1249 + 1.1250 + case NS_STYLE_LIST_STYLE_KATAKANA: 1.1251 + success = CharListToText(aOrdinal, result, gKatakanaChars, 1.1252 + KATAKANA_CHARS_SIZE); 1.1253 + break; 1.1254 + 1.1255 + case NS_STYLE_LIST_STYLE_HIRAGANA: 1.1256 + success = CharListToText(aOrdinal, result, gHiraganaChars, 1.1257 + HIRAGANA_CHARS_SIZE); 1.1258 + break; 1.1259 + 1.1260 + case NS_STYLE_LIST_STYLE_KATAKANA_IROHA: 1.1261 + success = CharListToText(aOrdinal, result, gKatakanaIrohaChars, 1.1262 + KATAKANA_IROHA_CHARS_SIZE); 1.1263 + break; 1.1264 + 1.1265 + case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA: 1.1266 + success = CharListToText(aOrdinal, result, gHiraganaIrohaChars, 1.1267 + HIRAGANA_IROHA_CHARS_SIZE); 1.1268 + break; 1.1269 + 1.1270 + case NS_STYLE_LIST_STYLE_LOWER_GREEK: 1.1271 + success = CharListToText(aOrdinal, result, gLowerGreekChars , 1.1272 + LOWER_GREEK_CHARS_SIZE); 1.1273 + break; 1.1274 + 1.1275 + case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC: 1.1276 + case NS_STYLE_LIST_STYLE_TRAD_CHINESE_INFORMAL: 1.1277 + case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL: 1.1278 + fallback = NS_STYLE_LIST_STYLE_CJK_DECIMAL; 1.1279 + success = 1.1280 + CJKIdeographicToText(aOrdinal, result, gDataTradChineseInformal); 1.1281 + break; 1.1282 + 1.1283 + case NS_STYLE_LIST_STYLE_TRAD_CHINESE_FORMAL: 1.1284 + case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL: 1.1285 + fallback = NS_STYLE_LIST_STYLE_CJK_DECIMAL; 1.1286 + success = CJKIdeographicToText(aOrdinal, result, gDataTradChineseFormal); 1.1287 + break; 1.1288 + 1.1289 + case NS_STYLE_LIST_STYLE_SIMP_CHINESE_INFORMAL: 1.1290 + case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL: 1.1291 + fallback = NS_STYLE_LIST_STYLE_CJK_DECIMAL; 1.1292 + success = 1.1293 + CJKIdeographicToText(aOrdinal, result, gDataSimpChineseInformal); 1.1294 + break; 1.1295 + 1.1296 + case NS_STYLE_LIST_STYLE_SIMP_CHINESE_FORMAL: 1.1297 + case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL: 1.1298 + fallback = NS_STYLE_LIST_STYLE_CJK_DECIMAL; 1.1299 + success = CJKIdeographicToText(aOrdinal, result, gDataSimpChineseFormal); 1.1300 + break; 1.1301 + 1.1302 + case NS_STYLE_LIST_STYLE_JAPANESE_INFORMAL: 1.1303 + case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL: 1.1304 + fallback = NS_STYLE_LIST_STYLE_CJK_DECIMAL; 1.1305 + success = CJKIdeographicToText(aOrdinal, result, gDataJapaneseInformal); 1.1306 + break; 1.1307 + 1.1308 + case NS_STYLE_LIST_STYLE_JAPANESE_FORMAL: 1.1309 + case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL: 1.1310 + fallback = NS_STYLE_LIST_STYLE_CJK_DECIMAL; 1.1311 + success = CJKIdeographicToText(aOrdinal, result, gDataJapaneseFormal); 1.1312 + break; 1.1313 + 1.1314 + case NS_STYLE_LIST_STYLE_KOREAN_HANGUL_FORMAL: 1.1315 + fallback = NS_STYLE_LIST_STYLE_CJK_DECIMAL; 1.1316 + success = 1.1317 + CJKIdeographicToText(aOrdinal, result, gDataKoreanHangulFormal); 1.1318 + break; 1.1319 + 1.1320 + case NS_STYLE_LIST_STYLE_KOREAN_HANJA_INFORMAL: 1.1321 + fallback = NS_STYLE_LIST_STYLE_CJK_DECIMAL; 1.1322 + success = 1.1323 + CJKIdeographicToText(aOrdinal, result, gDataKoreanHanjaInformal); 1.1324 + break; 1.1325 + 1.1326 + case NS_STYLE_LIST_STYLE_KOREAN_HANJA_FORMAL: 1.1327 + fallback = NS_STYLE_LIST_STYLE_CJK_DECIMAL; 1.1328 + success = CJKIdeographicToText(aOrdinal, result, gDataKoreanHanjaFormal); 1.1329 + break; 1.1330 + 1.1331 + case NS_STYLE_LIST_STYLE_HEBREW: 1.1332 + isRTL = true; 1.1333 + success = HebrewToText(aOrdinal, result); 1.1334 + break; 1.1335 + 1.1336 + case NS_STYLE_LIST_STYLE_ARMENIAN: 1.1337 + success = ArmenianToText(aOrdinal, result); 1.1338 + break; 1.1339 + 1.1340 + case NS_STYLE_LIST_STYLE_GEORGIAN: 1.1341 + success = GeorgianToText(aOrdinal, result); 1.1342 + break; 1.1343 + 1.1344 + case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC: 1.1345 + success = OtherDecimalToText(aOrdinal, 0x0660, result); 1.1346 + break; 1.1347 + 1.1348 + case NS_STYLE_LIST_STYLE_MOZ_PERSIAN: 1.1349 + case NS_STYLE_LIST_STYLE_MOZ_URDU: 1.1350 + success = OtherDecimalToText(aOrdinal, 0x06f0, result); 1.1351 + break; 1.1352 + 1.1353 + case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI: 1.1354 + success = OtherDecimalToText(aOrdinal, 0x0966, result); 1.1355 + break; 1.1356 + 1.1357 + case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI: 1.1358 + success = OtherDecimalToText(aOrdinal, 0x0a66, result); 1.1359 + break; 1.1360 + 1.1361 + case NS_STYLE_LIST_STYLE_MOZ_GUJARATI: 1.1362 + success = OtherDecimalToText(aOrdinal, 0x0AE6, result); 1.1363 + break; 1.1364 + 1.1365 + case NS_STYLE_LIST_STYLE_MOZ_ORIYA: 1.1366 + success = OtherDecimalToText(aOrdinal, 0x0B66, result); 1.1367 + break; 1.1368 + 1.1369 + case NS_STYLE_LIST_STYLE_MOZ_KANNADA: 1.1370 + success = OtherDecimalToText(aOrdinal, 0x0CE6, result); 1.1371 + break; 1.1372 + 1.1373 + case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM: 1.1374 + success = OtherDecimalToText(aOrdinal, 0x0D66, result); 1.1375 + break; 1.1376 + 1.1377 + case NS_STYLE_LIST_STYLE_MOZ_THAI: 1.1378 + success = OtherDecimalToText(aOrdinal, 0x0E50, result); 1.1379 + break; 1.1380 + 1.1381 + case NS_STYLE_LIST_STYLE_MOZ_LAO: 1.1382 + success = OtherDecimalToText(aOrdinal, 0x0ED0, result); 1.1383 + break; 1.1384 + 1.1385 + case NS_STYLE_LIST_STYLE_MOZ_MYANMAR: 1.1386 + success = OtherDecimalToText(aOrdinal, 0x1040, result); 1.1387 + break; 1.1388 + 1.1389 + case NS_STYLE_LIST_STYLE_MOZ_KHMER: 1.1390 + success = OtherDecimalToText(aOrdinal, 0x17E0, result); 1.1391 + break; 1.1392 + 1.1393 + case NS_STYLE_LIST_STYLE_MOZ_BENGALI: 1.1394 + success = OtherDecimalToText(aOrdinal, 0x09E6, result); 1.1395 + break; 1.1396 + 1.1397 + case NS_STYLE_LIST_STYLE_MOZ_TELUGU: 1.1398 + success = OtherDecimalToText(aOrdinal, 0x0C66, result); 1.1399 + break; 1.1400 + 1.1401 + case NS_STYLE_LIST_STYLE_MOZ_TAMIL: 1.1402 + success = TamilToText(aOrdinal, result); 1.1403 + break; 1.1404 + 1.1405 + case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM: 1.1406 + fallback = NS_STYLE_LIST_STYLE_CJK_DECIMAL; 1.1407 + success = CharListToText(aOrdinal, result, gCJKHeavenlyStemChars, 1.1408 + CJK_HEAVENLY_STEM_CHARS_SIZE); 1.1409 + break; 1.1410 + 1.1411 + case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH: 1.1412 + fallback = NS_STYLE_LIST_STYLE_CJK_DECIMAL; 1.1413 + success = CharListToText(aOrdinal, result, gCJKEarthlyBranchChars, 1.1414 + CJK_EARTHLY_BRANCH_CHARS_SIZE); 1.1415 + break; 1.1416 + 1.1417 + case NS_STYLE_LIST_STYLE_MOZ_HANGUL: 1.1418 + success = CharListToText(aOrdinal, result, gHangulChars, HANGUL_CHARS_SIZE); 1.1419 + break; 1.1420 + 1.1421 + case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT: 1.1422 + success = CharListToText(aOrdinal, result, gHangulConsonantChars, 1.1423 + HANGUL_CONSONANT_CHARS_SIZE); 1.1424 + break; 1.1425 + 1.1426 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME: 1.1427 + success = CharListToText(aOrdinal, result, gEthiopicHalehameChars, 1.1428 + ETHIOPIC_HALEHAME_CHARS_SIZE); 1.1429 + break; 1.1430 + 1.1431 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC: 1.1432 + success = EthiopicToText(aOrdinal, result); 1.1433 + break; 1.1434 + 1.1435 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM: 1.1436 + success = CharListToText(aOrdinal, result, gEthiopicHalehameAmChars, 1.1437 + ETHIOPIC_HALEHAME_AM_CHARS_SIZE); 1.1438 + break; 1.1439 + 1.1440 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER: 1.1441 + success = CharListToText(aOrdinal, result, gEthiopicHalehameTiErChars, 1.1442 + ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE); 1.1443 + break; 1.1444 + 1.1445 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET: 1.1446 + success = CharListToText(aOrdinal, result, gEthiopicHalehameTiEtChars, 1.1447 + ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE); 1.1448 + break; 1.1449 + } 1.1450 + if (!success) { 1.1451 + AppendCounterText(fallback, aOrdinal, result, isRTL); 1.1452 + } 1.1453 +} 1.1454 + 1.1455 +/* static */ void 1.1456 +nsBulletFrame::GetListItemSuffix(int32_t aListStyleType, 1.1457 + nsString& aResult, 1.1458 + bool& aSuppressPadding) 1.1459 +{ 1.1460 + aResult = '.'; 1.1461 + aSuppressPadding = false; 1.1462 + 1.1463 + switch (aListStyleType) { 1.1464 + case NS_STYLE_LIST_STYLE_NONE: // used by counters code only 1.1465 + case NS_STYLE_LIST_STYLE_DISC: // used by counters code only 1.1466 + case NS_STYLE_LIST_STYLE_CIRCLE: // used by counters code only 1.1467 + case NS_STYLE_LIST_STYLE_SQUARE: // used by counters code only 1.1468 + aResult.Truncate(); 1.1469 + break; 1.1470 + 1.1471 + case NS_STYLE_LIST_STYLE_CJK_DECIMAL: 1.1472 + case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC: 1.1473 + case NS_STYLE_LIST_STYLE_TRAD_CHINESE_INFORMAL: 1.1474 + case NS_STYLE_LIST_STYLE_TRAD_CHINESE_FORMAL: 1.1475 + case NS_STYLE_LIST_STYLE_SIMP_CHINESE_INFORMAL: 1.1476 + case NS_STYLE_LIST_STYLE_SIMP_CHINESE_FORMAL: 1.1477 + case NS_STYLE_LIST_STYLE_JAPANESE_INFORMAL: 1.1478 + case NS_STYLE_LIST_STYLE_JAPANESE_FORMAL: 1.1479 + case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL: 1.1480 + case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL: 1.1481 + case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL: 1.1482 + case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL: 1.1483 + case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL: 1.1484 + case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL: 1.1485 + case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM: 1.1486 + case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH: 1.1487 + aResult = 0x3001; 1.1488 + aSuppressPadding = true; 1.1489 + break; 1.1490 + 1.1491 + case NS_STYLE_LIST_STYLE_KOREAN_HANGUL_FORMAL: 1.1492 + case NS_STYLE_LIST_STYLE_KOREAN_HANJA_INFORMAL: 1.1493 + case NS_STYLE_LIST_STYLE_KOREAN_HANJA_FORMAL: 1.1494 + case NS_STYLE_LIST_STYLE_MOZ_HANGUL: 1.1495 + case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT: 1.1496 + aResult = ','; 1.1497 + break; 1.1498 + } 1.1499 +} 1.1500 + 1.1501 +void 1.1502 +nsBulletFrame::GetListItemText(const nsStyleList& aListStyle, 1.1503 + nsString& result) 1.1504 +{ 1.1505 + const nsStyleVisibility* vis = StyleVisibility(); 1.1506 + 1.1507 + NS_ASSERTION(aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_NONE && 1.1508 + aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_DISC && 1.1509 + aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_CIRCLE && 1.1510 + aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_SQUARE, 1.1511 + "we should be using specialized code for these types"); 1.1512 + 1.1513 + result.Truncate(); 1.1514 + AppendCounterText(aListStyle.mListStyleType, mOrdinal, result, mTextIsRTL); 1.1515 + 1.1516 + nsAutoString suffix; 1.1517 + GetListItemSuffix(aListStyle.mListStyleType, suffix, mSuppressPadding); 1.1518 + 1.1519 + // We're not going to do proper Bidi reordering on the list item marker, but 1.1520 + // just display the whole thing as RTL or LTR, so we fake reordering by 1.1521 + // appending the suffix to the end of the list item marker if the 1.1522 + // directionality of the characters is the same as the style direction or 1.1523 + // prepending it to the beginning if they are different. 1.1524 + result = (mTextIsRTL == (vis->mDirection == NS_STYLE_DIRECTION_RTL)) ? 1.1525 + result + suffix : suffix + result; 1.1526 +} 1.1527 + 1.1528 +#define MIN_BULLET_SIZE 1 1.1529 + 1.1530 + 1.1531 +void 1.1532 +nsBulletFrame::GetDesiredSize(nsPresContext* aCX, 1.1533 + nsRenderingContext *aRenderingContext, 1.1534 + nsHTMLReflowMetrics& aMetrics, 1.1535 + float aFontSizeInflation) 1.1536 +{ 1.1537 + // Reset our padding. If we need it, we'll set it below. 1.1538 + mPadding.SizeTo(0, 0, 0, 0); 1.1539 + 1.1540 + const nsStyleList* myList = StyleList(); 1.1541 + nscoord ascent; 1.1542 + 1.1543 + RemoveStateBits(BULLET_FRAME_IMAGE_LOADING); 1.1544 + 1.1545 + if (myList->GetListStyleImage() && mImageRequest) { 1.1546 + uint32_t status; 1.1547 + mImageRequest->GetImageStatus(&status); 1.1548 + if (status & imgIRequest::STATUS_SIZE_AVAILABLE && 1.1549 + !(status & imgIRequest::STATUS_ERROR)) { 1.1550 + // auto size the image 1.1551 + aMetrics.Width() = mIntrinsicSize.width; 1.1552 + aMetrics.SetTopAscent(aMetrics.Height() = mIntrinsicSize.height); 1.1553 + 1.1554 + AddStateBits(BULLET_FRAME_IMAGE_LOADING); 1.1555 + 1.1556 + return; 1.1557 + } 1.1558 + } 1.1559 + 1.1560 + // If we're getting our desired size and don't have an image, reset 1.1561 + // mIntrinsicSize to (0,0). Otherwise, if we used to have an image, it 1.1562 + // changed, and the new one is coming in, but we're reflowing before it's 1.1563 + // fully there, we'll end up with mIntrinsicSize not matching our size, but 1.1564 + // won't trigger a reflow in OnStartContainer (because mIntrinsicSize will 1.1565 + // match the image size). 1.1566 + mIntrinsicSize.SizeTo(0, 0); 1.1567 + 1.1568 + nsRefPtr<nsFontMetrics> fm; 1.1569 + nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), 1.1570 + aFontSizeInflation); 1.1571 + nscoord bulletSize; 1.1572 + 1.1573 + nsAutoString text; 1.1574 + switch (myList->mListStyleType) { 1.1575 + case NS_STYLE_LIST_STYLE_NONE: 1.1576 + aMetrics.Width() = aMetrics.Height() = 0; 1.1577 + aMetrics.SetTopAscent(0); 1.1578 + break; 1.1579 + 1.1580 + case NS_STYLE_LIST_STYLE_DISC: 1.1581 + case NS_STYLE_LIST_STYLE_CIRCLE: 1.1582 + case NS_STYLE_LIST_STYLE_SQUARE: 1.1583 + ascent = fm->MaxAscent(); 1.1584 + bulletSize = std::max(nsPresContext::CSSPixelsToAppUnits(MIN_BULLET_SIZE), 1.1585 + NSToCoordRound(0.8f * (float(ascent) / 2.0f))); 1.1586 + mPadding.bottom = NSToCoordRound(float(ascent) / 8.0f); 1.1587 + aMetrics.Width() = aMetrics.Height() = bulletSize; 1.1588 + aMetrics.SetTopAscent(bulletSize + mPadding.bottom); 1.1589 + break; 1.1590 + 1.1591 + default: 1.1592 + case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO: 1.1593 + case NS_STYLE_LIST_STYLE_DECIMAL: 1.1594 + case NS_STYLE_LIST_STYLE_CJK_DECIMAL: 1.1595 + case NS_STYLE_LIST_STYLE_LOWER_ROMAN: 1.1596 + case NS_STYLE_LIST_STYLE_UPPER_ROMAN: 1.1597 + case NS_STYLE_LIST_STYLE_LOWER_ALPHA: 1.1598 + case NS_STYLE_LIST_STYLE_UPPER_ALPHA: 1.1599 + case NS_STYLE_LIST_STYLE_KATAKANA: 1.1600 + case NS_STYLE_LIST_STYLE_HIRAGANA: 1.1601 + case NS_STYLE_LIST_STYLE_KATAKANA_IROHA: 1.1602 + case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA: 1.1603 + case NS_STYLE_LIST_STYLE_LOWER_GREEK: 1.1604 + case NS_STYLE_LIST_STYLE_HEBREW: 1.1605 + case NS_STYLE_LIST_STYLE_ARMENIAN: 1.1606 + case NS_STYLE_LIST_STYLE_GEORGIAN: 1.1607 + case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC: 1.1608 + case NS_STYLE_LIST_STYLE_JAPANESE_INFORMAL: 1.1609 + case NS_STYLE_LIST_STYLE_JAPANESE_FORMAL: 1.1610 + case NS_STYLE_LIST_STYLE_KOREAN_HANGUL_FORMAL: 1.1611 + case NS_STYLE_LIST_STYLE_KOREAN_HANJA_INFORMAL: 1.1612 + case NS_STYLE_LIST_STYLE_KOREAN_HANJA_FORMAL: 1.1613 + case NS_STYLE_LIST_STYLE_SIMP_CHINESE_INFORMAL: 1.1614 + case NS_STYLE_LIST_STYLE_SIMP_CHINESE_FORMAL: 1.1615 + case NS_STYLE_LIST_STYLE_TRAD_CHINESE_INFORMAL: 1.1616 + case NS_STYLE_LIST_STYLE_TRAD_CHINESE_FORMAL: 1.1617 + case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL: 1.1618 + case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL: 1.1619 + case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL: 1.1620 + case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL: 1.1621 + case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL: 1.1622 + case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL: 1.1623 + case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM: 1.1624 + case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH: 1.1625 + case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC: 1.1626 + case NS_STYLE_LIST_STYLE_MOZ_PERSIAN: 1.1627 + case NS_STYLE_LIST_STYLE_MOZ_URDU: 1.1628 + case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI: 1.1629 + case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI: 1.1630 + case NS_STYLE_LIST_STYLE_MOZ_GUJARATI: 1.1631 + case NS_STYLE_LIST_STYLE_MOZ_ORIYA: 1.1632 + case NS_STYLE_LIST_STYLE_MOZ_KANNADA: 1.1633 + case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM: 1.1634 + case NS_STYLE_LIST_STYLE_MOZ_BENGALI: 1.1635 + case NS_STYLE_LIST_STYLE_MOZ_TAMIL: 1.1636 + case NS_STYLE_LIST_STYLE_MOZ_TELUGU: 1.1637 + case NS_STYLE_LIST_STYLE_MOZ_THAI: 1.1638 + case NS_STYLE_LIST_STYLE_MOZ_LAO: 1.1639 + case NS_STYLE_LIST_STYLE_MOZ_MYANMAR: 1.1640 + case NS_STYLE_LIST_STYLE_MOZ_KHMER: 1.1641 + case NS_STYLE_LIST_STYLE_MOZ_HANGUL: 1.1642 + case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT: 1.1643 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME: 1.1644 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC: 1.1645 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM: 1.1646 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER: 1.1647 + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET: 1.1648 + GetListItemText(*myList, text); 1.1649 + aMetrics.Height() = fm->MaxHeight(); 1.1650 + aRenderingContext->SetFont(fm); 1.1651 + aMetrics.Width() = 1.1652 + nsLayoutUtils::GetStringWidth(this, aRenderingContext, 1.1653 + text.get(), text.Length()); 1.1654 + aMetrics.SetTopAscent(fm->MaxAscent()); 1.1655 + break; 1.1656 + } 1.1657 +} 1.1658 + 1.1659 +nsresult 1.1660 +nsBulletFrame::Reflow(nsPresContext* aPresContext, 1.1661 + nsHTMLReflowMetrics& aMetrics, 1.1662 + const nsHTMLReflowState& aReflowState, 1.1663 + nsReflowStatus& aStatus) 1.1664 +{ 1.1665 + DO_GLOBAL_REFLOW_COUNT("nsBulletFrame"); 1.1666 + DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); 1.1667 + 1.1668 + float inflation = nsLayoutUtils::FontSizeInflationFor(this); 1.1669 + SetFontSizeInflation(inflation); 1.1670 + 1.1671 + // Get the base size 1.1672 + // This will also set mSuppressPadding appropriately (via GetListItemText()) 1.1673 + // for the builtin counter styles with ideographic comma as suffix where the 1.1674 + // default padding from ua.css is not desired. 1.1675 + GetDesiredSize(aPresContext, aReflowState.rendContext, aMetrics, inflation); 1.1676 + 1.1677 + // Add in the border and padding; split the top/bottom between the 1.1678 + // ascent and descent to make things look nice 1.1679 + const nsMargin& borderPadding = aReflowState.ComputedPhysicalBorderPadding(); 1.1680 + if (!mSuppressPadding || 1.1681 + aPresContext->HasAuthorSpecifiedRules(this, 1.1682 + NS_AUTHOR_SPECIFIED_PADDING)) { 1.1683 + mPadding.top += NSToCoordRound(borderPadding.top * inflation); 1.1684 + mPadding.right += NSToCoordRound(borderPadding.right * inflation); 1.1685 + mPadding.bottom += NSToCoordRound(borderPadding.bottom * inflation); 1.1686 + mPadding.left += NSToCoordRound(borderPadding.left * inflation); 1.1687 + } 1.1688 + aMetrics.Width() += mPadding.left + mPadding.right; 1.1689 + aMetrics.Height() += mPadding.top + mPadding.bottom; 1.1690 + aMetrics.SetTopAscent(aMetrics.TopAscent() + mPadding.top); 1.1691 + 1.1692 + // XXX this is a bit of a hack, we're assuming that no glyphs used for bullets 1.1693 + // overflow their font-boxes. It'll do for now; to fix it for real, we really 1.1694 + // should rewrite all the text-handling code here to use gfxTextRun (bug 1.1695 + // 397294). 1.1696 + aMetrics.SetOverflowAreasToDesiredBounds(); 1.1697 + 1.1698 + aStatus = NS_FRAME_COMPLETE; 1.1699 + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); 1.1700 + return NS_OK; 1.1701 +} 1.1702 + 1.1703 +/* virtual */ nscoord 1.1704 +nsBulletFrame::GetMinWidth(nsRenderingContext *aRenderingContext) 1.1705 +{ 1.1706 + nsHTMLReflowMetrics metrics(GetWritingMode()); 1.1707 + DISPLAY_MIN_WIDTH(this, metrics.Width()); 1.1708 + GetDesiredSize(PresContext(), aRenderingContext, metrics, 1.0f); 1.1709 + return metrics.Width(); 1.1710 +} 1.1711 + 1.1712 +/* virtual */ nscoord 1.1713 +nsBulletFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) 1.1714 +{ 1.1715 + nsHTMLReflowMetrics metrics(GetWritingMode()); 1.1716 + DISPLAY_PREF_WIDTH(this, metrics.Width()); 1.1717 + GetDesiredSize(PresContext(), aRenderingContext, metrics, 1.0f); 1.1718 + return metrics.Width(); 1.1719 +} 1.1720 + 1.1721 +NS_IMETHODIMP 1.1722 +nsBulletFrame::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData) 1.1723 +{ 1.1724 + if (aType == imgINotificationObserver::SIZE_AVAILABLE) { 1.1725 + nsCOMPtr<imgIContainer> image; 1.1726 + aRequest->GetImage(getter_AddRefs(image)); 1.1727 + return OnStartContainer(aRequest, image); 1.1728 + } 1.1729 + 1.1730 + if (aType == imgINotificationObserver::FRAME_UPDATE) { 1.1731 + // The image has changed. 1.1732 + // Invalidate the entire content area. Maybe it's not optimal but it's simple and 1.1733 + // always correct, and I'll be a stunned mullet if it ever matters for performance 1.1734 + InvalidateFrame(); 1.1735 + } 1.1736 + 1.1737 + if (aType == imgINotificationObserver::IS_ANIMATED) { 1.1738 + // Register the image request with the refresh driver now that we know it's 1.1739 + // animated. 1.1740 + if (aRequest == mImageRequest) { 1.1741 + nsLayoutUtils::RegisterImageRequest(PresContext(), mImageRequest, 1.1742 + &mRequestRegistered); 1.1743 + } 1.1744 + } 1.1745 + 1.1746 + return NS_OK; 1.1747 +} 1.1748 + 1.1749 +nsresult nsBulletFrame::OnStartContainer(imgIRequest *aRequest, 1.1750 + imgIContainer *aImage) 1.1751 +{ 1.1752 + if (!aImage) return NS_ERROR_INVALID_ARG; 1.1753 + if (!aRequest) return NS_ERROR_INVALID_ARG; 1.1754 + 1.1755 + uint32_t status; 1.1756 + aRequest->GetImageStatus(&status); 1.1757 + if (status & imgIRequest::STATUS_ERROR) { 1.1758 + return NS_OK; 1.1759 + } 1.1760 + 1.1761 + nscoord w, h; 1.1762 + aImage->GetWidth(&w); 1.1763 + aImage->GetHeight(&h); 1.1764 + 1.1765 + nsPresContext* presContext = PresContext(); 1.1766 + 1.1767 + nsSize newsize(nsPresContext::CSSPixelsToAppUnits(w), 1.1768 + nsPresContext::CSSPixelsToAppUnits(h)); 1.1769 + 1.1770 + if (mIntrinsicSize != newsize) { 1.1771 + mIntrinsicSize = newsize; 1.1772 + 1.1773 + // Now that the size is available (or an error occurred), trigger 1.1774 + // a reflow of the bullet frame. 1.1775 + nsIPresShell *shell = presContext->GetPresShell(); 1.1776 + if (shell) { 1.1777 + shell->FrameNeedsReflow(this, nsIPresShell::eStyleChange, 1.1778 + NS_FRAME_IS_DIRTY); 1.1779 + } 1.1780 + } 1.1781 + 1.1782 + // Handle animations 1.1783 + aImage->SetAnimationMode(presContext->ImageAnimationMode()); 1.1784 + // Ensure the animation (if any) is started. Note: There is no 1.1785 + // corresponding call to Decrement for this. This Increment will be 1.1786 + // 'cleaned up' by the Request when it is destroyed, but only then. 1.1787 + aRequest->IncrementAnimationConsumers(); 1.1788 + 1.1789 + return NS_OK; 1.1790 +} 1.1791 + 1.1792 +void 1.1793 +nsBulletFrame::GetLoadGroup(nsPresContext *aPresContext, nsILoadGroup **aLoadGroup) 1.1794 +{ 1.1795 + if (!aPresContext) 1.1796 + return; 1.1797 + 1.1798 + NS_PRECONDITION(nullptr != aLoadGroup, "null OUT parameter pointer"); 1.1799 + 1.1800 + nsIPresShell *shell = aPresContext->GetPresShell(); 1.1801 + 1.1802 + if (!shell) 1.1803 + return; 1.1804 + 1.1805 + nsIDocument *doc = shell->GetDocument(); 1.1806 + if (!doc) 1.1807 + return; 1.1808 + 1.1809 + *aLoadGroup = doc->GetDocumentLoadGroup().take(); 1.1810 +} 1.1811 + 1.1812 +union VoidPtrOrFloat { 1.1813 + VoidPtrOrFloat() : p(nullptr) {} 1.1814 + 1.1815 + void *p; 1.1816 + float f; 1.1817 +}; 1.1818 + 1.1819 +float 1.1820 +nsBulletFrame::GetFontSizeInflation() const 1.1821 +{ 1.1822 + if (!HasFontSizeInflation()) { 1.1823 + return 1.0f; 1.1824 + } 1.1825 + VoidPtrOrFloat u; 1.1826 + u.p = Properties().Get(FontSizeInflationProperty()); 1.1827 + return u.f; 1.1828 +} 1.1829 + 1.1830 +void 1.1831 +nsBulletFrame::SetFontSizeInflation(float aInflation) 1.1832 +{ 1.1833 + if (aInflation == 1.0f) { 1.1834 + if (HasFontSizeInflation()) { 1.1835 + RemoveStateBits(BULLET_FRAME_HAS_FONT_INFLATION); 1.1836 + Properties().Delete(FontSizeInflationProperty()); 1.1837 + } 1.1838 + return; 1.1839 + } 1.1840 + 1.1841 + AddStateBits(BULLET_FRAME_HAS_FONT_INFLATION); 1.1842 + VoidPtrOrFloat u; 1.1843 + u.f = aInflation; 1.1844 + Properties().Set(FontSizeInflationProperty(), u.p); 1.1845 +} 1.1846 + 1.1847 +already_AddRefed<imgIContainer> 1.1848 +nsBulletFrame::GetImage() const 1.1849 +{ 1.1850 + if (mImageRequest && StyleList()->GetListStyleImage()) { 1.1851 + nsCOMPtr<imgIContainer> imageCon; 1.1852 + mImageRequest->GetImage(getter_AddRefs(imageCon)); 1.1853 + return imageCon.forget(); 1.1854 + } 1.1855 + 1.1856 + return nullptr; 1.1857 +} 1.1858 + 1.1859 +nscoord 1.1860 +nsBulletFrame::GetBaseline() const 1.1861 +{ 1.1862 + nscoord ascent = 0, bottomPadding; 1.1863 + if (GetStateBits() & BULLET_FRAME_IMAGE_LOADING) { 1.1864 + ascent = GetRect().height; 1.1865 + } else { 1.1866 + nsRefPtr<nsFontMetrics> fm; 1.1867 + nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), 1.1868 + GetFontSizeInflation()); 1.1869 + const nsStyleList* myList = StyleList(); 1.1870 + switch (myList->mListStyleType) { 1.1871 + case NS_STYLE_LIST_STYLE_NONE: 1.1872 + break; 1.1873 + 1.1874 + case NS_STYLE_LIST_STYLE_DISC: 1.1875 + case NS_STYLE_LIST_STYLE_CIRCLE: 1.1876 + case NS_STYLE_LIST_STYLE_SQUARE: 1.1877 + ascent = fm->MaxAscent(); 1.1878 + bottomPadding = NSToCoordRound(float(ascent) / 8.0f); 1.1879 + ascent = std::max(nsPresContext::CSSPixelsToAppUnits(MIN_BULLET_SIZE), 1.1880 + NSToCoordRound(0.8f * (float(ascent) / 2.0f))); 1.1881 + ascent += bottomPadding; 1.1882 + break; 1.1883 + 1.1884 + default: 1.1885 + ascent = fm->MaxAscent(); 1.1886 + break; 1.1887 + } 1.1888 + } 1.1889 + return ascent + GetUsedBorderAndPadding().top; 1.1890 +} 1.1891 + 1.1892 + 1.1893 + 1.1894 + 1.1895 + 1.1896 + 1.1897 + 1.1898 + 1.1899 +NS_IMPL_ISUPPORTS(nsBulletListener, imgINotificationObserver) 1.1900 + 1.1901 +nsBulletListener::nsBulletListener() : 1.1902 + mFrame(nullptr) 1.1903 +{ 1.1904 +} 1.1905 + 1.1906 +nsBulletListener::~nsBulletListener() 1.1907 +{ 1.1908 +} 1.1909 + 1.1910 +NS_IMETHODIMP 1.1911 +nsBulletListener::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData) 1.1912 +{ 1.1913 + if (!mFrame) 1.1914 + return NS_ERROR_FAILURE; 1.1915 + return mFrame->Notify(aRequest, aType, aData); 1.1916 +}