public LayoutWrapper CreateLinePartLayout (ISyntaxMode mode, DocumentLine line, int logicalRulerColumn, int offset, int length, int selectionStart, int selectionEnd) { bool containsPreedit = textEditor.ContainsPreedit (offset, length); LayoutDescriptor descriptor; if (!containsPreedit && layoutDict.TryGetValue (line, out descriptor)) { bool isInvalid; if (descriptor.Equals (line, offset, length, selectionStart, selectionEnd, out isInvalid) && descriptor.Layout != null) { return descriptor.Layout; } descriptor.Dispose (); layoutDict.Remove (line); } var wrapper = new LayoutWrapper (PangoUtil.CreateLayout (textEditor)); wrapper.IsUncached = containsPreedit; if (logicalRulerColumn < 0) logicalRulerColumn = line.GetLogicalColumn (textEditor.GetTextEditorData (), textEditor.Options.RulerColumn); var atts = new FastPangoAttrList (); wrapper.Layout.Alignment = Pango.Alignment.Left; wrapper.Layout.FontDescription = textEditor.Options.Font; wrapper.Layout.Tabs = tabArray; if (textEditor.Options.WrapLines) { wrapper.Layout.Wrap = Pango.WrapMode.WordChar; wrapper.Layout.Width = (int)((textEditor.Allocation.Width - XOffset - TextStartPosition) * Pango.Scale.PangoScale); } StringBuilder textBuilder = new StringBuilder (); var chunks = GetCachedChunks (mode, Document, textEditor.ColorStyle, line, offset, length); wrapper.Chunks = chunks; foreach (var chunk in chunks) { try { textBuilder.Append (Document.GetTextAt (chunk)); } catch { Console.WriteLine (chunk); } } int lineOffset = line.Offset; string lineText = textBuilder.ToString (); uint preeditLength = 0; if (containsPreedit) { if (textEditor.GetTextEditorData ().IsCaretInVirtualLocation) { lineText = textEditor.GetTextEditorData ().GetIndentationString (textEditor.Caret.Location) + textEditor.preeditString; } else { lineText = lineText.Insert (textEditor.preeditOffset - offset, textEditor.preeditString); } preeditLength = (uint)textEditor.preeditString.Length; } char[] lineChars = lineText.ToCharArray (); //int startOffset = offset, endOffset = offset + length; uint curIndex = 0, byteIndex = 0; uint curChunkIndex = 0, byteChunkIndex = 0; uint oldEndIndex = 0; foreach (Chunk chunk in chunks) { ChunkStyle chunkStyle = chunk != null ? textEditor.ColorStyle.GetChunkStyle (chunk) : null; foreach (TextLineMarker marker in line.Markers) chunkStyle = marker.GetStyle (chunkStyle); if (chunkStyle != null) { //startOffset = chunk.Offset; //endOffset = chunk.EndOffset; uint startIndex = (uint)(oldEndIndex); uint endIndex = (uint)(startIndex + chunk.Length); oldEndIndex = endIndex; var markers = Document.GetTextSegmentMarkersAt (line).Where (m => m.IsVisible).ToArray (); HandleSelection (lineOffset, logicalRulerColumn, selectionStart, selectionEnd, chunk.Offset, chunk.EndOffset, delegate(int start, int end) { if (containsPreedit) { if (textEditor.preeditOffset < start) start += (int)preeditLength; if (textEditor.preeditOffset < end) end += (int)preeditLength; } var si = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex); var ei = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex); var color = ColorStyle.GetForeground (chunkStyle); foreach (var marker in markers) { var chunkMarker = marker as IChunkMarker; if (chunkMarker == null) continue; chunkMarker.ChangeForeColor (textEditor, chunk, ref color); } atts.AddForegroundAttribute ((HslColor)color, si, ei); if (!chunkStyle.TransparentBackground && GetPixel (ColorStyle.PlainText.Background) != GetPixel (chunkStyle.Background)) { wrapper.AddBackground (chunkStyle.Background, (int)si, (int)ei); } else if (chunk.SpanStack != null && ColorStyle != null) { foreach (var span in chunk.SpanStack) { if (span == null || string.IsNullOrEmpty (span.Color)) continue; var spanStyle = ColorStyle.GetChunkStyle (span.Color); if (spanStyle != null && !spanStyle.TransparentBackground && GetPixel (ColorStyle.PlainText.Background) != GetPixel (spanStyle.Background)) { wrapper.AddBackground (spanStyle.Background, (int)si, (int)ei); break; } } } }, delegate(int start, int end) { if (containsPreedit) { if (textEditor.preeditOffset < start) start += (int)preeditLength; if (textEditor.preeditOffset < end) end += (int)preeditLength; } var si = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex); var ei = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex); var color = !SelectionColor.TransparentForeground ? SelectionColor.Foreground : ColorStyle.GetForeground (chunkStyle); foreach (var marker in markers) { var chunkMarker = marker as IChunkMarker; if (chunkMarker == null) continue; chunkMarker.ChangeForeColor (textEditor, chunk, ref color); } atts.AddForegroundAttribute ((HslColor)color, si, ei); if (!wrapper.StartSet) wrapper.SelectionStartIndex = (int)si; wrapper.SelectionEndIndex = (int)ei; }); var translatedStartIndex = TranslateToUTF8Index (lineChars, (uint)startIndex, ref curChunkIndex, ref byteChunkIndex); var translatedEndIndex = TranslateToUTF8Index (lineChars, (uint)endIndex, ref curChunkIndex, ref byteChunkIndex); if (chunkStyle.FontWeight != Xwt.Drawing.FontWeight.Normal) atts.AddWeightAttribute ((Pango.Weight)chunkStyle.FontWeight, translatedStartIndex, translatedEndIndex); if (chunkStyle.FontStyle != Xwt.Drawing.FontStyle.Normal) atts.AddStyleAttribute ((Pango.Style)chunkStyle.FontStyle, translatedStartIndex, translatedEndIndex); if (chunkStyle.Underline) atts.AddUnderlineAttribute (Pango.Underline.Single, translatedStartIndex, translatedEndIndex); } } if (containsPreedit) { var si = TranslateToUTF8Index (lineChars, (uint)(textEditor.preeditOffset - offset), ref curIndex, ref byteIndex); var ei = TranslateToUTF8Index (lineChars, (uint)(textEditor.preeditOffset - offset + preeditLength), ref curIndex, ref byteIndex); if (textEditor.GetTextEditorData ().IsCaretInVirtualLocation) { uint len = (uint)textEditor.GetTextEditorData ().GetIndentationString (textEditor.Caret.Location).Length; si += len; ei += len; } atts.AddForegroundAttribute ((HslColor)ColorStyle.PlainText.Foreground, si, ei); var hasBackground = wrapper.BackgroundColors.Any (bg => bg.FromIdx <= si && bg.ToIdx >= ei); if (hasBackground) atts.AddBackgroundAttribute ((HslColor)ColorStyle.PlainText.Background, si, ei); atts.InsertOffsetList (textEditor.preeditAttrs, si, ei); } wrapper.LineChars = lineChars; wrapper.Layout.SetText (lineText); wrapper.IndentSize = 0; for (int i = 0; i < lineChars.Length; i++) { char ch = lineChars [i]; if (ch == ' ') { wrapper.IndentSize ++; } else if (ch == '\t') { wrapper.IndentSize = GetNextTabstop (textEditor.GetTextEditorData (), wrapper.IndentSize); } else { break; } } var nextLine = line.NextLine; wrapper.EolSpanStack = nextLine != null ? nextLine.StartSpan : null; atts.AssignTo (wrapper.Layout); atts.Dispose (); int w, h; wrapper.Layout.GetSize (out w, out h); wrapper.PangoWidth = w; selectionStart = System.Math.Max (line.Offset - 1, selectionStart); selectionEnd = System.Math.Min (line.EndOffsetIncludingDelimiter + 1, selectionEnd); descriptor = new LayoutDescriptor (line, offset, length, wrapper, selectionStart, selectionEnd); if (!containsPreedit) layoutDict [line] = descriptor; //textEditor.GetTextEditorData ().HeightTree.SetLineHeight (line.LineNumber, System.Math.Max (LineHeight, System.Math.Floor (h / Pango.Scale.PangoScale))); return wrapper; }
public LayoutWrapper CreateLinePartLayout (ISyntaxMode mode, LineSegment line, int logicalRulerColumn, int offset, int length, int selectionStart, int selectionEnd) { bool containsPreedit = textEditor.ContainsPreedit (offset, length); LayoutDescriptor descriptor; if (!containsPreedit && layoutDict.TryGetValue (line, out descriptor)) { bool isInvalid; if (descriptor.Equals (line, offset, length, selectionStart, selectionEnd, out isInvalid) && descriptor.Layout != null) { return descriptor.Layout; } descriptor.Dispose (); layoutDict.Remove (line); } var wrapper = new LayoutWrapper (PangoUtil.CreateLayout (textEditor)); wrapper.IsUncached = containsPreedit; if (logicalRulerColumn < 0) logicalRulerColumn = line.GetLogicalColumn (textEditor.GetTextEditorData (), textEditor.Options.RulerColumn); var atts = new FastPangoAttrList (); wrapper.Layout.Alignment = Pango.Alignment.Left; wrapper.Layout.FontDescription = textEditor.Options.Font; wrapper.Layout.Tabs = tabArray; StringBuilder textBuilder = new StringBuilder (); var chunks = GetCachedChunks (mode, Document, textEditor.ColorStyle, line, offset, length); foreach (var chunk in chunks) { try { textBuilder.Append (Document.GetTextAt (chunk)); } catch { Console.WriteLine (chunk); } } var spanStack = line.StartSpan; int lineOffset = line.Offset; string lineText = textBuilder.ToString (); uint preeditLength = 0; if (containsPreedit) { lineText = lineText.Insert (textEditor.preeditOffset - offset, textEditor.preeditString); preeditLength = (uint)textEditor.preeditString.Length; } char[] lineChars = lineText.ToCharArray (); //int startOffset = offset, endOffset = offset + length; uint curIndex = 0, byteIndex = 0; uint curChunkIndex = 0, byteChunkIndex = 0; uint oldEndIndex = 0; foreach (Chunk chunk in chunks) { ChunkStyle chunkStyle = chunk != null ? textEditor.ColorStyle.GetChunkStyle (chunk) : null; spanStack = chunk.SpanStack ?? spanStack; foreach (TextMarker marker in line.Markers) chunkStyle = marker.GetStyle (chunkStyle); if (chunkStyle != null) { //startOffset = chunk.Offset; //endOffset = chunk.EndOffset; uint startIndex = (uint)(oldEndIndex); uint endIndex = (uint)(startIndex + chunk.Length); oldEndIndex = endIndex; HandleSelection (lineOffset, logicalRulerColumn, selectionStart, selectionEnd, chunk.Offset, chunk.EndOffset, delegate(int start, int end) { if (containsPreedit) { if (textEditor.preeditOffset < start) start += (int)preeditLength; if (textEditor.preeditOffset < end) end += (int)preeditLength; } var si = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex); var ei = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex); atts.AddForegroundAttribute (chunkStyle.Color, si, ei); if (!chunkStyle.TransparentBackround && GetPixel (ColorStyle.Default.BackgroundColor) != GetPixel (chunkStyle.BackgroundColor)) { wrapper.AddBackground (chunkStyle.CairoBackgroundColor, (int)si, (int)ei); } else if (chunk.SpanStack != null && ColorStyle != null) { foreach (var span in chunk.SpanStack) { if (span == null) continue; var spanStyle = ColorStyle.GetChunkStyle (span.Color); if (!spanStyle.TransparentBackround && GetPixel (ColorStyle.Default.BackgroundColor) != GetPixel (spanStyle.BackgroundColor)) { wrapper.AddBackground (spanStyle.CairoBackgroundColor, (int)si, (int)ei); break; } } } }, delegate(int start, int end) { if (containsPreedit) { if (textEditor.preeditOffset < start) start += (int)preeditLength; if (textEditor.preeditOffset < end) end += (int)preeditLength; } var si = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex); var ei = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex); atts.AddForegroundAttribute (SelectionColor.Color, si, ei); if (!wrapper.StartSet) wrapper.SelectionStartIndex = (int)si; wrapper.SelectionEndIndex = (int)ei; }); var translatedStartIndex = TranslateToUTF8Index (lineChars, (uint)startIndex, ref curChunkIndex, ref byteChunkIndex); var translatedEndIndex = TranslateToUTF8Index (lineChars, (uint)endIndex, ref curChunkIndex, ref byteChunkIndex); if (chunkStyle.Bold) atts.AddWeightAttribute (Pango.Weight.Bold, translatedStartIndex, translatedEndIndex); if (chunkStyle.Italic) atts.AddStyleAttribute (Pango.Style.Italic, translatedStartIndex, translatedEndIndex); if (chunkStyle.Underline) atts.AddUnderlineAttribute (Pango.Underline.Single, translatedStartIndex, translatedEndIndex); } } if (containsPreedit) { var si = TranslateToUTF8Index (lineChars, (uint)(textEditor.preeditOffset - offset), ref curIndex, ref byteIndex); var ei = TranslateToUTF8Index (lineChars, (uint)(textEditor.preeditOffset - offset + preeditLength), ref curIndex, ref byteIndex); atts.Splice (textEditor.preeditAttrs, (int)si, (int)(ei - si)); } wrapper.LineChars = lineChars; wrapper.Layout.SetText (lineText); wrapper.EolSpanStack = spanStack; atts.AssignTo (wrapper.Layout); atts.Dispose (); int w, h; wrapper.Layout.GetSize (out w, out h); wrapper.PangoWidth = w; selectionStart = System.Math.Max (line.Offset - 1, selectionStart); selectionEnd = System.Math.Min (line.EndOffsetIncludingDelimiter + 1, selectionEnd); descriptor = new LayoutDescriptor (line, offset, length, wrapper, selectionStart, selectionEnd); if (!containsPreedit) layoutDict[line] = descriptor; return wrapper; }