2 // System.Drawing.Test.TextLineIterator.jvm.cs
5 // Konstantin Triger <kostat@mainsoft.com>
7 // Copyright (C) 2005 Mainsoft Corporation, (http://www.mainsoft.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
30 using System.Drawing.Drawing2D;
32 using font = java.awt.font;
\r
33 using text = java.text;
34 using awt = java.awt;
\r
35 using geom = java.awt.geom;
37 namespace System.Drawing.Text {
38 internal sealed class TextLineIterator {
42 readonly float _width;
\r
43 readonly float _height;
\r
44 readonly StringFormat _format;
\r
45 readonly font.FontRenderContext _frc;
48 readonly float _margin;
50 static readonly string NewLine;
\r
52 static readonly geom.AffineTransform Rotate90Transform =
\r
53 geom.AffineTransform.getRotateInstance(Math.PI/2);
\r
55 font.TextMeasurer _measurer;
\r
56 int _charsConsumed = 0;
\r
57 int _currentPos = 0;
\r
58 int _currentRun = 0;
\r
59 float _accumulatedHeight = 0;
\r
65 static TextLineIterator() {
\r
66 string newLine = Environment.NewLine;
\r
67 if (newLine == null || newLine.Length == 0 || newLine[newLine.Length - 1] == '\n')
\r
73 internal TextLineIterator(string s, Font font, font.FontRenderContext frc, StringFormat format, float width, float height) {
\r
74 _format = (format != null) ? format : new StringFormat();
\r
76 _s = (s != null) ? s : String.Empty;
\r
78 FontFamily ff = font.FontFamily;
\r
79 _margin = font.Size*ff.GetDrawMargin(font.Style)/ff.GetEmHeight(font.Style);
\r
90 get { return (_format.IsVertical ? Height : Width) - (Margin * 2); }
93 internal float WrapHeight {
94 get { return (_format.IsVertical ? Width : Height); }
97 internal float Width {
98 get { return _width; }
101 internal float Height {
102 get { return _height; }
105 internal StringFormat Format {
106 get { return _format; }
109 internal float Margin {
110 get { return _margin; }
113 internal int CharsConsumed {
114 get { return _charsConsumed; }
117 internal int CurrentRun {
118 get { return _currentRun; }
121 internal int CurrentPosition {
122 get { return _currentPos; }
125 internal float AccumulatedHeight {
126 get { return _accumulatedHeight; }
129 internal float GetAdvanceBetween(int start, int limit) {
130 return _measurer.getAdvanceBetween(start, limit);
133 internal geom.AffineTransform Transform {
134 get { return Format.IsVertical ? Rotate90Transform : Matrix.IdentityTransform.NativeObject; }
141 LineLayout NextTextLayoutFromMeasurer() {
142 if (_accumulatedHeight >= WrapHeight) {
143 _charsConsumed += _currentPos;
147 int limit = _measurer.getLineBreakIndex(_currentPos, WrapWidth);
149 int wordBreak = limit;
150 if (wordBreak < _currentRun) {
151 while (wordBreak >= _currentPos && char.IsLetterOrDigit(_s, _charsConsumed + wordBreak))
154 if (wordBreak > _currentPos)
155 limit = wordBreak + 1;
157 font.TextLayout layout = _measurer.getLayout(_currentPos, limit);
159 LineLayout lineLayout = new LineLayout(
164 float lineHeight = lineLayout.Ascent + lineLayout.Descent;
166 if (Format.LineLimit && (_accumulatedHeight + lineHeight > WrapHeight)) {
167 _charsConsumed += _currentPos;
171 _accumulatedHeight += lineHeight + lineLayout.Leading;
175 while (_currentPos < _currentRun) {
176 if (char.IsWhiteSpace(_s, _charsConsumed + _currentPos))
184 internal LineLayout NextLine() {
185 if (_currentPos < _currentRun && !Format.NoWrap)
186 return NextTextLayoutFromMeasurer();
188 _charsConsumed += _currentRun;
189 if (_charsConsumed >= _s.Length)
\r
193 int lineBreakIndex = _s.IndexOf(NewLine, _charsConsumed);
\r
194 if (lineBreakIndex >= 0) {
\r
195 s = _s.Substring(_charsConsumed, lineBreakIndex - _charsConsumed + NewLine.Length);
\r
198 s = _s.Substring(_charsConsumed);
\r
200 _currentRun = s.Length;
\r
203 text.AttributedString aS = new text.AttributedString(s);
\r
205 // TODO: add more attribs according to StringFormat
\r
206 aS.addAttribute(font.TextAttribute.FONT, _font.NativeObject);
\r
207 if((_font.Style & FontStyle.Underline) != FontStyle.Regular)
208 aS.addAttribute(font.TextAttribute.UNDERLINE, font.TextAttribute.UNDERLINE_ON);
209 if((_font.Style & FontStyle.Strikeout) != FontStyle.Regular)
210 aS.addAttribute(font.TextAttribute.STRIKETHROUGH, font.TextAttribute.STRIKETHROUGH_ON);
\r
212 text.AttributedCharacterIterator charIter = aS.getIterator();
\r
214 _measurer = new font.TextMeasurer(charIter, _frc);
215 return NextTextLayoutFromMeasurer();
218 internal geom.AffineTransform CalcLineAlignmentTransform() {
219 if (Format.LineAlignment == StringAlignment.Near)
\r
221 float height = WrapHeight;
\r
222 if (float.IsPositiveInfinity(height))
\r
225 float shift = height - AccumulatedHeight;
\r
226 if (height > 0 && shift <= 0)
\r
229 if (Format.LineAlignment == StringAlignment.Center)
\r
232 if (Format.IsVertical && Format.IsRightToLeft)
\r
235 return Format.IsVertical ?
\r
236 geom.AffineTransform.getTranslateInstance(shift, 0) :
\r
237 geom.AffineTransform.getTranslateInstance(0, shift);