Skip to content

Commit

Permalink
Merge branch 'feature/new-term-engine' into devel
Browse files Browse the repository at this point in the history
  • Loading branch information
poderosaproject committed Dec 1, 2024
2 parents 6524c0a + b5a38de commit 23866f9
Show file tree
Hide file tree
Showing 8 changed files with 294 additions and 161 deletions.
95 changes: 48 additions & 47 deletions Core/CharacterDocumentViewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class CharacterDocumentViewer : Control, IPoderosaControl, ISelectionList
internal const int TIMER_INTERVAL = 50; //再描画最適化とキャレット処理を行うタイマーの間隔

private CharacterDocument _document;
private int _maxDisplayLines; // restrict lines to display to avoid artifacts
private bool _errorRaisedInDrawing;
private readonly List<GLine> _transientLines; //再描画するGLineを一時的に保管する
private readonly List<GLine> _glinePool;
Expand All @@ -70,6 +71,7 @@ public class CharacterDocumentViewer : Control, IPoderosaControl, ISelectionList
#endif

public CharacterDocumentViewer() {
_maxDisplayLines = Int32.MaxValue;
_enableAutoScrollBarAdjustment = true;
_transientLines = new List<GLine>();
_glinePool = new List<GLine>();
Expand Down Expand Up @@ -134,6 +136,7 @@ public bool EnabledEx {
this.ImeMode = value ? ImeMode.NoControl : ImeMode.Disable;
}
}

public VScrollBar VScrollBar {
get {
return _VScrollBar;
Expand Down Expand Up @@ -304,6 +307,10 @@ protected virtual void VScrollBarValueChanged() {
protected virtual void AdjustCaret(Caret caret) {
}

protected void RestrictDisplayArea(int width, int height) {
_maxDisplayLines = height;
}

//_documentの更新状況を見て適切な領域のControl.Invalidate()を呼ぶ。
//また、コントロールを所有していないスレッドから呼んでもOKなようになっている。
protected void InvalidateEx() {
Expand Down Expand Up @@ -446,11 +453,11 @@ protected override sealed void OnPaint(PaintEventArgs e) {

//描画用にテンポラリのGLineを作り、描画中にdocumentをロックしないようにする
//!!ここは実行頻度が高いのでnewを毎回するのは避けたいところだ
RenderParameter param = new RenderParameter();
RenderParameter param;
_caret.Enabled = _caret.Enabled && this.Focused; //TODO さらにIME起動中はキャレットを表示しないように. TerminalControlだったらAdjustCaretでIMEをみてるので問題はない
lock (_document) {
CommitTransientScrollBar();
BuildTransientDocument(e, param);
BuildTransientDocument(clip, out param);
}

DrawLines(g, param, backColor);
Expand Down Expand Up @@ -482,33 +489,37 @@ protected override sealed void OnPaint(PaintEventArgs e) {
#endif
}

private void BuildTransientDocument(PaintEventArgs e, RenderParameter param) {
Rectangle clip = e.ClipRectangle;
private void BuildTransientDocument(Rectangle clip, out RenderParameter param) {
RenderProfile profile = GetRenderProfile();
_transientLines.Clear();

//Win32.SystemMetrics sm = GEnv.SystemMetrics;
//param.TargetRect = new Rectangle(sm.ControlBorderWidth+1, sm.ControlBorderHeight,
// this.Width - _VScrollBar.Width - sm.ControlBorderWidth + 8, //この8がない値が正当だが、.NETの文字サイズ丸め問題のため行の最終文字が表示されないことがある。これを回避するためにちょっと増やす
// this.Height - sm.ControlBorderHeight);
param.TargetRect = this.ClientRectangle;

int offset1 = (int)Math.Floor((clip.Top - BORDER) / (profile.Pitch.Height + profile.LineSpacing));
if (offset1 < 0)
offset1 = 0;
param.LineFrom = offset1;
int offset2 = (int)Math.Floor((clip.Bottom - BORDER) / (profile.Pitch.Height + profile.LineSpacing));
if (offset2 < 0)
offset2 = 0;
Rectangle targetRect = this.ClientRectangle;

param.LineCount = offset2 - offset1 + 1;
float linePitch = profile.Pitch.Height + profile.LineSpacing;
int lineFrom = (int)Math.Floor(Math.Max(clip.Top - BORDER, 0) / linePitch);
int lineTo = (int)Math.Floor(Math.Max(clip.Bottom - BORDER, 0) / linePitch);
int lineCount;
if (lineFrom >= _maxDisplayLines) {
lineCount = 0;
}
else {
if (lineTo >= _maxDisplayLines) {
lineTo = _maxDisplayLines - 1;
}
lineCount = lineTo - lineFrom + 1;
}

//Debug.WriteLine(String.Format("{0} {1} ", param.LineFrom, param.LineCount));

int topline_id = GetTopLine().ID;
GLine l = _document.FindLineOrNull(topline_id + param.LineFrom);
GLine l = _document.FindLineOrNull(topline_id + lineFrom);
if (l != null) {
int poolIndex = 0;
for (int i = 0; i < param.LineCount; i++) {
for (int i = 0; i < lineCount; i++) {
GLine cloned;
if (poolIndex < _glinePool.Count) {
cloned = _glinePool[poolIndex];
Expand Down Expand Up @@ -541,7 +552,7 @@ private void BuildTransientDocument(PaintEventArgs e, RenderParameter param) {
t = t.NextLine;
int pos = from.Column; //たとえば左端を越えてドラッグしたときの選択範囲は前行末になるので pos==TerminalWidthとなるケースがある。
do {
int index = l.ID - (topline_id + param.LineFrom);
int index = l.ID - (topline_id + lineFrom);
if (pos >= 0 && pos < l.DisplayLength && index >= 0 && index < _transientLines.Count) {
if (l.ID == to.Line) {
if (pos != to.Column) {
Expand All @@ -559,18 +570,24 @@ private void BuildTransientDocument(PaintEventArgs e, RenderParameter param) {
}

AdjustCaret(_caret);
_caret.Enabled = _caret.Enabled && (param.LineFrom <= _caret.Y && _caret.Y < param.LineFrom + param.LineCount);
_caret.Enabled = _caret.Enabled && (lineFrom <= _caret.Y && _caret.Y < lineFrom + lineCount);

//Caret画面外にあるなら処理はしなくてよい。2番目の条件は、Attach-ResizeTerminalの流れの中でこのOnPaintを実行した場合にTerminalHeight>lines.Countになるケースがあるのを防止するため
if (_caret.Enabled) {
//ヒクヒク問題のため、キャレットを表示しないときでもこの操作は省けない
if (_caret.Style == CaretType.Box) {
int y = _caret.Y - param.LineFrom;
int y = _caret.Y - lineFrom;
if (y >= 0 && y < _transientLines.Count) {
_transientLines[y].SetCursor(_caret.X);
}
}
}

param = new RenderParameter(
lineFrom: lineFrom,
lineCount: lineCount,
targetRect: targetRect
);
}

private void DrawLines(Graphics g, RenderParameter param, Color baseBackColor) {
Expand Down Expand Up @@ -796,34 +813,18 @@ public void OnSelectionFixed() {
* 何行目から何行目までを描画すべきかの情報を収録
*/
internal class RenderParameter {
private int _linefrom;
private int _linecount;
private Rectangle _targetRect;

public int LineFrom {
get {
return _linefrom;
}
set {
_linefrom = value;
}
}

public int LineCount {
get {
return _linecount;
}
set {
_linecount = value;
}
}
public Rectangle TargetRect {
get {
return _targetRect;
}
set {
_targetRect = value;
}
public readonly int LineFrom;
public readonly int LineCount;
public readonly Rectangle TargetRect;

public RenderParameter(
int lineFrom,
int lineCount,
Rectangle targetRect
) {
this.LineFrom = lineFrom;
this.LineCount = lineCount;
this.TargetRect = targetRect;
}
}

Expand Down
42 changes: 30 additions & 12 deletions Core/GLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -755,9 +755,6 @@ public LineRenderingType LineRenderingType {
get {
return _lineRenderingType;
}
set {
_lineRenderingType = value;
}
}

/// <summary>
Expand Down Expand Up @@ -988,12 +985,16 @@ private GColor24[] Duplicate24bitColors(GColor24[] reusable) {
/// </summary>
/// <param name="dec">text decoration for specifying the background color, or null for using default attributes.</param>
/// <param name="selective">if true, protected characters are retained.</param>
public void Clear(TextDecoration dec = null, bool selective = false) {
/// <param name="resetLineRenderingType">if true, LineRenderingType is reset to Normal.</param>
public void Clear(TextDecoration dec = null, bool selective = false, bool resetLineRenderingType = true) {
TextDecoration d = dec ?? TextDecoration.Default;
GAttr attr = d.Attr;
GColor24 color = d.Color24;

lock (this) {
if (resetLineRenderingType) {
_lineRenderingType = LineRenderingType.Normal;
}
if (selective) {
FillSelective(0, _cell.Length, GChar.ASCII_NUL, attr, color);
}
Expand Down Expand Up @@ -1149,6 +1150,21 @@ private static byte ToCharTypeForWordBreak(GChar ch) {
// TODO: consider unicode character class
}

/// <summary>
/// Set rendering type
/// </summary>
/// <param name="t">new value</param>
/// <returns>true if rendering type has been changed</returns>
public bool SetLineRenderingType(LineRenderingType t) {
if (_lineRenderingType != t) {
_lineRenderingType = t;
return true;
}
else {
return false;
}
}

/// <summary>
/// Expand internal buffer.
/// </summary>
Expand Down Expand Up @@ -1218,14 +1234,16 @@ internal void Render(IntPtr hdc, RenderProfile prof, Caret caret, Color baseBack

if (IsDoubleWidth) {
pitch *= 2;
}
if (IsDoubleHeight) {
etoCommonOpts += Win32.ETO_CLIPPED;
if (IsLowerHalf) {
textYOffset = -(int)prof.Pitch.Height;
}
else {
underlineFlag = GAttrFlags.None;

// supports only the case where both double-height and double-width are specified.
if (IsDoubleHeight) {
etoCommonOpts += Win32.ETO_CLIPPED;
if (IsLowerHalf) {
textYOffset = -(int)prof.Pitch.Height;
}
else {
underlineFlag = GAttrFlags.None;
}
}
}

Expand Down
15 changes: 11 additions & 4 deletions TerminalEmulator/EscapeSequenceEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,17 @@ public EscapeSequenceEngine(
Action<IEscapeSequenceContext> incompleteHandler,
Action<Exception, IEscapeSequenceContext> exceptionHandler
) {
BuildStateMachine();
_currentState = _root;
_completedHandler = completedHandler;
_incompleteHandler = incompleteHandler;
_exceptionHandler = exceptionHandler;
}

/// <summary>
/// Build global instance of the state machine
/// </summary>
public static void BuildStateMachine() {
lock (_initializeSync) {
if (!_initialized) {
#if DEBUG
Expand All @@ -1327,10 +1338,6 @@ Action<Exception, IEscapeSequenceContext> exceptionHandler
#endif
}
}
_currentState = _root;
_completedHandler = completedHandler;
_incompleteHandler = incompleteHandler;
_exceptionHandler = exceptionHandler;
}

/// <summary>
Expand Down
80 changes: 80 additions & 0 deletions TerminalEmulator/TerminalBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,86 @@ protected void ResetDocumentCursor() {
}
}

/// <summary>
/// Represents the row number; vertical position on the screen, 1-based.
/// </summary>
public struct Row {
public readonly int Value;

public Row(int v) {
Value = v;
}

public Row Clamp(int min, int max) {
return new Row(Math.Min(Math.Max(Value, min), max));
}

public Row ClipLower(int min) {
return new Row(Math.Max(Value, min));
}

public Row ClipUpper(int max) {
return new Row(Math.Min(Value, max));
}

public string ToInvariantString() {
return Value.ToInvariantString();
}

public static Row operator +(Row r, int n) {
return new Row(r.Value + n);
}

public static Row operator -(Row r, int n) {
return new Row(r.Value - n);
}
}

/// <summary>
/// Represents the column number; horizontal position on the screen, 1-based.
/// </summary>
public struct Col {
public readonly int Value;

public Col(int v) {
Value = v;
}

public Col Clamp(int min, int max) {
return new Col(Math.Min(Math.Max(Value, min), max));
}

public Col ClipLower(int min) {
return new Col(Math.Max(Value, min));
}

public Col ClipUpper(int max) {
return new Col(Math.Min(Value, max));
}

public string ToInvariantString() {
return Value.ToInvariantString();
}

public static Col operator +(Col r, int n) {
return new Col(r.Value + n);
}

public static Col operator -(Col r, int n) {
return new Col(r.Value - n);
}
}

public static class RowColMixin {
public static Row AsRow(this int v) {
return new Row(v);
}

public static Col AsCol(this int v) {
return new Col(v);
}
}

internal static class ControlCode {
public const char NUL = '\u0000';
public const char ENQ = '\u0005';
Expand Down
5 changes: 5 additions & 0 deletions TerminalEmulator/TerminalControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,11 @@ public void SplitterDragging(int width, int height) {
private void ResizeTerminal(int width, int height) {
//Debug.WriteLine(String.Format("Resize {0} {1}", width, height));

// In the terminal display, the rendered area should be restricted to
// the screen size, since the remote application only updates within
// the notified screen size.
RestrictDisplayArea(width, height);

//Documentへ通知
GetDocument().Resize(width, height);

Expand Down
Loading

0 comments on commit 23866f9

Please sign in to comment.