layout/generic/nsBulletFrame.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial