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

Side by Side Diff: pkg/intl/lib/bidi_utils.dart

Issue 10961061: migrate raw string to new syntax in pkg (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « pkg/args/lib/args.dart ('k') | pkg/intl/lib/intl_standalone.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * Bidi stands for Bi-directional text. 6 * Bidi stands for Bi-directional text.
7 * According to http://en.wikipedia.org/wiki/Bi-directional_text: 7 * According to http://en.wikipedia.org/wiki/Bi-directional_text:
8 * Bi-directional text is text containing text in both text directionalities, 8 * Bi-directional text is text containing text in both text directionalities,
9 * both right-to-left (RTL) and left-to-right (LTR). It generally involves text 9 * both right-to-left (RTL) and left-to-right (LTR). It generally involves text
10 * containing different types of alphabets, but may also refer to boustrophedon, 10 * containing different types of alphabets, but may also refer to boustrophedon,
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 65
66 /** Constant to define the threshold of RTL directionality. */ 66 /** Constant to define the threshold of RTL directionality. */
67 num _RTL_DETECTION_THRESHOLD = 0.40; 67 num _RTL_DETECTION_THRESHOLD = 0.40;
68 68
69 /** 69 /**
70 * Practical patterns to identify strong LTR and RTL characters, respectively. 70 * Practical patterns to identify strong LTR and RTL characters, respectively.
71 * These patterns are not completely correct according to the Unicode 71 * These patterns are not completely correct according to the Unicode
72 * standard. They are simplified for performance and small code size. 72 * standard. They are simplified for performance and small code size.
73 */ 73 */
74 const String _LTR_CHARS = 74 const String _LTR_CHARS =
75 @'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590' 75 r'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590'
76 @'\u0800-\u1FFF\u2C00-\uFB1C\uFDFE-\uFE6F\uFEFD-\uFFFF'; 76 r'\u0800-\u1FFF\u2C00-\uFB1C\uFDFE-\uFE6F\uFEFD-\uFFFF';
77 const String _RTL_CHARS = @'\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC'; 77 const String _RTL_CHARS = r'\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC';
78 78
79 /** 79 /**
80 * Returns the input [text] with spaces instead of HTML tags or HTML escapes, 80 * Returns the input [text] with spaces instead of HTML tags or HTML escapes,
81 * which is helpful for text directionality estimation. 81 * which is helpful for text directionality estimation.
82 * Note: This function should not be used in other contexts. 82 * Note: This function should not be used in other contexts.
83 * It does not deal well with many things: comments, script, 83 * It does not deal well with many things: comments, script,
84 * elements, style elements, dir attribute,`>` in quoted attribute values, 84 * elements, style elements, dir attribute,`>` in quoted attribute values,
85 * etc. But it does handle well enough the most common use cases. 85 * etc. But it does handle well enough the most common use cases.
86 * Since the worst that can happen as a result of these shortcomings is that 86 * Since the worst that can happen as a result of these shortcomings is that
87 * the wrong directionality will be estimated, we have not invested in 87 * the wrong directionality will be estimated, we have not invested in
88 * improving this. 88 * improving this.
89 */ 89 */
90 String stripHtmlIfNeeded(String text) { 90 String stripHtmlIfNeeded(String text) {
91 // The regular expression is simplified for an HTML tag (opening or 91 // The regular expression is simplified for an HTML tag (opening or
92 // closing) or an HTML escape. We might want to skip over such expressions 92 // closing) or an HTML escape. We might want to skip over such expressions
93 // when estimating the text directionality. 93 // when estimating the text directionality.
94 return text.replaceAll(const RegExp(@'<[^>]*>|&[^;]+;'), ' '); 94 return text.replaceAll(const RegExp(r'<[^>]*>|&[^;]+;'), ' ');
95 } 95 }
96 96
97 /** 97 /**
98 * Determines if the first character in [text] with strong directionality is 98 * Determines if the first character in [text] with strong directionality is
99 * LTR. If [isHtml] is true, the text is HTML or HTML-escaped. 99 * LTR. If [isHtml] is true, the text is HTML or HTML-escaped.
100 */ 100 */
101 bool startsWithLtr(String text, [isHtml=false]) { 101 bool startsWithLtr(String text, [isHtml=false]) {
102 return const RegExp('^[^$_RTL_CHARS]*[$_LTR_CHARS]').hasMatch( 102 return const RegExp('^[^$_RTL_CHARS]*[$_LTR_CHARS]').hasMatch(
103 isHtml? stripHtmlIfNeeded(text) : text); 103 isHtml? stripHtmlIfNeeded(text) : text);
104 } 104 }
(...skipping 25 matching lines...) Expand all
130 bool endsWithRtl(String text, [isHtml=false]) { 130 bool endsWithRtl(String text, [isHtml=false]) {
131 return const RegExp('[$_RTL_CHARS][^$_LTR_CHARS]*\$').hasMatch( 131 return const RegExp('[$_RTL_CHARS][^$_LTR_CHARS]*\$').hasMatch(
132 isHtml? stripHtmlIfNeeded(text) : text); 132 isHtml? stripHtmlIfNeeded(text) : text);
133 } 133 }
134 134
135 /** 135 /**
136 * Determines if the given [text] has any LTR characters in it. 136 * Determines if the given [text] has any LTR characters in it.
137 * If [isHtml] is true, the text is HTML or HTML-escaped. 137 * If [isHtml] is true, the text is HTML or HTML-escaped.
138 */ 138 */
139 bool hasAnyLtr(String text, [isHtml=false]) { 139 bool hasAnyLtr(String text, [isHtml=false]) {
140 return const RegExp(@'[' '$_LTR_CHARS' @']').hasMatch( 140 return const RegExp(r'[' '$_LTR_CHARS' r']').hasMatch(
141 isHtml? stripHtmlIfNeeded(text) : text); 141 isHtml? stripHtmlIfNeeded(text) : text);
142 } 142 }
143 143
144 /** 144 /**
145 * Determines if the given [text] has any RTL characters in it. 145 * Determines if the given [text] has any RTL characters in it.
146 * If [isHtml] is true, the text is HTML or HTML-escaped. 146 * If [isHtml] is true, the text is HTML or HTML-escaped.
147 */ 147 */
148 bool hasAnyRtl(String text, [isHtml=false]) { 148 bool hasAnyRtl(String text, [isHtml=false]) {
149 return const RegExp(@'[' '$_RTL_CHARS' @']').hasMatch( 149 return const RegExp(r'[' '$_RTL_CHARS' r']').hasMatch(
150 isHtml? stripHtmlIfNeeded(text) : text); 150 isHtml? stripHtmlIfNeeded(text) : text);
151 } 151 }
152 152
153 /** 153 /**
154 * Check if a BCP 47 / III [languageString] indicates an RTL language. 154 * Check if a BCP 47 / III [languageString] indicates an RTL language.
155 * 155 *
156 * i.e. either: 156 * i.e. either:
157 * - a language code explicitly specifying one of the right-to-left scripts, 157 * - a language code explicitly specifying one of the right-to-left scripts,
158 * e.g. "az-Arab", or 158 * e.g. "az-Arab", or
159 * - a language code specifying one of the languages normally written in a 159 * - a language code specifying one of the languages normally written in a
160 * right-to-left script, e.g. "fa" (Farsi), except ones explicitly 160 * right-to-left script, e.g. "fa" (Farsi), except ones explicitly
161 * specifying Latin or Cyrillic script (which are the usual LTR 161 * specifying Latin or Cyrillic script (which are the usual LTR
162 * alternatives). 162 * alternatives).
163 * 163 *
164 * The list of right-to-left scripts appears in the 100-199 range in 164 * The list of right-to-left scripts appears in the 100-199 range in
165 * http://www.unicode.org/iso15924/iso15924-num.html, of which Arabic and 165 * http://www.unicode.org/iso15924/iso15924-num.html, of which Arabic and
166 * Hebrew are by far the most widely used. We also recognize Thaana, N'Ko, and 166 * Hebrew are by far the most widely used. We also recognize Thaana, N'Ko, and
167 * Tifinagh, which also have significant modern usage. The rest (Syriac, 167 * Tifinagh, which also have significant modern usage. The rest (Syriac,
168 * Samaritan, Mandaic, etc.) seem to have extremely limited or no modern usage 168 * Samaritan, Mandaic, etc.) seem to have extremely limited or no modern usage
169 * and are not recognized. 169 * and are not recognized.
170 * The languages usually written in a right-to-left script are taken as those 170 * The languages usually written in a right-to-left script are taken as those
171 * with Suppress-Script: Hebr|Arab|Thaa|Nkoo|Tfng in 171 * with Suppress-Script: Hebr|Arab|Thaa|Nkoo|Tfng in
172 * http://www.iana.org/assignments/language-subtag-registry, 172 * http://www.iana.org/assignments/language-subtag-registry,
173 * as well as Sindhi (sd) and Uyghur (ug). 173 * as well as Sindhi (sd) and Uyghur (ug).
174 * The presence of other subtags of the language code, e.g. regions like EG 174 * The presence of other subtags of the language code, e.g. regions like EG
175 * (Egypt), is ignored. 175 * (Egypt), is ignored.
176 */ 176 */
177 bool isRtlLanguage(String languageString) { 177 bool isRtlLanguage(String languageString) {
178 return const RegExp(@'^(ar|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_]' 178 return const RegExp(r'^(ar|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_]'
179 @'(Arab|Hebr|Thaa|Nkoo|Tfng))(?!.*[-_](Latn|Cyrl)($|-|_))' 179 r'(Arab|Hebr|Thaa|Nkoo|Tfng))(?!.*[-_](Latn|Cyrl)($|-|_))'
180 @'($|-|_)', ignoreCase : true).hasMatch(languageString); 180 r'($|-|_)', ignoreCase : true).hasMatch(languageString);
181 } 181 }
182 182
183 /** 183 /**
184 * Enforce the [html] snippet in RTL directionality regardless of overall 184 * Enforce the [html] snippet in RTL directionality regardless of overall
185 * context. If the html piece was enclosed by a tag, the direction will be 185 * context. If the html piece was enclosed by a tag, the direction will be
186 * applied to existing tag, otherwise a span tag will be added as wrapper. 186 * applied to existing tag, otherwise a span tag will be added as wrapper.
187 * For this reason, if html snippet start with with tag, this tag must enclose 187 * For this reason, if html snippet start with with tag, this tag must enclose
188 * the whole piece. If the tag already has a direction specified, this new one 188 * the whole piece. If the tag already has a direction specified, this new one
189 * will override existing one in behavior (should work on Chrome, FF, and IE 189 * will override existing one in behavior (should work on Chrome, FF, and IE
190 * since this was ported directly from the Closure version). 190 * since this was ported directly from the Closure version).
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 247
248 /** 248 /**
249 * Apply bracket guard to [str] using html span tag. This is to address the 249 * Apply bracket guard to [str] using html span tag. This is to address the
250 * problem of messy bracket display that frequently happens in RTL layout. 250 * problem of messy bracket display that frequently happens in RTL layout.
251 * If [isRtlContext] is true, then we explicitly want to wrap in a span of RTL 251 * If [isRtlContext] is true, then we explicitly want to wrap in a span of RTL
252 * directionality, regardless of the estimated directionality. 252 * directionality, regardless of the estimated directionality.
253 */ 253 */
254 String guardBracketInHtml(String str, [bool isRtlContext]) { 254 String guardBracketInHtml(String str, [bool isRtlContext]) {
255 var useRtl = isRtlContext == null ? hasAnyRtl(str) : isRtlContext; 255 var useRtl = isRtlContext == null ? hasAnyRtl(str) : isRtlContext;
256 RegExp matchingBrackets = 256 RegExp matchingBrackets =
257 const RegExp(@'(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(&lt;.*?(&gt;)+)'); 257 const RegExp(r'(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(&lt;.*?(&gt;)+)');
258 return _guardBracketHelper(str, matchingBrackets, 258 return _guardBracketHelper(str, matchingBrackets,
259 '<span dir=${useRtl? "rtl" : "ltr"}>', '</span>'); 259 '<span dir=${useRtl? "rtl" : "ltr"}>', '</span>');
260 } 260 }
261 261
262 /** 262 /**
263 * Apply bracket guard to [str] using LRM and RLM. This is to address the 263 * Apply bracket guard to [str] using LRM and RLM. This is to address the
264 * problem of messy bracket display that frequently happens in RTL layout. 264 * problem of messy bracket display that frequently happens in RTL layout.
265 * This version works for both plain text and html, but in some cases is not 265 * This version works for both plain text and html, but in some cases is not
266 * as good as guardBracketInHtml. 266 * as good as guardBracketInHtml.
267 * If [isRtlContext] is true, then we explicitly want to wrap in a span of RTL 267 * If [isRtlContext] is true, then we explicitly want to wrap in a span of RTL
268 * directionality, regardless of the estimated directionality. 268 * directionality, regardless of the estimated directionality.
269 */ 269 */
270 String guardBracketInText(String str, [bool isRtlContext]) { 270 String guardBracketInText(String str, [bool isRtlContext]) {
271 var useRtl = isRtlContext == null ? hasAnyRtl(str) : isRtlContext; 271 var useRtl = isRtlContext == null ? hasAnyRtl(str) : isRtlContext;
272 var mark = useRtl ? RLM : LRM; 272 var mark = useRtl ? RLM : LRM;
273 return _guardBracketHelper(str, 273 return _guardBracketHelper(str,
274 const RegExp(@'(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)'), mark, mark); 274 const RegExp(r'(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)'), mark, mark);
275 } 275 }
276 276
277 /** 277 /**
278 * (Mostly) reimplements the $& functionality of "replace" in JavaScript. 278 * (Mostly) reimplements the $& functionality of "replace" in JavaScript.
279 * Given a [str] and the [regexp] to match with, optionally supply a string to 279 * Given a [str] and the [regexp] to match with, optionally supply a string to
280 * be inserted [before] the match and/or [after]. For example, 280 * be inserted [before] the match and/or [after]. For example,
281 * `_guardBracketHelper('firetruck', const RegExp('truck'), 'hydrant', '!')` 281 * `_guardBracketHelper('firetruck', const RegExp('truck'), 'hydrant', '!')`
282 * would return 'firehydrant!'. 282 * would return 'firehydrant!'.
283 */ 283 */
284 // TODO(efortuna): Get rid of this once this is implemented in Dart. 284 // TODO(efortuna): Get rid of this once this is implemented in Dart.
(...skipping 23 matching lines...) Expand all
308 * Otherwise, returns UNKNOWN, which is used to mean `neutral`. 308 * Otherwise, returns UNKNOWN, which is used to mean `neutral`.
309 * Numbers and URLs are counted as weakly LTR. 309 * Numbers and URLs are counted as weakly LTR.
310 */ 310 */
311 TextDirection estimateDirectionOfText(String text, [bool isHtml=false]) { 311 TextDirection estimateDirectionOfText(String text, [bool isHtml=false]) {
312 text = isHtml? stripHtmlIfNeeded(text) : text; 312 text = isHtml? stripHtmlIfNeeded(text) : text;
313 var rtlCount = 0; 313 var rtlCount = 0;
314 var total = 0; 314 var total = 0;
315 var hasWeaklyLtr = false; 315 var hasWeaklyLtr = false;
316 // Split a string into 'words' for directionality estimation based on 316 // Split a string into 'words' for directionality estimation based on
317 // relative word counts. 317 // relative word counts.
318 for (String token in text.split(const RegExp(@'\s+'))) { 318 for (String token in text.split(const RegExp(r'\s+'))) {
319 if (startsWithRtl(token)) { 319 if (startsWithRtl(token)) {
320 rtlCount++; 320 rtlCount++;
321 total++; 321 total++;
322 } else if (const RegExp(@'^http://').hasMatch(token)) { 322 } else if (const RegExp(r'^http://').hasMatch(token)) {
323 // Checked if token looks like something that must always be LTR even in 323 // Checked if token looks like something that must always be LTR even in
324 // RTL text, such as a URL. 324 // RTL text, such as a URL.
325 hasWeaklyLtr = true; 325 hasWeaklyLtr = true;
326 } else if (hasAnyLtr(token)) { 326 } else if (hasAnyLtr(token)) {
327 total++; 327 total++;
328 } else if (const RegExp(@'\d').hasMatch(token)) { 328 } else if (const RegExp(r'\d').hasMatch(token)) {
329 // Checked if token contains any numerals. 329 // Checked if token contains any numerals.
330 hasWeaklyLtr = true; 330 hasWeaklyLtr = true;
331 } 331 }
332 } 332 }
333 333
334 if (total == 0) { 334 if (total == 0) {
335 return hasWeaklyLtr ? TextDirection.LTR : TextDirection.UNKNOWN; 335 return hasWeaklyLtr ? TextDirection.LTR : TextDirection.UNKNOWN;
336 } else if (rtlCount > _RTL_DETECTION_THRESHOLD * total) { 336 } else if (rtlCount > _RTL_DETECTION_THRESHOLD * total) {
337 return TextDirection.RTL; 337 return TextDirection.RTL;
338 } else { 338 } else {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 } 382 }
383 383
384 /** 384 /**
385 * Check the estimated directionality of [str], return true if the piece of 385 * Check the estimated directionality of [str], return true if the piece of
386 * text should be laid out in RTL direction. If [isHtml] is true, the string 386 * text should be laid out in RTL direction. If [isHtml] is true, the string
387 * is HTML or HTML-escaped. 387 * is HTML or HTML-escaped.
388 */ 388 */
389 bool detectRtlDirectionality(String str, [bool isHtml]) { 389 bool detectRtlDirectionality(String str, [bool isHtml]) {
390 return estimateDirectionOfText(str, isHtml) == TextDirection.RTL; 390 return estimateDirectionOfText(str, isHtml) == TextDirection.RTL;
391 } 391 }
OLDNEW
« no previous file with comments | « pkg/args/lib/args.dart ('k') | pkg/intl/lib/intl_standalone.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698