void InnerDecorateTabsAndSpaces (Cairo.Context ctx, LayoutWrapper layout, int offset, double x, double y, int selectionStart, int selectionEnd, char spaceOrTab)
{
var chars = layout.LineChars;
if (Array.IndexOf (chars, spaceOrTab) == -1)
return;
uint curIndex = 0, byteIndex = 0;
bool first = true, oldSelected = false;
var curchunk = layout.Chunks != null ? layout.Chunks.FirstOrDefault () : null;
var dotThickness = textEditor.Options.Zoom * 2;
var textEditorWidth = textEditor.Allocation.Width;
//Get 1st visible character index from left based on HAdjustment
int index, trailing;
layout.Layout.XyToIndex ((int)textEditor.HAdjustment.Value, 0, out index, out trailing);
double ypos;
if (spaceOrTab == ' ') {
ypos = System.Math.Floor (y + (LineHeight - dotThickness) / 2);
} else {
ypos = 0.5 + System.Math.Floor (y + LineHeight / 2);
}
var showOnlySelected = textEditor.Options.ShowWhitespaces != ShowWhitespaces.Always;
var lastColor = new Cairo.Color ();
bool firstDraw = true;
var foregroundColor = ColorStyle.PlainText.Foreground;
int lastIndex = -1;
int lastPosX = 0;
for (int i = index; i < chars.Length; i++) {
if (spaceOrTab != chars [i])
continue;
bool selected = selectionStart <= offset + i && offset + i < selectionEnd;
if (first || oldSelected != selected) {
first = false;
oldSelected = selected;
}
if (showOnlySelected && !selected)
continue;
int line, posX;
if (lastIndex == i) {
posX = lastPosX;
} else {
layout.Layout.IndexToLineX ((int)TranslateToUTF8Index (chars, (uint)i, ref curIndex, ref byteIndex), false, out line, out posX);
}
double xpos = x + posX / Pango.Scale.PangoScale;
if (xpos > textEditorWidth)
break;
layout.Layout.IndexToLineX ((int)TranslateToUTF8Index (chars, (uint)i + 1, ref curIndex, ref byteIndex), false, out line, out posX);
lastPosX = posX;
lastIndex = i + 1;
double xpos2 = x + posX / Pango.Scale.PangoScale;
var col = new Cairo.Color (0, 0, 0);
if (SelectionColor.TransparentForeground) {
while (curchunk != null && curchunk.EndOffset < offset + i)
curchunk = curchunk.Next;
if (curchunk != null && curchunk.SpanStack.Count > 0 && curchunk.SpanStack.Peek ().Color != "Plain Text") {
var chunkStyle = ColorStyle.GetChunkStyle (curchunk.SpanStack.Peek ().Color);
if (chunkStyle != null)
col = ColorStyle.GetForeground (chunkStyle);
} else {
col = foregroundColor;
}
} else {
col = selected ? SelectionColor.Foreground : foregroundColor;
}
if (firstDraw || (lastColor.R != col.R && lastColor.G != col.G && lastColor.B != col.B)) {
ctx.SetSourceRGBA (col.R, col.G, col.B, whitespaceMarkerAlpha);
lastColor = col;
firstDraw = false;
}
if (spaceOrTab == ' ') {
ctx.Rectangle (xpos + (xpos2 - xpos - dotThickness) / 2, ypos, dotThickness, dotThickness);
} else {
ctx.MoveTo (0.5 + xpos, ypos);
ctx.LineTo (0.5 + xpos2 - charWidth / 2, ypos);
}
}
if (!firstDraw) {//Atleast one draw was called
if (spaceOrTab == ' ') {
ctx.Fill ();
} else {
ctx.Stroke ();
}
}
}