Index: client/view/MeasureText.dart |
=================================================================== |
--- client/view/MeasureText.dart (revision 4144) |
+++ client/view/MeasureText.dart (working copy) |
@@ -1,161 +0,0 @@ |
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-// TODO(jacobr): handle splitting lines on symbols such as '-' that aren't |
-// whitespace but are valid word breaking points. |
-/** |
- * Utility class to efficiently word break and measure text without requiring |
- * access to the DOM. |
- */ |
-class MeasureText { |
- static CanvasRenderingContext2D _context; |
- |
- final String font; |
- num _spaceLength; |
- num _typicalCharLength; |
- |
- static final String ELLIPSIS = '...'; |
- |
- MeasureText(this.font) { |
- if (_context === null) { |
- CanvasElement canvas = new Element.tag('canvas'); |
- _context = canvas.getContext('2d'); |
- } |
- if (_spaceLength === null) { |
- _context.font = font; |
- _spaceLength = _context.measureText(' ').width; |
- _typicalCharLength = _context.measureText('k').width; |
- } |
- } |
- |
- // TODO(jacobr): we are DOA for i18N... |
- // the right solution is for the server to send us text perparsed into words |
- // perhaps even with hints on the guess for the correct breaks so on the |
- // client all we have to do is verify and fix errors rather than perform the |
- // full calculation. |
- static bool isWhitespace(String character) { |
- return character == ' ' || character == '\t' || character == '\n'; |
- } |
- |
- num get typicalCharLength() { |
- return _typicalCharLength; |
- } |
- |
- String quickTruncate(String text, num lineWidth, int maxLines) { |
- int targetLength = (lineWidth * maxLines / _typicalCharLength).toInt(); |
- // Advance to next word break point. |
- while(targetLength < text.length && !isWhitespace(text[targetLength])) { |
- targetLength++; |
- } |
- |
- if (targetLength < text.length) { |
- return text.substring(0, targetLength) + ELLIPSIS; |
- } else { |
- return text; |
- } |
- } |
- |
- /** |
- * Add line broken text as html separated by <br> elements. |
- * Returns the number of lines in the output. |
- * This function is safe to call with [:sb === null:] in which case just the |
- * line count is returned. |
- */ |
- int addLineBrokenText(StringBuffer sb, String text, num lineWidth, |
- int maxLines) { |
- // Strip surrounding whitespace. This ensures we create zero lines if there |
- // is no visible text. |
- text = text.trim(); |
- |
- // We can often avoid performing a full line break calculation when only |
- // the number of lines and not the actual linebreaks is required. |
- if (sb === null) { |
- _context.font = font; |
- int textWidth = _context.measureText(text).width.toInt(); |
- // By the pigeon hole principle, the resulting text will require at least |
- // maxLines if the raw text is longer than the amount of text that will |
- // fit on maxLines - 1. We add the length of a whitespace |
- // character to the lineWidth as each line is separated by a whitespace |
- // character. We assume all whitespace characters have the same length. |
- if (textWidth >= (lineWidth + _spaceLength) * (maxLines - 1)) { |
- return maxLines; |
- } else if (textWidth == 0) { |
- return 0; |
- } else if (textWidth < lineWidth) { |
- return 1; |
- } |
- // Fall through to the regular line breaking calculation as the number |
- // of lines required is unclear. |
- } |
- int lines = 0; |
- lineBreak(text, lineWidth, maxLines, (int start, int end, num width) { |
- lines++; |
- if (lines == maxLines) { |
- // Overflow case... there may be more lines of text than we can handle. |
- // Add a few characters to the last line so that the browser will |
- // render ellipses correctly. |
- // TODO(jacobr): make this optional and only add characters until |
- // the first whitespace character encountered. |
- end = Math.min(end + 50, text.length); |
- } |
- if (sb !== null) { |
- if (lines > 1) { |
- sb.add('<br>'); |
- } |
- // TODO(jacobr): HTML escape this text. |
- sb.add(text.substring(start, end)); |
- } |
- }); |
- return lines; |
- } |
- |
- void lineBreak(String text, num lineWidth, int maxLines, |
- Function callback) { |
- _context.font = font; |
- int lines = 0; |
- num currentLength = 0; |
- int startIndex = 0; |
- int wordStartIndex = null; |
- int lastWordEndIndex = null; |
- bool lastWhitespace = true; |
- // TODO(jacobr): optimize this further. |
- // To simplify the logic, we simulate injecting a whitespace character |
- // at the end of the string. |
- for (int i = 0, len = text.length; i <= len; i++) { |
- // Treat the char after the end of the string as whitespace. |
- bool whitespace = i == len || isWhitespace(text[i]); |
- if (whitespace && !lastWhitespace) { |
- num wordLength = _context.measureText(text.substring( |
- wordStartIndex, i)).width; |
- // TODO(jimhug): Replace the line above with this one to workaround |
- // dartium bug - error: unimplemented code |
- // num wordLength = (i - wordStartIndex) * 17; |
- currentLength += wordLength; |
- if (currentLength > lineWidth) { |
- // Edge case: |
- // It could be the very first word we ran into was too long for a |
- // line in which case we let it have its own line. |
- if (lastWordEndIndex !== null) { |
- lines++; |
- callback(startIndex, lastWordEndIndex, currentLength - wordLength); |
- } |
- if (lines == maxLines) { |
- return; |
- } |
- startIndex = wordStartIndex; |
- currentLength = wordLength; |
- } |
- lastWordEndIndex = i; |
- currentLength += _spaceLength; |
- wordStartIndex = null; |
- } else if (wordStartIndex === null && !whitespace) { |
- wordStartIndex = i; |
- } |
- lastWhitespace = whitespace; |
- } |
- if (currentLength > 0) { |
- callback(startIndex, text.length, currentLength); |
- } |
- } |
-} |