Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(225)

Side by Side Diff: Source/core/rendering/RenderListMarker.cpp

Issue 931423003: Rename rendering/RenderList* to layout/LayoutList* (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Remove spurious LayoutLayerModelObject reference Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/core/rendering/RenderListMarker.h ('k') | Source/core/rendering/RenderText.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserv ed.
5 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
6 * Copyright (C) 2010 Daniel Bates (dbates@intudata.com)
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25 #include "config.h"
26 #include "core/rendering/RenderListMarker.h"
27
28 #include "core/fetch/ImageResource.h"
29 #include "core/layout/Layer.h"
30 #include "core/layout/TextRunConstructor.h"
31 #include "core/paint/ListMarkerPainter.h"
32 #include "core/rendering/RenderListItem.h"
33 #include "platform/fonts/Font.h"
34 #include "wtf/text/StringBuilder.h"
35
36 namespace blink {
37
38 const int cMarkerPadding = 7;
39
40 enum SequenceType { NumericSequence, AlphabeticSequence };
41
42 static String toRoman(int number, bool upper)
43 {
44 // FIXME: CSS3 describes how to make this work for much larger numbers,
45 // using overbars and special characters. It also specifies the characters
46 // in the range U+2160 to U+217F instead of standard ASCII ones.
47 ASSERT(number >= 1 && number <= 3999);
48
49 // Big enough to store largest roman number less than 3999 which
50 // is 3888 (MMMDCCCLXXXVIII)
51 const int lettersSize = 15;
52 LChar letters[lettersSize];
53
54 int length = 0;
55 const LChar ldigits[] = { 'i', 'v', 'x', 'l', 'c', 'd', 'm' };
56 const LChar udigits[] = { 'I', 'V', 'X', 'L', 'C', 'D', 'M' };
57 const LChar* digits = upper ? udigits : ldigits;
58 int d = 0;
59 do {
60 int num = number % 10;
61 if (num % 5 < 4)
62 for (int i = num % 5; i > 0; i--)
63 letters[lettersSize - ++length] = digits[d];
64 if (num >= 4 && num <= 8)
65 letters[lettersSize - ++length] = digits[d + 1];
66 if (num == 9)
67 letters[lettersSize - ++length] = digits[d + 2];
68 if (num % 5 == 4)
69 letters[lettersSize - ++length] = digits[d];
70 number /= 10;
71 d += 2;
72 } while (number);
73
74 ASSERT(length <= lettersSize);
75 return String(&letters[lettersSize - length], length);
76 }
77
78 // The typedef is needed because taking sizeof(number) in the const expression b elow doesn't work with some compilers.
79 // This is likely the case because of the template.
80 typedef int numberType;
81
82 template <typename CharacterType>
83 static inline String toAlphabeticOrNumeric(numberType number, const CharacterTyp e* sequence, unsigned sequenceSize, SequenceType type)
84 {
85 ASSERT(sequenceSize >= 2);
86
87 const int lettersSize = sizeof(numberType) * 8 + 1; // Binary is the worst c ase; requires one character per bit plus a minus sign.
88
89 CharacterType letters[lettersSize];
90
91 bool isNegativeNumber = false;
92 unsigned numberShadow = number;
93 if (type == AlphabeticSequence) {
94 ASSERT(number > 0);
95 --numberShadow;
96 } else if (number < 0) {
97 numberShadow = -number;
98 isNegativeNumber = true;
99 }
100 letters[lettersSize - 1] = sequence[numberShadow % sequenceSize];
101 int length = 1;
102
103 if (type == AlphabeticSequence) {
104 while ((numberShadow /= sequenceSize) > 0) {
105 --numberShadow;
106 letters[lettersSize - ++length] = sequence[numberShadow % sequenceSi ze];
107 }
108 } else {
109 while ((numberShadow /= sequenceSize) > 0)
110 letters[lettersSize - ++length] = sequence[numberShadow % sequenceSi ze];
111 }
112 if (isNegativeNumber)
113 letters[lettersSize - ++length] = hyphenMinus;
114
115 ASSERT(length <= lettersSize);
116 return String(&letters[lettersSize - length], length);
117 }
118
119 template <typename CharacterType>
120 static String toSymbolic(int number, const CharacterType* symbols, unsigned symb olsSize)
121 {
122 ASSERT(number > 0);
123 ASSERT(symbolsSize >= 1);
124 unsigned numberShadow = number;
125 --numberShadow;
126
127 // The asterisks list-style-type is the worst case; we show |numberShadow| a sterisks.
128 StringBuilder letters;
129 letters.append(symbols[numberShadow % symbolsSize]);
130 unsigned numSymbols = numberShadow / symbolsSize;
131 while (numSymbols--)
132 letters.append(symbols[numberShadow % symbolsSize]);
133 return letters.toString();
134 }
135
136 template <typename CharacterType>
137 static String toAlphabetic(int number, const CharacterType* alphabet, unsigned a lphabetSize)
138 {
139 return toAlphabeticOrNumeric(number, alphabet, alphabetSize, AlphabeticSeque nce);
140 }
141
142 template <typename CharacterType>
143 static String toNumeric(int number, const CharacterType* numerals, unsigned nume ralsSize)
144 {
145 return toAlphabeticOrNumeric(number, numerals, numeralsSize, NumericSequence );
146 }
147
148 template <typename CharacterType, size_t size>
149 static inline String toAlphabetic(int number, const CharacterType(&alphabet)[siz e])
150 {
151 return toAlphabetic(number, alphabet, size);
152 }
153
154 template <typename CharacterType, size_t size>
155 static inline String toNumeric(int number, const CharacterType(&alphabet)[size])
156 {
157 return toNumeric(number, alphabet, size);
158 }
159
160 template <typename CharacterType, size_t size>
161 static inline String toSymbolic(int number, const CharacterType(&alphabet)[size] )
162 {
163 return toSymbolic(number, alphabet, size);
164 }
165
166 static int toHebrewUnder1000(int number, UChar letters[5])
167 {
168 // FIXME: CSS3 mentions various refinements not implemented here.
169 // FIXME: Should take a look at Mozilla's HebrewToText function (in nsBullet Frame).
170 ASSERT(number >= 0 && number < 1000);
171 int length = 0;
172 int fourHundreds = number / 400;
173 for (int i = 0; i < fourHundreds; i++)
174 letters[length++] = 1511 + 3;
175 number %= 400;
176 if (number / 100)
177 letters[length++] = 1511 + (number / 100) - 1;
178 number %= 100;
179 if (number == 15 || number == 16) {
180 letters[length++] = 1487 + 9;
181 letters[length++] = 1487 + number - 9;
182 } else {
183 if (int tens = number / 10) {
184 static const UChar hebrewTens[9] = { 1497, 1499, 1500, 1502, 1504, 1 505, 1506, 1508, 1510 };
185 letters[length++] = hebrewTens[tens - 1];
186 }
187 if (int ones = number % 10)
188 letters[length++] = 1487 + ones;
189 }
190 ASSERT(length <= 5);
191 return length;
192 }
193
194 static String toHebrew(int number)
195 {
196 // FIXME: CSS3 mentions ways to make this work for much larger numbers.
197 ASSERT(number >= 0 && number <= 999999);
198
199 if (number == 0) {
200 static const UChar hebrewZero[3] = { 0x05D0, 0x05E4, 0x05E1 };
201 return String(hebrewZero, 3);
202 }
203
204 const int lettersSize = 11; // big enough for two 5-digit sequences plus a q uote mark between
205 UChar letters[lettersSize];
206
207 int length;
208 if (number < 1000)
209 length = 0;
210 else {
211 length = toHebrewUnder1000(number / 1000, letters);
212 letters[length++] = '\'';
213 number = number % 1000;
214 }
215 length += toHebrewUnder1000(number, letters + length);
216
217 ASSERT(length <= lettersSize);
218 return String(letters, length);
219 }
220
221 static int toArmenianUnder10000(int number, bool upper, bool addCircumflex, UCha r letters[9])
222 {
223 ASSERT(number >= 0 && number < 10000);
224 int length = 0;
225
226 int lowerOffset = upper ? 0 : 0x0030;
227
228 if (int thousands = number / 1000) {
229 if (thousands == 7) {
230 letters[length++] = 0x0552 + lowerOffset;
231 if (addCircumflex)
232 letters[length++] = 0x0302;
233 } else {
234 letters[length++] = (0x054C - 1 + lowerOffset) + thousands;
235 if (addCircumflex)
236 letters[length++] = 0x0302;
237 }
238 }
239
240 if (int hundreds = (number / 100) % 10) {
241 letters[length++] = (0x0543 - 1 + lowerOffset) + hundreds;
242 if (addCircumflex)
243 letters[length++] = 0x0302;
244 }
245
246 if (int tens = (number / 10) % 10) {
247 letters[length++] = (0x053A - 1 + lowerOffset) + tens;
248 if (addCircumflex)
249 letters[length++] = 0x0302;
250 }
251
252 if (int ones = number % 10) {
253 letters[length++] = (0x531 - 1 + lowerOffset) + ones;
254 if (addCircumflex)
255 letters[length++] = 0x0302;
256 }
257
258 return length;
259 }
260
261 static String toArmenian(int number, bool upper)
262 {
263 ASSERT(number >= 1 && number <= 99999999);
264
265 const int lettersSize = 18; // twice what toArmenianUnder10000 needs
266 UChar letters[lettersSize];
267
268 int length = toArmenianUnder10000(number / 10000, upper, true, letters);
269 length += toArmenianUnder10000(number % 10000, upper, false, letters + lengt h);
270
271 ASSERT(length <= lettersSize);
272 return String(letters, length);
273 }
274
275 static String toGeorgian(int number)
276 {
277 ASSERT(number >= 1 && number <= 19999);
278
279 const int lettersSize = 5;
280 UChar letters[lettersSize];
281
282 int length = 0;
283
284 if (number > 9999)
285 letters[length++] = 0x10F5;
286
287 if (int thousands = (number / 1000) % 10) {
288 static const UChar georgianThousands[9] = {
289 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10F4, 0x10EF, 0x10 F0
290 };
291 letters[length++] = georgianThousands[thousands - 1];
292 }
293
294 if (int hundreds = (number / 100) % 10) {
295 static const UChar georgianHundreds[9] = {
296 0x10E0, 0x10E1, 0x10E2, 0x10F3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10 E8
297 };
298 letters[length++] = georgianHundreds[hundreds - 1];
299 }
300
301 if (int tens = (number / 10) % 10) {
302 static const UChar georgianTens[9] = {
303 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10F2, 0x10DD, 0x10DE, 0x10 DF
304 };
305 letters[length++] = georgianTens[tens - 1];
306 }
307
308 if (int ones = number % 10) {
309 static const UChar georgianOnes[9] = {
310 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10F1, 0x10 D7
311 };
312 letters[length++] = georgianOnes[ones - 1];
313 }
314
315 ASSERT(length <= lettersSize);
316 return String(letters, length);
317 }
318
319 // The table uses the order from the CSS3 specification:
320 // first 3 group markers, then 3 digit markers, then ten digits.
321 static String toCJKIdeographic(int number, const UChar table[16])
322 {
323 ASSERT(number >= 0);
324
325 enum AbstractCJKChar {
326 noChar,
327 secondGroupMarker, thirdGroupMarker, fourthGroupMarker,
328 secondDigitMarker, thirdDigitMarker, fourthDigitMarker,
329 digit0, digit1, digit2, digit3, digit4,
330 digit5, digit6, digit7, digit8, digit9
331 };
332
333 if (number == 0)
334 return String(&table[digit0 - 1], 1);
335
336 const int groupLength = 8; // 4 digits, 3 digit markers, and a group marker
337 const int bufferLength = 4 * groupLength;
338 AbstractCJKChar buffer[bufferLength] = { noChar };
339
340 for (int i = 0; i < 4; ++i) {
341 int groupValue = number % 10000;
342 number /= 10000;
343
344 // Process least-significant group first, but put it in the buffer last.
345 AbstractCJKChar* group = &buffer[(3 - i) * groupLength];
346
347 if (groupValue && i)
348 group[7] = static_cast<AbstractCJKChar>(secondGroupMarker - 1 + i);
349
350 // Put in the four digits and digit markers for any non-zero digits.
351 group[6] = static_cast<AbstractCJKChar>(digit0 + (groupValue % 10));
352 if (number != 0 || groupValue > 9) {
353 int digitValue = ((groupValue / 10) % 10);
354 group[4] = static_cast<AbstractCJKChar>(digit0 + digitValue);
355 if (digitValue)
356 group[5] = secondDigitMarker;
357 }
358 if (number != 0 || groupValue > 99) {
359 int digitValue = ((groupValue / 100) % 10);
360 group[2] = static_cast<AbstractCJKChar>(digit0 + digitValue);
361 if (digitValue)
362 group[3] = thirdDigitMarker;
363 }
364 if (number != 0 || groupValue > 999) {
365 int digitValue = groupValue / 1000;
366 group[0] = static_cast<AbstractCJKChar>(digit0 + digitValue);
367 if (digitValue)
368 group[1] = fourthDigitMarker;
369 }
370
371 // Remove the tens digit, but leave the marker, for any group that has
372 // a value of less than 20.
373 if (groupValue < 20) {
374 ASSERT(group[4] == noChar || group[4] == digit0 || group[4] == digit 1);
375 group[4] = noChar;
376 }
377
378 if (number == 0)
379 break;
380 }
381
382 // Convert into characters, omitting consecutive runs of digit0 and
383 // any trailing digit0.
384 int length = 0;
385 UChar characters[bufferLength];
386 AbstractCJKChar last = noChar;
387 for (int i = 0; i < bufferLength; ++i) {
388 AbstractCJKChar a = buffer[i];
389 if (a != noChar) {
390 if (a != digit0 || last != digit0)
391 characters[length++] = table[a - 1];
392 last = a;
393 }
394 }
395 if (last == digit0)
396 --length;
397
398 return String(characters, length);
399 }
400
401 static EListStyleType effectiveListMarkerType(EListStyleType type, int value)
402 {
403 // Note, the following switch statement has been explicitly grouped
404 // by list-style-type ordinal range.
405 switch (type) {
406 case ArabicIndic:
407 case Bengali:
408 case BinaryListStyle:
409 case Cambodian:
410 case Circle:
411 case DecimalLeadingZero:
412 case DecimalListStyle:
413 case Devanagari:
414 case Disc:
415 case Gujarati:
416 case Gurmukhi:
417 case Kannada:
418 case Khmer:
419 case Lao:
420 case LowerHexadecimal:
421 case Malayalam:
422 case Mongolian:
423 case Myanmar:
424 case NoneListStyle:
425 case Octal:
426 case Oriya:
427 case Persian:
428 case Square:
429 case Telugu:
430 case Thai:
431 case Tibetan:
432 case UpperHexadecimal:
433 case Urdu:
434 return type; // Can represent all ordinals.
435 case Armenian:
436 return (value < 1 || value > 99999999) ? DecimalListStyle : type;
437 case CJKIdeographic:
438 return (value < 0) ? DecimalListStyle : type;
439 case Georgian:
440 return (value < 1 || value > 19999) ? DecimalListStyle : type;
441 case Hebrew:
442 return (value < 0 || value > 999999) ? DecimalListStyle : type;
443 case LowerRoman:
444 case UpperRoman:
445 return (value < 1 || value > 3999) ? DecimalListStyle : type;
446 case Afar:
447 case Amharic:
448 case AmharicAbegede:
449 case Asterisks:
450 case CjkEarthlyBranch:
451 case CjkHeavenlyStem:
452 case Ethiopic:
453 case EthiopicAbegede:
454 case EthiopicAbegedeAmEt:
455 case EthiopicAbegedeGez:
456 case EthiopicAbegedeTiEr:
457 case EthiopicAbegedeTiEt:
458 case EthiopicHalehameAaEr:
459 case EthiopicHalehameAaEt:
460 case EthiopicHalehameAmEt:
461 case EthiopicHalehameGez:
462 case EthiopicHalehameOmEt:
463 case EthiopicHalehameSidEt:
464 case EthiopicHalehameSoEt:
465 case EthiopicHalehameTiEr:
466 case EthiopicHalehameTiEt:
467 case EthiopicHalehameTig:
468 case Footnotes:
469 case Hangul:
470 case HangulConsonant:
471 case Hiragana:
472 case HiraganaIroha:
473 case Katakana:
474 case KatakanaIroha:
475 case LowerAlpha:
476 case LowerArmenian:
477 case LowerGreek:
478 case LowerLatin:
479 case LowerNorwegian:
480 case Oromo:
481 case Sidama:
482 case Somali:
483 case Tigre:
484 case TigrinyaEr:
485 case TigrinyaErAbegede:
486 case TigrinyaEt:
487 case TigrinyaEtAbegede:
488 case UpperAlpha:
489 case UpperArmenian:
490 case UpperGreek:
491 case UpperLatin:
492 case UpperNorwegian:
493 return (value < 1) ? DecimalListStyle : type;
494 }
495
496 ASSERT_NOT_REACHED();
497 return type;
498 }
499
500 UChar RenderListMarker::listMarkerSuffix(EListStyleType type, int value)
501 {
502 // If the list-style-type cannot represent |value| because it's outside its
503 // ordinal range then we fall back to some list style that can represent |va lue|.
504 EListStyleType effectiveType = effectiveListMarkerType(type, value);
505
506 // Note, the following switch statement has been explicitly
507 // grouped by list-style-type suffix.
508 switch (effectiveType) {
509 case Asterisks:
510 case Circle:
511 case Disc:
512 case Footnotes:
513 case NoneListStyle:
514 case Square:
515 return ' ';
516 case Afar:
517 case Amharic:
518 case AmharicAbegede:
519 case Ethiopic:
520 case EthiopicAbegede:
521 case EthiopicAbegedeAmEt:
522 case EthiopicAbegedeGez:
523 case EthiopicAbegedeTiEr:
524 case EthiopicAbegedeTiEt:
525 case EthiopicHalehameAaEr:
526 case EthiopicHalehameAaEt:
527 case EthiopicHalehameAmEt:
528 case EthiopicHalehameGez:
529 case EthiopicHalehameOmEt:
530 case EthiopicHalehameSidEt:
531 case EthiopicHalehameSoEt:
532 case EthiopicHalehameTiEr:
533 case EthiopicHalehameTiEt:
534 case EthiopicHalehameTig:
535 case Oromo:
536 case Sidama:
537 case Somali:
538 case Tigre:
539 case TigrinyaEr:
540 case TigrinyaErAbegede:
541 case TigrinyaEt:
542 case TigrinyaEtAbegede:
543 return ethiopicPrefaceColon;
544 case Armenian:
545 case ArabicIndic:
546 case Bengali:
547 case BinaryListStyle:
548 case Cambodian:
549 case CJKIdeographic:
550 case CjkEarthlyBranch:
551 case CjkHeavenlyStem:
552 case DecimalLeadingZero:
553 case DecimalListStyle:
554 case Devanagari:
555 case Georgian:
556 case Gujarati:
557 case Gurmukhi:
558 case Hangul:
559 case HangulConsonant:
560 case Hebrew:
561 case Hiragana:
562 case HiraganaIroha:
563 case Kannada:
564 case Katakana:
565 case KatakanaIroha:
566 case Khmer:
567 case Lao:
568 case LowerAlpha:
569 case LowerArmenian:
570 case LowerGreek:
571 case LowerHexadecimal:
572 case LowerLatin:
573 case LowerNorwegian:
574 case LowerRoman:
575 case Malayalam:
576 case Mongolian:
577 case Myanmar:
578 case Octal:
579 case Oriya:
580 case Persian:
581 case Telugu:
582 case Thai:
583 case Tibetan:
584 case UpperAlpha:
585 case UpperArmenian:
586 case UpperGreek:
587 case UpperHexadecimal:
588 case UpperLatin:
589 case UpperNorwegian:
590 case UpperRoman:
591 case Urdu:
592 return '.';
593 }
594
595 ASSERT_NOT_REACHED();
596 return '.';
597 }
598
599 String listMarkerText(EListStyleType type, int value)
600 {
601 // If the list-style-type, say hebrew, cannot represent |value| because it's outside
602 // its ordinal range then we fallback to some list style that can represent |value|.
603 switch (effectiveListMarkerType(type, value)) {
604 case NoneListStyle:
605 return "";
606
607 case Asterisks: {
608 static const LChar asterisksSymbols[1] = {
609 0x2A
610 };
611 return toSymbolic(value, asterisksSymbols);
612 }
613 // We use the same characters for text security.
614 // See RenderText::setInternalString.
615 case Circle:
616 return String(&whiteBullet, 1);
617 case Disc:
618 return String(&bullet, 1);
619 case Footnotes: {
620 static const UChar footnotesSymbols[4] = {
621 0x002A, 0x2051, 0x2020, 0x2021
622 };
623 return toSymbolic(value, footnotesSymbols);
624 }
625 case Square:
626 // The CSS 2.1 test suite uses U+25EE BLACK MEDIUM SMALL SQUARE
627 // instead, but I think this looks better.
628 return String(&blackSquare, 1);
629
630 case DecimalListStyle:
631 return String::number(value);
632 case DecimalLeadingZero:
633 if (value < -9 || value > 9)
634 return String::number(value);
635 if (value < 0)
636 return "-0" + String::number(-value); // -01 to -09
637 return "0" + String::number(value); // 00 to 09
638
639 case ArabicIndic: {
640 static const UChar arabicIndicNumerals[10] = {
641 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669
642 };
643 return toNumeric(value, arabicIndicNumerals);
644 }
645 case BinaryListStyle: {
646 static const LChar binaryNumerals[2] = {
647 '0', '1'
648 };
649 return toNumeric(value, binaryNumerals);
650 }
651 case Bengali: {
652 static const UChar bengaliNumerals[10] = {
653 0x09E6, 0x09E7, 0x09E8, 0x09E9, 0x09EA, 0x09EB, 0x09EC, 0x09ED, 0x09EE, 0x09EF
654 };
655 return toNumeric(value, bengaliNumerals);
656 }
657 case Cambodian:
658 case Khmer: {
659 static const UChar khmerNumerals[10] = {
660 0x17E0, 0x17E1, 0x17E2, 0x17E3, 0x17E4, 0x17E5, 0x17E6, 0x17E7, 0x17E8, 0x17E9
661 };
662 return toNumeric(value, khmerNumerals);
663 }
664 case Devanagari: {
665 static const UChar devanagariNumerals[10] = {
666 0x0966, 0x0967, 0x0968, 0x0969, 0x096A, 0x096B, 0x096C, 0x096D, 0x096E, 0x096F
667 };
668 return toNumeric(value, devanagariNumerals);
669 }
670 case Gujarati: {
671 static const UChar gujaratiNumerals[10] = {
672 0x0AE6, 0x0AE7, 0x0AE8, 0x0AE9, 0x0AEA, 0x0AEB, 0x0AEC, 0x0AED, 0x0AEE, 0x0AEF
673 };
674 return toNumeric(value, gujaratiNumerals);
675 }
676 case Gurmukhi: {
677 static const UChar gurmukhiNumerals[10] = {
678 0x0A66, 0x0A67, 0x0A68, 0x0A69, 0x0A6A, 0x0A6B, 0x0A6C, 0x0A6D, 0x0A6E, 0x0A6F
679 };
680 return toNumeric(value, gurmukhiNumerals);
681 }
682 case Kannada: {
683 static const UChar kannadaNumerals[10] = {
684 0x0CE6, 0x0CE7, 0x0CE8, 0x0CE9, 0x0CEA, 0x0CEB, 0x0CEC, 0x0CED, 0x0CEE, 0x0CEF
685 };
686 return toNumeric(value, kannadaNumerals);
687 }
688 case LowerHexadecimal: {
689 static const LChar lowerHexadecimalNumerals[16] = {
690 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
691 };
692 return toNumeric(value, lowerHexadecimalNumerals);
693 }
694 case Lao: {
695 static const UChar laoNumerals[10] = {
696 0x0ED0, 0x0ED1, 0x0ED2, 0x0ED3, 0x0ED4, 0x0ED5, 0x0ED6, 0x0ED7, 0x0ED8, 0x0ED9
697 };
698 return toNumeric(value, laoNumerals);
699 }
700 case Malayalam: {
701 static const UChar malayalamNumerals[10] = {
702 0x0D66, 0x0D67, 0x0D68, 0x0D69, 0x0D6A, 0x0D6B, 0x0D6C, 0x0D6D, 0x0D6E, 0x0D6F
703 };
704 return toNumeric(value, malayalamNumerals);
705 }
706 case Mongolian: {
707 static const UChar mongolianNumerals[10] = {
708 0x1810, 0x1811, 0x1812, 0x1813, 0x1814, 0x1815, 0x1816, 0x1817, 0x1818, 0x1819
709 };
710 return toNumeric(value, mongolianNumerals);
711 }
712 case Myanmar: {
713 static const UChar myanmarNumerals[10] = {
714 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, 0x1048, 0x1049
715 };
716 return toNumeric(value, myanmarNumerals);
717 }
718 case Octal: {
719 static const LChar octalNumerals[8] = {
720 '0', '1', '2', '3', '4', '5', '6', '7'
721 };
722 return toNumeric(value, octalNumerals);
723 }
724 case Oriya: {
725 static const UChar oriyaNumerals[10] = {
726 0x0B66, 0x0B67, 0x0B68, 0x0B69, 0x0B6A, 0x0B6B, 0x0B6C, 0x0B6D, 0x0B6E, 0x0B6F
727 };
728 return toNumeric(value, oriyaNumerals);
729 }
730 case Persian:
731 case Urdu: {
732 static const UChar urduNumerals[10] = {
733 0x06F0, 0x06F1, 0x06F2, 0x06F3, 0x06F4, 0x06F5, 0x06F6, 0x06F7, 0x06F8, 0x06F9
734 };
735 return toNumeric(value, urduNumerals);
736 }
737 case Telugu: {
738 static const UChar teluguNumerals[10] = {
739 0x0C66, 0x0C67, 0x0C68, 0x0C69, 0x0C6A, 0x0C6B, 0x0C6C, 0x0C6D, 0x0C6E, 0x0C6F
740 };
741 return toNumeric(value, teluguNumerals);
742 }
743 case Tibetan: {
744 static const UChar tibetanNumerals[10] = {
745 0x0F20, 0x0F21, 0x0F22, 0x0F23, 0x0F24, 0x0F25, 0x0F26, 0x0F27, 0x0F28, 0x0F29
746 };
747 return toNumeric(value, tibetanNumerals);
748 }
749 case Thai: {
750 static const UChar thaiNumerals[10] = {
751 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, 0x0E58, 0x0E59
752 };
753 return toNumeric(value, thaiNumerals);
754 }
755 case UpperHexadecimal: {
756 static const LChar upperHexadecimalNumerals[16] = {
757 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
758 };
759 return toNumeric(value, upperHexadecimalNumerals);
760 }
761
762 case LowerAlpha:
763 case LowerLatin: {
764 static const LChar lowerLatinAlphabet[26] = {
765 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
766 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
767 };
768 return toAlphabetic(value, lowerLatinAlphabet);
769 }
770 case UpperAlpha:
771 case UpperLatin: {
772 static const LChar upperLatinAlphabet[26] = {
773 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
774 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
775 };
776 return toAlphabetic(value, upperLatinAlphabet);
777 }
778 case LowerGreek: {
779 static const UChar lowerGreekAlphabet[24] = {
780 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
781 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0,
782 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9
783 };
784 return toAlphabetic(value, lowerGreekAlphabet);
785 }
786
787 case Hiragana: {
788 // FIXME: This table comes from the CSS3 draft, and is probably
789 // incorrect, given the comments in that draft.
790 static const UChar hiraganaAlphabet[48] = {
791 0x3042, 0x3044, 0x3046, 0x3048, 0x304A, 0x304B, 0x304D, 0x304F,
792 0x3051, 0x3053, 0x3055, 0x3057, 0x3059, 0x305B, 0x305D, 0x305F,
793 0x3061, 0x3064, 0x3066, 0x3068, 0x306A, 0x306B, 0x306C, 0x306D,
794 0x306E, 0x306F, 0x3072, 0x3075, 0x3078, 0x307B, 0x307E, 0x307F,
795 0x3080, 0x3081, 0x3082, 0x3084, 0x3086, 0x3088, 0x3089, 0x308A,
796 0x308B, 0x308C, 0x308D, 0x308F, 0x3090, 0x3091, 0x3092, 0x3093
797 };
798 return toAlphabetic(value, hiraganaAlphabet);
799 }
800 case HiraganaIroha: {
801 // FIXME: This table comes from the CSS3 draft, and is probably
802 // incorrect, given the comments in that draft.
803 static const UChar hiraganaIrohaAlphabet[47] = {
804 0x3044, 0x308D, 0x306F, 0x306B, 0x307B, 0x3078, 0x3068, 0x3061,
805 0x308A, 0x306C, 0x308B, 0x3092, 0x308F, 0x304B, 0x3088, 0x305F,
806 0x308C, 0x305D, 0x3064, 0x306D, 0x306A, 0x3089, 0x3080, 0x3046,
807 0x3090, 0x306E, 0x304A, 0x304F, 0x3084, 0x307E, 0x3051, 0x3075,
808 0x3053, 0x3048, 0x3066, 0x3042, 0x3055, 0x304D, 0x3086, 0x3081,
809 0x307F, 0x3057, 0x3091, 0x3072, 0x3082, 0x305B, 0x3059
810 };
811 return toAlphabetic(value, hiraganaIrohaAlphabet);
812 }
813 case Katakana: {
814 // FIXME: This table comes from the CSS3 draft, and is probably
815 // incorrect, given the comments in that draft.
816 static const UChar katakanaAlphabet[48] = {
817 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, 0x30AB, 0x30AD, 0x30AF,
818 0x30B1, 0x30B3, 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD, 0x30BF,
819 0x30C1, 0x30C4, 0x30C6, 0x30C8, 0x30CA, 0x30CB, 0x30CC, 0x30CD,
820 0x30CE, 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, 0x30DE, 0x30DF,
821 0x30E0, 0x30E1, 0x30E2, 0x30E4, 0x30E6, 0x30E8, 0x30E9, 0x30EA,
822 0x30EB, 0x30EC, 0x30ED, 0x30EF, 0x30F0, 0x30F1, 0x30F2, 0x30F3
823 };
824 return toAlphabetic(value, katakanaAlphabet);
825 }
826 case KatakanaIroha: {
827 // FIXME: This table comes from the CSS3 draft, and is probably
828 // incorrect, given the comments in that draft.
829 static const UChar katakanaIrohaAlphabet[47] = {
830 0x30A4, 0x30ED, 0x30CF, 0x30CB, 0x30DB, 0x30D8, 0x30C8, 0x30C1,
831 0x30EA, 0x30CC, 0x30EB, 0x30F2, 0x30EF, 0x30AB, 0x30E8, 0x30BF,
832 0x30EC, 0x30BD, 0x30C4, 0x30CD, 0x30CA, 0x30E9, 0x30E0, 0x30A6,
833 0x30F0, 0x30CE, 0x30AA, 0x30AF, 0x30E4, 0x30DE, 0x30B1, 0x30D5,
834 0x30B3, 0x30A8, 0x30C6, 0x30A2, 0x30B5, 0x30AD, 0x30E6, 0x30E1,
835 0x30DF, 0x30B7, 0x30F1, 0x30D2, 0x30E2, 0x30BB, 0x30B9
836 };
837 return toAlphabetic(value, katakanaIrohaAlphabet);
838 }
839
840 case Afar:
841 case EthiopicHalehameAaEt:
842 case EthiopicHalehameAaEr: {
843 static const UChar ethiopicHalehameAaErAlphabet[18] = {
844 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1260, 0x1270, 0x1290,
845 0x12A0, 0x12A8, 0x12C8, 0x12D0, 0x12E8, 0x12F0, 0x1308, 0x1338, 0x1348
846 };
847 return toAlphabetic(value, ethiopicHalehameAaErAlphabet);
848 }
849 case Amharic:
850 case EthiopicHalehameAmEt: {
851 static const UChar ethiopicHalehameAmEtAlphabet[33] = {
852 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 0x1230, 0x1238, 0x1240,
853 0x1260, 0x1270, 0x1278, 0x1280, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12B8,
854 0x12C8, 0x12D0, 0x12D8, 0x12E0, 0x12E8, 0x12F0, 0x1300, 0x1308, 0x1320,
855 0x1328, 0x1330, 0x1338, 0x1340, 0x1348, 0x1350
856 };
857 return toAlphabetic(value, ethiopicHalehameAmEtAlphabet);
858 }
859 case AmharicAbegede:
860 case EthiopicAbegedeAmEt: {
861 static const UChar ethiopicAbegedeAmEtAlphabet[33] = {
862 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1300, 0x1200, 0x12C8, 0x12D8, 0x12E0,
863 0x1210, 0x1320, 0x1328, 0x12E8, 0x12A8, 0x12B8, 0x1208, 0x1218, 0x1290,
864 0x1298, 0x1220, 0x12D0, 0x1348, 0x1338, 0x1240, 0x1228, 0x1230, 0x1238,
865 0x1270, 0x1278, 0x1280, 0x1340, 0x1330, 0x1350
866 };
867 return toAlphabetic(value, ethiopicAbegedeAmEtAlphabet);
868 }
869 case CjkEarthlyBranch: {
870 static const UChar cjkEarthlyBranchAlphabet[12] = {
871 0x5B50, 0x4E11, 0x5BC5, 0x536F, 0x8FB0, 0x5DF3, 0x5348, 0x672A, 0x7533,
872 0x9149, 0x620C, 0x4EA5
873 };
874 return toAlphabetic(value, cjkEarthlyBranchAlphabet);
875 }
876 case CjkHeavenlyStem: {
877 static const UChar cjkHeavenlyStemAlphabet[10] = {
878 0x7532, 0x4E59, 0x4E19, 0x4E01, 0x620A, 0x5DF1, 0x5E9A, 0x8F9B, 0x58EC,
879 0x7678
880 };
881 return toAlphabetic(value, cjkHeavenlyStemAlphabet);
882 }
883 case Ethiopic:
884 case EthiopicHalehameGez: {
885 static const UChar ethiopicHalehameGezAlphabet[26] = {
886 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 0x1230, 0x1240, 0x1260,
887 0x1270, 0x1280, 0x1290, 0x12A0, 0x12A8, 0x12C8, 0x12D0, 0x12D8, 0x12E8,
888 0x12F0, 0x1308, 0x1320, 0x1330, 0x1338, 0x1340, 0x1348, 0x1350
889 };
890 return toAlphabetic(value, ethiopicHalehameGezAlphabet);
891 }
892 case EthiopicAbegede:
893 case EthiopicAbegedeGez: {
894 static const UChar ethiopicAbegedeGezAlphabet[26] = {
895 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1200, 0x12C8, 0x12D8, 0x1210, 0x1320,
896 0x12E8, 0x12A8, 0x1208, 0x1218, 0x1290, 0x1220, 0x12D0, 0x1348, 0x1338,
897 0x1240, 0x1228, 0x1230, 0x1270, 0x1280, 0x1340, 0x1330, 0x1350
898 };
899 return toAlphabetic(value, ethiopicAbegedeGezAlphabet);
900 }
901 case HangulConsonant: {
902 static const UChar hangulConsonantAlphabet[14] = {
903 0x3131, 0x3134, 0x3137, 0x3139, 0x3141, 0x3142, 0x3145, 0x3147, 0x3148,
904 0x314A, 0x314B, 0x314C, 0x314D, 0x314E
905 };
906 return toAlphabetic(value, hangulConsonantAlphabet);
907 }
908 case Hangul: {
909 static const UChar hangulAlphabet[14] = {
910 0xAC00, 0xB098, 0xB2E4, 0xB77C, 0xB9C8, 0xBC14, 0xC0AC, 0xC544, 0xC790,
911 0xCC28, 0xCE74, 0xD0C0, 0xD30C, 0xD558
912 };
913 return toAlphabetic(value, hangulAlphabet);
914 }
915 case Oromo:
916 case EthiopicHalehameOmEt: {
917 static const UChar ethiopicHalehameOmEtAlphabet[25] = {
918 0x1200, 0x1208, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260, 0x1270,
919 0x1278, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12C8, 0x12E8, 0x12F0, 0x12F8,
920 0x1300, 0x1308, 0x1320, 0x1328, 0x1338, 0x1330, 0x1348
921 };
922 return toAlphabetic(value, ethiopicHalehameOmEtAlphabet);
923 }
924 case Sidama:
925 case EthiopicHalehameSidEt: {
926 static const UChar ethiopicHalehameSidEtAlphabet[26] = {
927 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260,
928 0x1270, 0x1278, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12C8, 0x12E8, 0x12F0,
929 0x12F8, 0x1300, 0x1308, 0x1320, 0x1328, 0x1338, 0x1330, 0x1348
930 };
931 return toAlphabetic(value, ethiopicHalehameSidEtAlphabet);
932 }
933 case Somali:
934 case EthiopicHalehameSoEt: {
935 static const UChar ethiopicHalehameSoEtAlphabet[22] = {
936 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260,
937 0x1270, 0x1290, 0x12A0, 0x12A8, 0x12B8, 0x12C8, 0x12D0, 0x12E8, 0x12F0,
938 0x1300, 0x1308, 0x1338, 0x1348
939 };
940 return toAlphabetic(value, ethiopicHalehameSoEtAlphabet);
941 }
942 case Tigre:
943 case EthiopicHalehameTig: {
944 static const UChar ethiopicHalehameTigAlphabet[27] = {
945 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1260,
946 0x1270, 0x1278, 0x1290, 0x12A0, 0x12A8, 0x12C8, 0x12D0, 0x12D8, 0x12E8,
947 0x12F0, 0x1300, 0x1308, 0x1320, 0x1328, 0x1338, 0x1330, 0x1348, 0x1350
948 };
949 return toAlphabetic(value, ethiopicHalehameTigAlphabet);
950 }
951 case TigrinyaEr:
952 case EthiopicHalehameTiEr: {
953 static const UChar ethiopicHalehameTiErAlphabet[31] = {
954 0x1200, 0x1208, 0x1210, 0x1218, 0x1228, 0x1230, 0x1238, 0x1240, 0x1250,
955 0x1260, 0x1270, 0x1278, 0x1290, 0x1298, 0x12A0, 0x12A8, 0x12B8, 0x12C8,
956 0x12D0, 0x12D8, 0x12E0, 0x12E8, 0x12F0, 0x1300, 0x1308, 0x1320, 0x1328,
957 0x1330, 0x1338, 0x1348, 0x1350
958 };
959 return toAlphabetic(value, ethiopicHalehameTiErAlphabet);
960 }
961 case TigrinyaErAbegede:
962 case EthiopicAbegedeTiEr: {
963 static const UChar ethiopicAbegedeTiErAlphabet[31] = {
964 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1300, 0x1200, 0x12C8, 0x12D8, 0x12E0,
965 0x1210, 0x1320, 0x1328, 0x12E8, 0x12A8, 0x12B8, 0x1208, 0x1218, 0x1290,
966 0x1298, 0x12D0, 0x1348, 0x1338, 0x1240, 0x1250, 0x1228, 0x1230, 0x1238,
967 0x1270, 0x1278, 0x1330, 0x1350
968 };
969 return toAlphabetic(value, ethiopicAbegedeTiErAlphabet);
970 }
971 case TigrinyaEt:
972 case EthiopicHalehameTiEt: {
973 static const UChar ethiopicHalehameTiEtAlphabet[34] = {
974 0x1200, 0x1208, 0x1210, 0x1218, 0x1220, 0x1228, 0x1230, 0x1238, 0x1240,
975 0x1250, 0x1260, 0x1270, 0x1278, 0x1280, 0x1290, 0x1298, 0x12A0, 0x12A8,
976 0x12B8, 0x12C8, 0x12D0, 0x12D8, 0x12E0, 0x12E8, 0x12F0, 0x1300, 0x1308,
977 0x1320, 0x1328, 0x1330, 0x1338, 0x1340, 0x1348, 0x1350
978 };
979 return toAlphabetic(value, ethiopicHalehameTiEtAlphabet);
980 }
981 case TigrinyaEtAbegede:
982 case EthiopicAbegedeTiEt: {
983 static const UChar ethiopicAbegedeTiEtAlphabet[34] = {
984 0x12A0, 0x1260, 0x1308, 0x12F0, 0x1300, 0x1200, 0x12C8, 0x12D8, 0x12E0,
985 0x1210, 0x1320, 0x1328, 0x12E8, 0x12A8, 0x12B8, 0x1208, 0x1218, 0x1290,
986 0x1298, 0x1220, 0x12D0, 0x1348, 0x1338, 0x1240, 0x1250, 0x1228, 0x1230,
987 0x1238, 0x1270, 0x1278, 0x1280, 0x1340, 0x1330, 0x1350
988 };
989 return toAlphabetic(value, ethiopicAbegedeTiEtAlphabet);
990 }
991 case UpperGreek: {
992 static const UChar upperGreekAlphabet[24] = {
993 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399,
994 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03A1, 0x03A3,
995 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9
996 };
997 return toAlphabetic(value, upperGreekAlphabet);
998 }
999 case LowerNorwegian: {
1000 static const LChar lowerNorwegianAlphabet[29] = {
1001 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
1002 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72,
1003 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xE6,
1004 0xF8, 0xE5
1005 };
1006 return toAlphabetic(value, lowerNorwegianAlphabet);
1007 }
1008 case UpperNorwegian: {
1009 static const LChar upperNorwegianAlphabet[29] = {
1010 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
1011 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52,
1012 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0xC6,
1013 0xD8, 0xC5
1014 };
1015 return toAlphabetic(value, upperNorwegianAlphabet);
1016 }
1017 case CJKIdeographic: {
1018 static const UChar traditionalChineseInformalTable[16] = {
1019 0x842C, 0x5104, 0x5146,
1020 0x5341, 0x767E, 0x5343,
1021 0x96F6, 0x4E00, 0x4E8C, 0x4E09, 0x56DB,
1022 0x4E94, 0x516D, 0x4E03, 0x516B, 0x4E5D
1023 };
1024 return toCJKIdeographic(value, traditionalChineseInformalTable);
1025 }
1026
1027 case LowerRoman:
1028 return toRoman(value, false);
1029 case UpperRoman:
1030 return toRoman(value, true);
1031
1032 case Armenian:
1033 case UpperArmenian:
1034 // CSS3 says "armenian" means "lower-armenian".
1035 // But the CSS2.1 test suite contains uppercase test results for "ar menian",
1036 // so we'll match the test suite.
1037 return toArmenian(value, true);
1038 case LowerArmenian:
1039 return toArmenian(value, false);
1040 case Georgian:
1041 return toGeorgian(value);
1042 case Hebrew:
1043 return toHebrew(value);
1044 }
1045
1046 ASSERT_NOT_REACHED();
1047 return "";
1048 }
1049
1050 RenderListMarker::RenderListMarker(RenderListItem* item)
1051 : RenderBox(0)
1052 , m_listItem(item)
1053 {
1054 // init LayoutObject attributes
1055 setInline(true); // our object is Inline
1056 setReplaced(true); // pretend to be replaced
1057 }
1058
1059 RenderListMarker::~RenderListMarker()
1060 {
1061 }
1062
1063 void RenderListMarker::destroy()
1064 {
1065 if (m_image)
1066 m_image->removeClient(this);
1067 RenderBox::destroy();
1068 }
1069
1070 RenderListMarker* RenderListMarker::createAnonymous(RenderListItem* item)
1071 {
1072 Document& document = item->document();
1073 RenderListMarker* renderer = new RenderListMarker(item);
1074 renderer->setDocumentForAnonymous(&document);
1075 return renderer;
1076 }
1077
1078 void RenderListMarker::styleWillChange(StyleDifference diff, const LayoutStyle& newStyle)
1079 {
1080 if (style() && (newStyle.listStylePosition() != style()->listStylePosition() || newStyle.listStyleType() != style()->listStyleType()))
1081 setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
1082
1083 RenderBox::styleWillChange(diff, newStyle);
1084 }
1085
1086 void RenderListMarker::styleDidChange(StyleDifference diff, const LayoutStyle* o ldStyle)
1087 {
1088 RenderBox::styleDidChange(diff, oldStyle);
1089
1090 if (m_image != style()->listStyleImage()) {
1091 if (m_image)
1092 m_image->removeClient(this);
1093 m_image = style()->listStyleImage();
1094 if (m_image)
1095 m_image->addClient(this);
1096 }
1097 }
1098
1099 InlineBox* RenderListMarker::createInlineBox()
1100 {
1101 InlineBox* result = RenderBox::createInlineBox();
1102 result->setIsText(isText());
1103 return result;
1104 }
1105
1106 bool RenderListMarker::isImage() const
1107 {
1108 return m_image && !m_image->errorOccurred();
1109 }
1110
1111 LayoutRect RenderListMarker::localSelectionRect()
1112 {
1113 InlineBox* box = inlineBoxWrapper();
1114 if (!box)
1115 return LayoutRect(LayoutPoint(), size());
1116 RootInlineBox& root = inlineBoxWrapper()->root();
1117 LayoutUnit newLogicalTop = root.block().style()->isFlippedBlocksWritingMode( ) ? inlineBoxWrapper()->logicalBottom() - root.selectionBottom() : root.selectio nTop() - inlineBoxWrapper()->logicalTop();
1118 if (root.block().style()->isHorizontalWritingMode())
1119 return LayoutRect(0, newLogicalTop, size().width(), root.selectionHeight ());
1120 return LayoutRect(newLogicalTop, 0, root.selectionHeight(), size().height()) ;
1121 }
1122
1123 void RenderListMarker::paint(const PaintInfo& paintInfo, const LayoutPoint& pain tOffset)
1124 {
1125 ListMarkerPainter(*this).paint(paintInfo, paintOffset);
1126 }
1127
1128 void RenderListMarker::layout()
1129 {
1130 ASSERT(needsLayout());
1131
1132 if (isImage()) {
1133 updateMarginsAndContent();
1134 setWidth(m_image->imageSize(this, style()->effectiveZoom()).width());
1135 setHeight(m_image->imageSize(this, style()->effectiveZoom()).height());
1136 } else {
1137 setLogicalWidth(minPreferredLogicalWidth());
1138 setLogicalHeight(style()->fontMetrics().height());
1139 }
1140
1141 setMarginStart(0);
1142 setMarginEnd(0);
1143
1144 Length startMargin = style()->marginStart();
1145 Length endMargin = style()->marginEnd();
1146 if (startMargin.isFixed())
1147 setMarginStart(startMargin.value());
1148 if (endMargin.isFixed())
1149 setMarginEnd(endMargin.value());
1150
1151 clearNeedsLayout();
1152 }
1153
1154 void RenderListMarker::imageChanged(WrappedImagePtr o, const IntRect*)
1155 {
1156 // A list marker can't have a background or border image, so no need to call the base class method.
1157 if (o != m_image->data())
1158 return;
1159
1160 if (size() != m_image->imageSize(this, style()->effectiveZoom()) || m_image- >errorOccurred())
1161 setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
1162 else
1163 setShouldDoFullPaintInvalidation();
1164 }
1165
1166 void RenderListMarker::updateMarginsAndContent()
1167 {
1168 updateContent();
1169 updateMargins();
1170 }
1171
1172 void RenderListMarker::updateContent()
1173 {
1174 // FIXME: This if-statement is just a performance optimization, but it's mes sy to use the preferredLogicalWidths dirty bit for this.
1175 // It's unclear if this is a premature optimization.
1176 if (!preferredLogicalWidthsDirty())
1177 return;
1178
1179 m_text = "";
1180
1181 if (isImage()) {
1182 // FIXME: This is a somewhat arbitrary width. Generated images for mark ers really won't become particularly useful
1183 // until we support the CSS3 marker pseudoclass to allow control over th e width and height of the marker box.
1184 int bulletWidth = style()->fontMetrics().ascent() / 2;
1185 IntSize defaultBulletSize(bulletWidth, bulletWidth);
1186 IntSize imageSize = calculateImageIntrinsicDimensions(m_image.get(), def aultBulletSize, DoNotScaleByEffectiveZoom);
1187 m_image->setContainerSizeForRenderer(this, imageSize, style()->effective Zoom());
1188 return;
1189 }
1190
1191 EListStyleType type = style()->listStyleType();
1192 switch (type) {
1193 case NoneListStyle:
1194 break;
1195 case Circle:
1196 case Disc:
1197 case Square:
1198 m_text = listMarkerText(type, 0); // value is ignored for these types
1199 break;
1200 case Asterisks:
1201 case Footnotes:
1202 case Afar:
1203 case Amharic:
1204 case AmharicAbegede:
1205 case ArabicIndic:
1206 case Armenian:
1207 case BinaryListStyle:
1208 case Bengali:
1209 case Cambodian:
1210 case CJKIdeographic:
1211 case CjkEarthlyBranch:
1212 case CjkHeavenlyStem:
1213 case DecimalLeadingZero:
1214 case DecimalListStyle:
1215 case Devanagari:
1216 case Ethiopic:
1217 case EthiopicAbegede:
1218 case EthiopicAbegedeAmEt:
1219 case EthiopicAbegedeGez:
1220 case EthiopicAbegedeTiEr:
1221 case EthiopicAbegedeTiEt:
1222 case EthiopicHalehameAaEr:
1223 case EthiopicHalehameAaEt:
1224 case EthiopicHalehameAmEt:
1225 case EthiopicHalehameGez:
1226 case EthiopicHalehameOmEt:
1227 case EthiopicHalehameSidEt:
1228 case EthiopicHalehameSoEt:
1229 case EthiopicHalehameTiEr:
1230 case EthiopicHalehameTiEt:
1231 case EthiopicHalehameTig:
1232 case Georgian:
1233 case Gujarati:
1234 case Gurmukhi:
1235 case Hangul:
1236 case HangulConsonant:
1237 case Hebrew:
1238 case Hiragana:
1239 case HiraganaIroha:
1240 case Kannada:
1241 case Katakana:
1242 case KatakanaIroha:
1243 case Khmer:
1244 case Lao:
1245 case LowerAlpha:
1246 case LowerArmenian:
1247 case LowerGreek:
1248 case LowerHexadecimal:
1249 case LowerLatin:
1250 case LowerNorwegian:
1251 case LowerRoman:
1252 case Malayalam:
1253 case Mongolian:
1254 case Myanmar:
1255 case Octal:
1256 case Oriya:
1257 case Oromo:
1258 case Persian:
1259 case Sidama:
1260 case Somali:
1261 case Telugu:
1262 case Thai:
1263 case Tibetan:
1264 case Tigre:
1265 case TigrinyaEr:
1266 case TigrinyaErAbegede:
1267 case TigrinyaEt:
1268 case TigrinyaEtAbegede:
1269 case UpperAlpha:
1270 case UpperArmenian:
1271 case UpperGreek:
1272 case UpperHexadecimal:
1273 case UpperLatin:
1274 case UpperNorwegian:
1275 case UpperRoman:
1276 case Urdu:
1277 m_text = listMarkerText(type, m_listItem->value());
1278 break;
1279 }
1280 }
1281
1282 void RenderListMarker::computePreferredLogicalWidths()
1283 {
1284 ASSERT(preferredLogicalWidthsDirty());
1285 updateContent();
1286
1287 if (isImage()) {
1288 LayoutSize imageSize = m_image->imageSize(this, style()->effectiveZoom() );
1289 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = style()->isHor izontalWritingMode() ? imageSize.width() : imageSize.height();
1290 clearPreferredLogicalWidthsDirty();
1291 updateMargins();
1292 return;
1293 }
1294
1295 const Font& font = style()->font();
1296
1297 LayoutUnit logicalWidth = 0;
1298 EListStyleType type = style()->listStyleType();
1299 switch (type) {
1300 case NoneListStyle:
1301 break;
1302 case Asterisks:
1303 case Footnotes:
1304 logicalWidth = font.width(m_text); // no suffix for these types
1305 break;
1306 case Circle:
1307 case Disc:
1308 case Square:
1309 logicalWidth = (font.fontMetrics().ascent() * 2 / 3 + 1) / 2 + 2;
1310 break;
1311 case Afar:
1312 case Amharic:
1313 case AmharicAbegede:
1314 case ArabicIndic:
1315 case Armenian:
1316 case BinaryListStyle:
1317 case Bengali:
1318 case Cambodian:
1319 case CJKIdeographic:
1320 case CjkEarthlyBranch:
1321 case CjkHeavenlyStem:
1322 case DecimalLeadingZero:
1323 case DecimalListStyle:
1324 case Devanagari:
1325 case Ethiopic:
1326 case EthiopicAbegede:
1327 case EthiopicAbegedeAmEt:
1328 case EthiopicAbegedeGez:
1329 case EthiopicAbegedeTiEr:
1330 case EthiopicAbegedeTiEt:
1331 case EthiopicHalehameAaEr:
1332 case EthiopicHalehameAaEt:
1333 case EthiopicHalehameAmEt:
1334 case EthiopicHalehameGez:
1335 case EthiopicHalehameOmEt:
1336 case EthiopicHalehameSidEt:
1337 case EthiopicHalehameSoEt:
1338 case EthiopicHalehameTiEr:
1339 case EthiopicHalehameTiEt:
1340 case EthiopicHalehameTig:
1341 case Georgian:
1342 case Gujarati:
1343 case Gurmukhi:
1344 case Hangul:
1345 case HangulConsonant:
1346 case Hebrew:
1347 case Hiragana:
1348 case HiraganaIroha:
1349 case Kannada:
1350 case Katakana:
1351 case KatakanaIroha:
1352 case Khmer:
1353 case Lao:
1354 case LowerAlpha:
1355 case LowerArmenian:
1356 case LowerGreek:
1357 case LowerHexadecimal:
1358 case LowerLatin:
1359 case LowerNorwegian:
1360 case LowerRoman:
1361 case Malayalam:
1362 case Mongolian:
1363 case Myanmar:
1364 case Octal:
1365 case Oriya:
1366 case Oromo:
1367 case Persian:
1368 case Sidama:
1369 case Somali:
1370 case Telugu:
1371 case Thai:
1372 case Tibetan:
1373 case Tigre:
1374 case TigrinyaEr:
1375 case TigrinyaErAbegede:
1376 case TigrinyaEt:
1377 case TigrinyaEtAbegede:
1378 case UpperAlpha:
1379 case UpperArmenian:
1380 case UpperGreek:
1381 case UpperHexadecimal:
1382 case UpperLatin:
1383 case UpperNorwegian:
1384 case UpperRoman:
1385 case Urdu:
1386 if (m_text.isEmpty())
1387 logicalWidth = 0;
1388 else {
1389 LayoutUnit itemWidth = font.width(m_text);
1390 UChar suffixSpace[2] = { listMarkerSuffix(type, m_listItem->valu e()), ' ' };
1391 LayoutUnit suffixSpaceWidth = font.width(constructTextRun(this, font, suffixSpace, 2, styleRef(), style()->direction()));
1392 logicalWidth = itemWidth + suffixSpaceWidth;
1393 }
1394 break;
1395 }
1396
1397 m_minPreferredLogicalWidth = logicalWidth;
1398 m_maxPreferredLogicalWidth = logicalWidth;
1399
1400 clearPreferredLogicalWidthsDirty();
1401
1402 updateMargins();
1403 }
1404
1405 void RenderListMarker::updateMargins()
1406 {
1407 const FontMetrics& fontMetrics = style()->fontMetrics();
1408
1409 LayoutUnit marginStart = 0;
1410 LayoutUnit marginEnd = 0;
1411
1412 if (isInside()) {
1413 if (isImage())
1414 marginEnd = cMarkerPadding;
1415 else switch (style()->listStyleType()) {
1416 case Disc:
1417 case Circle:
1418 case Square:
1419 marginStart = -1;
1420 marginEnd = fontMetrics.ascent() - minPreferredLogicalWidth() + 1;
1421 break;
1422 default:
1423 break;
1424 }
1425 } else {
1426 if (style()->isLeftToRightDirection()) {
1427 if (isImage())
1428 marginStart = -minPreferredLogicalWidth() - cMarkerPadding;
1429 else {
1430 int offset = fontMetrics.ascent() * 2 / 3;
1431 switch (style()->listStyleType()) {
1432 case Disc:
1433 case Circle:
1434 case Square:
1435 marginStart = -offset - cMarkerPadding - 1;
1436 break;
1437 case NoneListStyle:
1438 break;
1439 default:
1440 marginStart = m_text.isEmpty() ? LayoutUnit() : -minPref erredLogicalWidth() - offset / 2;
1441 }
1442 }
1443 marginEnd = -marginStart - minPreferredLogicalWidth();
1444 } else {
1445 if (isImage())
1446 marginEnd = cMarkerPadding;
1447 else {
1448 int offset = fontMetrics.ascent() * 2 / 3;
1449 switch (style()->listStyleType()) {
1450 case Disc:
1451 case Circle:
1452 case Square:
1453 marginEnd = offset + cMarkerPadding + 1 - minPreferredLo gicalWidth();
1454 break;
1455 case NoneListStyle:
1456 break;
1457 default:
1458 marginEnd = m_text.isEmpty() ? 0 : offset / 2;
1459 }
1460 }
1461 marginStart = -marginEnd - minPreferredLogicalWidth();
1462 }
1463
1464 }
1465
1466 style()->setMarginStart(Length(marginStart, Fixed));
1467 style()->setMarginEnd(Length(marginEnd, Fixed));
1468 }
1469
1470 LayoutUnit RenderListMarker::lineHeight(bool firstLine, LineDirectionMode direct ion, LinePositionMode linePositionMode) const
1471 {
1472 if (!isImage())
1473 return m_listItem->lineHeight(firstLine, direction, PositionOfInteriorLi neBoxes);
1474 return RenderBox::lineHeight(firstLine, direction, linePositionMode);
1475 }
1476
1477 int RenderListMarker::baselinePosition(FontBaseline baselineType, bool firstLine , LineDirectionMode direction, LinePositionMode linePositionMode) const
1478 {
1479 ASSERT(linePositionMode == PositionOnContainingLine);
1480 if (!isImage())
1481 return m_listItem->baselinePosition(baselineType, firstLine, direction, PositionOfInteriorLineBoxes);
1482 return RenderBox::baselinePosition(baselineType, firstLine, direction, lineP ositionMode);
1483 }
1484
1485 bool RenderListMarker::isInside() const
1486 {
1487 return m_listItem->notInList() || style()->listStylePosition() == INSIDE;
1488 }
1489
1490 IntRect RenderListMarker::getRelativeMarkerRect()
1491 {
1492 if (isImage())
1493 return IntRect(0, 0, m_image->imageSize(this, style()->effectiveZoom()). width(), m_image->imageSize(this, style()->effectiveZoom()).height());
1494
1495 IntRect relativeRect;
1496 EListStyleType type = style()->listStyleType();
1497 switch (type) {
1498 case Asterisks:
1499 case Footnotes: {
1500 const Font& font = style()->font();
1501 relativeRect = IntRect(0, 0, font.width(m_text), font.fontMetrics(). height());
1502 break;
1503 }
1504 case Disc:
1505 case Circle:
1506 case Square: {
1507 // FIXME: Are these particular rounding rules necessary?
1508 const FontMetrics& fontMetrics = style()->fontMetrics();
1509 int ascent = fontMetrics.ascent();
1510 int bulletWidth = (ascent * 2 / 3 + 1) / 2;
1511 relativeRect = IntRect(1, 3 * (ascent - ascent * 2 / 3) / 2, bulletW idth, bulletWidth);
1512 break;
1513 }
1514 case NoneListStyle:
1515 return IntRect();
1516 case Afar:
1517 case Amharic:
1518 case AmharicAbegede:
1519 case ArabicIndic:
1520 case Armenian:
1521 case BinaryListStyle:
1522 case Bengali:
1523 case Cambodian:
1524 case CJKIdeographic:
1525 case CjkEarthlyBranch:
1526 case CjkHeavenlyStem:
1527 case DecimalLeadingZero:
1528 case DecimalListStyle:
1529 case Devanagari:
1530 case Ethiopic:
1531 case EthiopicAbegede:
1532 case EthiopicAbegedeAmEt:
1533 case EthiopicAbegedeGez:
1534 case EthiopicAbegedeTiEr:
1535 case EthiopicAbegedeTiEt:
1536 case EthiopicHalehameAaEr:
1537 case EthiopicHalehameAaEt:
1538 case EthiopicHalehameAmEt:
1539 case EthiopicHalehameGez:
1540 case EthiopicHalehameOmEt:
1541 case EthiopicHalehameSidEt:
1542 case EthiopicHalehameSoEt:
1543 case EthiopicHalehameTiEr:
1544 case EthiopicHalehameTiEt:
1545 case EthiopicHalehameTig:
1546 case Georgian:
1547 case Gujarati:
1548 case Gurmukhi:
1549 case Hangul:
1550 case HangulConsonant:
1551 case Hebrew:
1552 case Hiragana:
1553 case HiraganaIroha:
1554 case Kannada:
1555 case Katakana:
1556 case KatakanaIroha:
1557 case Khmer:
1558 case Lao:
1559 case LowerAlpha:
1560 case LowerArmenian:
1561 case LowerGreek:
1562 case LowerHexadecimal:
1563 case LowerLatin:
1564 case LowerNorwegian:
1565 case LowerRoman:
1566 case Malayalam:
1567 case Mongolian:
1568 case Myanmar:
1569 case Octal:
1570 case Oriya:
1571 case Oromo:
1572 case Persian:
1573 case Sidama:
1574 case Somali:
1575 case Telugu:
1576 case Thai:
1577 case Tibetan:
1578 case Tigre:
1579 case TigrinyaEr:
1580 case TigrinyaErAbegede:
1581 case TigrinyaEt:
1582 case TigrinyaEtAbegede:
1583 case UpperAlpha:
1584 case UpperArmenian:
1585 case UpperGreek:
1586 case UpperHexadecimal:
1587 case UpperLatin:
1588 case UpperNorwegian:
1589 case UpperRoman:
1590 case Urdu:
1591 if (m_text.isEmpty())
1592 return IntRect();
1593 const Font& font = style()->font();
1594 int itemWidth = font.width(m_text);
1595 UChar suffixSpace[2] = { listMarkerSuffix(type, m_listItem->value()) , ' ' };
1596 int suffixSpaceWidth = font.width(constructTextRun(this, font, suffi xSpace, 2, styleRef(), style()->direction()));
1597 relativeRect = IntRect(0, 0, itemWidth + suffixSpaceWidth, font.font Metrics().height());
1598 }
1599
1600 if (!style()->isHorizontalWritingMode()) {
1601 relativeRect = relativeRect.transposedRect();
1602 relativeRect.setX(size().width() - relativeRect.x() - relativeRect.width ());
1603 }
1604
1605 return relativeRect;
1606 }
1607
1608 void RenderListMarker::setSelectionState(SelectionState state)
1609 {
1610 // The selection state for our containing block hierarchy is updated by the base class call.
1611 RenderBox::setSelectionState(state);
1612
1613 if (inlineBoxWrapper() && canUpdateSelectionOnRootLineBoxes())
1614 inlineBoxWrapper()->root().setHasSelectedChildren(state != SelectionNone );
1615 }
1616
1617 LayoutRect RenderListMarker::selectionRectForPaintInvalidation(const LayoutBoxMo delObject* paintInvalidationContainer) const
1618 {
1619 ASSERT(!needsLayout());
1620
1621 if (selectionState() == SelectionNone || !inlineBoxWrapper())
1622 return LayoutRect();
1623
1624 RootInlineBox& root = inlineBoxWrapper()->root();
1625 LayoutRect rect(0, root.selectionTop() - location().y(), size().width(), roo t.selectionHeight());
1626 mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, 0);
1627 // FIXME: groupedMapping() leaks the squashing abstraction.
1628 if (paintInvalidationContainer->layer()->groupedMapping())
1629 Layer::mapRectToPaintBackingCoordinates(paintInvalidationContainer, rect );
1630 return rect;
1631 }
1632
1633 void RenderListMarker::listItemStyleDidChange()
1634 {
1635 RefPtr<LayoutStyle> newStyle = LayoutStyle::create();
1636 // The marker always inherits from the list item, regardless of where it mig ht end
1637 // up (e.g., in some deeply nested line box). See CSS3 spec.
1638 newStyle->inheritFrom(m_listItem->styleRef());
1639 if (style()) {
1640 // Reuse the current margins. Otherwise resetting the margins to initial values
1641 // would trigger unnecessary layout.
1642 newStyle->setMarginStart(style()->marginStart());
1643 newStyle->setMarginEnd(style()->marginRight());
1644 }
1645 setStyle(newStyle.release());
1646 }
1647
1648 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/rendering/RenderListMarker.h ('k') | Source/core/rendering/RenderText.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698