TextLineIterator.jvm.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. //
  2. // System.Drawing.Test.TextLineIterator.jvm.cs
  3. //
  4. // Author:
  5. // Konstantin Triger <[email protected]>
  6. //
  7. // Copyright (C) 2005 Mainsoft Corporation, (http://www.mainsoft.com)
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. using System;
  29. using System.Drawing.Drawing2D;
  30. using font = java.awt.font;
  31. using text = java.text;
  32. using awt = java.awt;
  33. using geom = java.awt.geom;
  34. namespace System.Drawing.Text {
  35. internal sealed class TextLineIterator {
  36. #region Fields
  37. readonly float _width;
  38. readonly float _height;
  39. readonly StringFormat _format;
  40. readonly font.FontRenderContext _frc;
  41. readonly string _s;
  42. readonly Font _font;
  43. readonly float _margin;
  44. static readonly string NewLine;
  45. static readonly geom.AffineTransform Rotate90Transform =
  46. geom.AffineTransform.getRotateInstance(Math.PI/2);
  47. font.TextMeasurer _measurer;
  48. int _charsConsumed = 0;
  49. int _currentPos = 0;
  50. int _currentRun = 0;
  51. float _accumulatedHeight = 0;
  52. #endregion
  53. #region ctors
  54. static TextLineIterator() {
  55. string newLine = Environment.NewLine;
  56. if (newLine == null || newLine.Length == 0 || newLine[newLine.Length - 1] == '\n')
  57. newLine = "\n";
  58. NewLine = newLine;
  59. }
  60. internal TextLineIterator(string s, Font font, font.FontRenderContext frc, StringFormat format, float width, float height) {
  61. _format = (format != null) ? format : new StringFormat();
  62. _font = font;
  63. _s = (s != null) ? s : String.Empty;
  64. _frc = frc;
  65. FontFamily ff = font.FontFamily;
  66. _margin = font.Size*ff.GetDrawMargin(font.Style)/ff.GetEmHeight(font.Style);
  67. _width = width;
  68. _height = height;
  69. }
  70. #endregion
  71. #region Properties
  72. float WrapWidth {
  73. get { return (_format.IsVertical ? Height : Width) - (Margin * 2); }
  74. }
  75. internal float WrapHeight {
  76. get { return (_format.IsVertical ? Width : Height); }
  77. }
  78. internal float Width {
  79. get { return _width; }
  80. }
  81. internal float Height {
  82. get { return _height; }
  83. }
  84. internal StringFormat Format {
  85. get { return _format; }
  86. }
  87. internal float Margin {
  88. get { return _margin; }
  89. }
  90. internal int CharsConsumed {
  91. get { return _charsConsumed; }
  92. }
  93. internal int CurrentRun {
  94. get { return _currentRun; }
  95. }
  96. internal int CurrentPosition {
  97. get { return _currentPos; }
  98. }
  99. internal float AccumulatedHeight {
  100. get { return _accumulatedHeight; }
  101. }
  102. internal float GetAdvanceBetween(int start, int limit) {
  103. return _measurer.getAdvanceBetween(start, limit);
  104. }
  105. internal geom.AffineTransform Transform {
  106. get { return Format.IsVertical ? Rotate90Transform : Matrix.IdentityTransform.NativeObject; }
  107. }
  108. #endregion
  109. #region Methods
  110. LineLayout NextTextLayoutFromMeasurer() {
  111. if (_accumulatedHeight >= WrapHeight) {
  112. _charsConsumed += _currentPos;
  113. return null;
  114. }
  115. int limit = _measurer.getLineBreakIndex(_currentPos, WrapWidth);
  116. int wordBreak = limit;
  117. if (wordBreak < _currentRun) {
  118. while (wordBreak >= _currentPos && char.IsLetterOrDigit(_s, _charsConsumed + wordBreak))
  119. wordBreak--;
  120. if (wordBreak > _currentPos)
  121. limit = wordBreak + 1;
  122. }
  123. font.TextLayout layout = _measurer.getLayout(_currentPos, limit);
  124. LineLayout lineLayout = new LineLayout(
  125. layout,
  126. this,
  127. _accumulatedHeight);
  128. float lineHeight = lineLayout.Ascent + lineLayout.Descent;
  129. if (Format.LineLimit && (_accumulatedHeight + lineHeight > WrapHeight)) {
  130. _charsConsumed += _currentPos;
  131. return null;
  132. }
  133. _accumulatedHeight += lineHeight + lineLayout.Leading;
  134. _currentPos = limit;
  135. while (_currentPos < _currentRun) {
  136. if (char.IsWhiteSpace(_s, _charsConsumed + _currentPos))
  137. _currentPos++;
  138. else
  139. break;
  140. }
  141. return lineLayout;
  142. }
  143. internal LineLayout NextLine() {
  144. if (_currentPos < _currentRun && !Format.NoWrap)
  145. return NextTextLayoutFromMeasurer();
  146. _charsConsumed += _currentRun;
  147. if (_charsConsumed >= _s.Length)
  148. return null;
  149. string s;
  150. int lineBreakIndex = _s.IndexOf(NewLine, _charsConsumed);
  151. if (lineBreakIndex >= 0) {
  152. s = _s.Substring(_charsConsumed, lineBreakIndex - _charsConsumed + NewLine.Length);
  153. }
  154. else
  155. s = _s.Substring(_charsConsumed);
  156. _currentRun = s.Length;
  157. _currentPos = 0;
  158. text.AttributedString aS = new text.AttributedString(s);
  159. // TODO: add more attribs according to StringFormat
  160. aS.addAttribute(font.TextAttribute.FONT, _font.NativeObject);
  161. if((_font.Style & FontStyle.Underline) != FontStyle.Regular)
  162. aS.addAttribute(font.TextAttribute.UNDERLINE, font.TextAttribute.UNDERLINE_ON);
  163. if((_font.Style & FontStyle.Strikeout) != FontStyle.Regular)
  164. aS.addAttribute(font.TextAttribute.STRIKETHROUGH, font.TextAttribute.STRIKETHROUGH_ON);
  165. text.AttributedCharacterIterator charIter = aS.getIterator();
  166. _measurer = new font.TextMeasurer(charIter, _frc);
  167. return NextTextLayoutFromMeasurer();
  168. }
  169. internal geom.AffineTransform CalcLineAlignmentTransform() {
  170. if (Format.LineAlignment == StringAlignment.Near)
  171. return null;
  172. float height = WrapHeight;
  173. if (float.IsPositiveInfinity(height))
  174. height = 0;
  175. float shift = height - AccumulatedHeight;
  176. if (height > 0 && shift <= 0)
  177. return null;
  178. if (Format.LineAlignment == StringAlignment.Center)
  179. shift /= 2;
  180. else
  181. if (Format.IsVertical && Format.IsRightToLeft)
  182. return null;
  183. return Format.IsVertical ?
  184. geom.AffineTransform.getTranslateInstance(shift, 0) :
  185. geom.AffineTransform.getTranslateInstance(0, shift);
  186. }
  187. #endregion
  188. }
  189. }