OLD | NEW |
| (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 | |
OLD | NEW |