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
92 float widthOrHeight = _format.IsVertical ? Height : Width;
\r
93 if (!_format.IsGenericTypographic) {
\r
95 ((_format.IsVertical ? Height : Width) - (0.463f * FontSize)) / 1.028f;
\r
97 return widthOrHeight;
\r
101 internal float WrapHeight {
\r
103 float widthOrHeight = _format.IsVertical ? Width : Height;
\r
104 if (!_format.IsGenericTypographic) {
\r
105 widthOrHeight = (_format.IsVertical ? Width : Height) / 1.08864f;
\r
107 return widthOrHeight;
111 internal float Width {
112 get { return _width; }
115 internal float Height {
116 get { return _height; }
119 internal StringFormat Format {
120 get { return _format; }
123 internal float PadWidth (float origWidth)
\r
125 if (Format.IsGenericTypographic)
\r
128 //This is a proximity to .NET calculated Width.
\r
129 return origWidth * 1.028f + 0.463f * FontSize;
\r
132 internal float PadHeight (float origHeight)
\r
134 if (Format.IsGenericTypographic)
\r
137 //This is a proximity to .NET calculated Height.
\r
138 return 1.08864f * origHeight;
\r
141 internal float FontSize
\r
148 internal int CharsConsumed {
149 get { return _charsConsumed; }
152 internal int CurrentRun {
153 get { return _currentRun; }
156 internal int CurrentPosition {
157 get { return _currentPos; }
160 internal float AccumulatedHeight {
161 get { return _accumulatedHeight; }
164 internal float GetAdvanceBetween(int start, int limit) {
165 return _measurer.getAdvanceBetween(start, limit);
168 internal geom.AffineTransform Transform {
169 get { return Format.IsVertical ? Rotate90Transform : Matrix.IdentityTransform.NativeObject; }
176 LineLayout NextTextLayoutFromMeasurer() {
177 if (_accumulatedHeight >= WrapHeight) {
178 _charsConsumed += _currentPos;
182 int limit = _measurer.getLineBreakIndex(_currentPos, WrapWidth);
184 int wordBreak = limit;
185 if (wordBreak < _currentRun) {
186 while (wordBreak >= _currentPos && char.IsLetterOrDigit(_s, _charsConsumed + wordBreak))
189 if (wordBreak > _currentPos)
190 limit = wordBreak + 1;
192 font.TextLayout layout = _measurer.getLayout(_currentPos, limit);
194 LineLayout lineLayout = new LineLayout(
197 _accumulatedHeight);
\r
199 float lineHeight = PadHeight (lineLayout.Ascent + lineLayout.Descent + lineLayout.Leading);
201 if (Format.LineLimit && (_accumulatedHeight + lineHeight > WrapHeight)) {
202 _charsConsumed += _currentPos;
206 _accumulatedHeight += lineHeight + lineLayout.Leading;
210 while (_currentPos < _currentRun) {
211 if (char.IsWhiteSpace(_s, _charsConsumed + _currentPos))
219 internal LineLayout NextLine() {
220 if (_currentPos < _currentRun && !Format.NoWrap)
221 return NextTextLayoutFromMeasurer();
223 _charsConsumed += _currentRun;
224 if (_charsConsumed >= _s.Length)
\r
228 int lineBreakIndex = _s.IndexOf(NewLine, _charsConsumed);
\r
229 if (lineBreakIndex >= 0) {
\r
230 s = _s.Substring(_charsConsumed, lineBreakIndex - _charsConsumed + NewLine.Length);
\r
233 s = _s.Substring(_charsConsumed);
\r
235 _currentRun = s.Length;
\r
238 text.AttributedString aS = new text.AttributedString(s);
\r
240 // TODO: add more attribs according to StringFormat
\r
241 aS.addAttribute(font.TextAttribute.FONT, _font.NativeObject);
\r
242 if((_font.Style & FontStyle.Underline) != FontStyle.Regular)
243 aS.addAttribute(font.TextAttribute.UNDERLINE, font.TextAttribute.UNDERLINE_ON);
244 if((_font.Style & FontStyle.Strikeout) != FontStyle.Regular)
245 aS.addAttribute(font.TextAttribute.STRIKETHROUGH, font.TextAttribute.STRIKETHROUGH_ON);
\r
247 text.AttributedCharacterIterator charIter = aS.getIterator();
\r
249 _measurer = new font.TextMeasurer(charIter, _frc);
250 return NextTextLayoutFromMeasurer();
253 internal geom.AffineTransform CalcLineAlignmentTransform() {
254 if (Format.LineAlignment == StringAlignment.Near)
\r
256 float height = WrapHeight;
\r
257 if (float.IsPositiveInfinity(height))
\r
260 float shift = height - AccumulatedHeight;
\r
261 if (height > 0 && shift <= 0)
\r
264 if (Format.LineAlignment == StringAlignment.Center)
\r
267 if (Format.IsVertical && Format.IsRightToLeft)
\r
270 return Format.IsVertical ?
\r
271 geom.AffineTransform.getTranslateInstance(shift, 0) :
\r
272 geom.AffineTransform.getTranslateInstance(0, shift);