Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 #library("UnicodeCore"); | |
| 6 | |
| 7 /* | |
| 8 * Test for presence of bug related to the use of UTF-16 code units for | |
| 9 * Dart compiled to JS. | |
| 10 */ | |
| 11 bool _test16BitCodeUnit = null; | |
| 12 // TODO is16BitCodeUnit() is used to work around a bug with frog/dartc | |
| 13 // (http://code.google.com/p/dart/issues/detail?id=1357). Consider | |
| 14 // removing after this issue is resolved. | |
| 15 bool is16BitCodeUnit() { | |
| 16 if (_test16BitCodeUnit == null) { | |
| 17 _test16BitCodeUnit = (new String.fromCharCodes([0x1D11E])) == | |
| 18 (new String.fromCharCodes([0xD11E])); | |
| 19 } | |
| 20 return _test16BitCodeUnit; | |
| 21 } | |
| 22 | |
| 23 | |
| 24 /** | |
| 25 * Invalid codepoints or encodings may be substituted with the value U+fffd. | |
| 26 */ | |
| 27 final int UNICODE_REPLACEMENT_CHARACTER_CODEPOINT = 0xfffd; | |
| 28 final int UNICODE_BOM = 0xfeff; | |
| 29 final int UNICODE_UTF_BOM_LO = 0xff; | |
| 30 final int UNICODE_UTF_BOM_HI = 0xfe; | |
| 31 | |
| 32 final int UNICODE_BYTE_ZERO_MASK = 0xff; | |
| 33 final int UNICODE_BYTE_ONE_MASK = 0xff00; | |
| 34 final int UNICODE_VALID_RANGE_MAX = 0x10ffff; | |
| 35 final int UNICODE_PLANE_ONE_MAX = 0xffff; | |
| 36 final int UNICODE_UTF16_RESERVED_LO = 0xd800; | |
| 37 final int UNICODE_UTF16_RESERVED_HI = 0xdfff; | |
| 38 final int UNICODE_UTF16_OFFSET = 0x10000; | |
| 39 final int UNICODE_UTF16_SURROGATE_UNIT_0_BASE = 0xd800; | |
| 40 final int UNICODE_UTF16_SURROGATE_UNIT_1_BASE = 0xdc00; | |
| 41 final int UNICODE_UTF16_HI_MASK = 0xffc00; | |
| 42 final int UNICODE_UTF16_LO_MASK = 0x3ff; | |
| 43 | |
| 44 /** | |
| 45 * Encode code points as UTF16 code units. | |
|
Søren Gjesse
2012/02/01 11:25:25
Please be consistent with UTF16/utf16 in comments.
dcarlson
2012/02/01 22:18:46
Done. I went ahead and made sure all the variants
| |
| 46 */ | |
| 47 List<int> codepointsToUtf16CodeUnits(List<int> codepoints, | |
| 48 [int start = 0, int length = null]) { | |
| 49 if (!(start >= 0)) { | |
| 50 throw new IllegalArgumentException("start"); | |
| 51 } | |
| 52 | |
| 53 if (!(length == null || length >= 0)) { | |
| 54 throw new IllegalArgumentException("length"); | |
| 55 } | |
| 56 | |
| 57 int end = length != null ? | |
| 58 Math.min(codepoints.length, start + length) : | |
| 59 codepoints.length; | |
| 60 | |
| 61 List<int> codeUnitsBuffer = <int>[]; | |
| 62 int i = start; | |
| 63 while (i < end) { | |
| 64 int value = codepoints[i++]; | |
| 65 if ((value >= 0 && value < UNICODE_UTF16_RESERVED_LO) || | |
| 66 (value > UNICODE_UTF16_RESERVED_HI && value <= UNICODE_PLANE_ONE_MAX)) { | |
| 67 codeUnitsBuffer.add(value); | |
| 68 } else if (value > UNICODE_PLANE_ONE_MAX && | |
| 69 value <= UNICODE_VALID_RANGE_MAX) { | |
| 70 int base = value - UNICODE_UTF16_OFFSET; | |
| 71 codeUnitsBuffer.add(UNICODE_UTF16_SURROGATE_UNIT_0_BASE + | |
| 72 ((base & UNICODE_UTF16_HI_MASK) >> 10)); | |
| 73 codeUnitsBuffer.add(UNICODE_UTF16_SURROGATE_UNIT_1_BASE + | |
| 74 (base & UNICODE_UTF16_LO_MASK)); | |
| 75 } else { | |
| 76 codeUnitsBuffer.add(UNICODE_REPLACEMENT_CHARACTER_CODEPOINT); | |
| 77 } | |
| 78 } | |
| 79 return codeUnitsBuffer; | |
| 80 } | |
| 81 | |
| 82 /** | |
| 83 * Decodes the utf16 codeunits to codepoints. | |
| 84 */ | |
| 85 List<int> utf16CodeUnitsToCodepoints(List<int> utf16CodeUnits, | |
| 86 [int start = 0, int length = null]) { | |
|
Søren Gjesse
2012/02/01 11:25:25
Normally we don't split argument lists like this.
dcarlson
2012/02/01 22:18:46
Not always (other lines), but done with a simple l
| |
| 87 if (!(start >= 0)) { | |
| 88 throw new IllegalArgumentException("start"); | |
| 89 } | |
| 90 | |
| 91 if (!(length == null || length >= 0)) { | |
| 92 throw new IllegalArgumentException("length"); | |
| 93 } | |
| 94 | |
| 95 int end = length != null ? | |
| 96 Math.min(utf16CodeUnits.length, start + length) : | |
| 97 utf16CodeUnits.length; | |
| 98 | |
| 99 List<int> codepointBuffer = <int>[]; | |
| 100 int i = start; | |
| 101 // skip the first entry if it is a BOM. | |
| 102 if (end > 0 && utf16CodeUnits[0] == UNICODE_BOM) { | |
| 103 i++; | |
| 104 } | |
| 105 while (i < end) { | |
| 106 int value = utf16CodeUnits[i++]; | |
| 107 if (value < 0) { | |
| 108 codepointBuffer.add(UNICODE_REPLACEMENT_CHARACTER_CODEPOINT); | |
| 109 continue; | |
| 110 } | |
| 111 if (value < UNICODE_UTF16_RESERVED_LO || | |
| 112 (value > UNICODE_UTF16_RESERVED_HI && | |
| 113 value <= UNICODE_PLANE_ONE_MAX)) { | |
| 114 // transfer directly | |
| 115 codepointBuffer.add(value); | |
| 116 } else if (value < UNICODE_UTF16_SURROGATE_UNIT_1_BASE && i < end) { | |
| 117 // merge surrogate pair | |
| 118 value = (value - UNICODE_UTF16_SURROGATE_UNIT_0_BASE) << 10; | |
| 119 int nextValue = utf16CodeUnits[i++]; | |
| 120 if (nextValue >= UNICODE_UTF16_SURROGATE_UNIT_1_BASE && | |
| 121 nextValue <= UNICODE_UTF16_RESERVED_HI) { | |
| 122 value += UNICODE_UTF16_OFFSET + | |
| 123 (nextValue - UNICODE_UTF16_SURROGATE_UNIT_1_BASE); | |
| 124 codepointBuffer.add(value); | |
| 125 } else { | |
| 126 if (nextValue >= UNICODE_UTF16_SURROGATE_UNIT_0_BASE && | |
| 127 nextValue < UNICODE_UTF16_SURROGATE_UNIT_1_BASE) { | |
| 128 i--; | |
| 129 } | |
| 130 codepointBuffer.add(UNICODE_REPLACEMENT_CHARACTER_CODEPOINT); | |
| 131 continue; | |
| 132 } | |
| 133 } else { | |
| 134 codepointBuffer.add(UNICODE_REPLACEMENT_CHARACTER_CODEPOINT); | |
| 135 continue; | |
| 136 } | |
| 137 } | |
| 138 return codepointBuffer; | |
| 139 } | |
| OLD | NEW |