* @param endOffset exclusive end index of the drawing range
* @param lineOffset inclusive start index of the line
* @param lineEndOffset exclusive end index of the line
*/
private void drawCharRange(GC gc, int startOffset, int endOffset, int lineOffset, int lineEndOffset) {
StyledTextContent content= fTextWidget.getContent();
String lineText= content.getTextRange(lineOffset, lineEndOffset - lineOffset);
int startOffsetInLine= startOffset - lineOffset;
int endOffsetInLine= endOffset - lineOffset;
int textBegin= -1;
for (int i= 0; i < lineText.length(); ++i) {
if (!isWhitespaceCharacter(lineText.charAt(i))) {
textBegin= i;
break;
}
}
boolean isEmptyLine= textBegin == -1;
int textEnd= lineText.length() - 1;
if (!isEmptyLine) {
for (int i= lineText.length() - 1; i >= 0; --i) {
if (!isWhitespaceCharacter(lineText.charAt(i))) {
textEnd= i;
break;
}
}
}
StyleRange styleRange= null;
Color fg= null;
StringBuffer visibleChar= new StringBuffer(10);
for (int textOffset= startOffsetInLine; textOffset <= endOffsetInLine; ++textOffset) {
int delta= 0;
boolean eol= false;
if (textOffset < endOffsetInLine) {
delta= 1;
char c= lineText.charAt(textOffset);
switch (c) {
case ' ':
if (isEmptyLine) {
if (fShowLeadingSpaces || fShowEnclosedSpace || fShowTrailingSpaces) {
visibleChar.append(SPACE_SIGN);
}
} else if (textOffset < textBegin) {
if (fShowLeadingSpaces) {
visibleChar.append(SPACE_SIGN);
}
} else if (textOffset < textEnd) {
if (fShowEnclosedSpace) {
visibleChar.append(SPACE_SIGN);
}
} else {
if (fShowTrailingSpaces) {
visibleChar.append(SPACE_SIGN);
}
}
// 'continue' would improve performance but may produce drawing errors
// for long runs of space if width of space and dot differ
break;
case '\u3000': // ideographic whitespace
if (isEmptyLine) {
if (fShowLeadingIdeographicSpaces || fShowEnclosedIdeographicSpaces || fShowTrailingIdeographicSpaces) {
visibleChar.append(IDEOGRAPHIC_SPACE_SIGN);
}
} else if (textOffset < textBegin) {
if (fShowLeadingIdeographicSpaces) {
visibleChar.append(IDEOGRAPHIC_SPACE_SIGN);
}
} else if (textOffset < textEnd) {
if (fShowEnclosedIdeographicSpaces) {
visibleChar.append(IDEOGRAPHIC_SPACE_SIGN);
}
} else {
if (fShowTrailingIdeographicSpaces) {
visibleChar.append(IDEOGRAPHIC_SPACE_SIGN);
}
}
// 'continue' would improve performance but may produce drawing errors
// for long runs of space if width of space and dot differ
break;
case '\t':
if (isEmptyLine) {
if (fShowLeadingTabs || fShowEnclosedTabs || fShowTrailingTabs) {
visibleChar.append(TAB_SIGN);
}
} else if (textOffset < textBegin) {
if (fShowLeadingTabs) {
visibleChar.append(TAB_SIGN);
}
} else if (textOffset < textEnd) {
if (fShowEnclosedTabs) {
visibleChar.append(TAB_SIGN);
}
} else {
if (fShowTrailingTabs) {
visibleChar.append(TAB_SIGN);
}
}
break;
case '\r':
if (fShowCarriageReturn) {
visibleChar.append(CARRIAGE_RETURN_SIGN);
}
if (textOffset >= endOffsetInLine - 1 || lineText.charAt(textOffset + 1) != '\n') {
eol= true;
break;
}
continue;
case '\n':
if (fShowLineFeed) {
visibleChar.append(LINE_FEED_SIGN);
}
eol= true;
break;
default:
delta= 0;
break;
}
}
if (visibleChar.length() > 0) {
int widgetOffset= startOffset + textOffset - startOffsetInLine - visibleChar.length() + delta;
if (!eol || !isFoldedLine(content.getLineAtOffset(widgetOffset))) {
/*
* Block selection is drawn using alpha and no selection-inverting
* takes place, we always draw as 'unselected' in block selection mode.
*/
if (!fTextWidget.getBlockSelection() && fIsFullSelectionStyle && isOffsetSelected(fTextWidget, widgetOffset)) {