aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gtk/PlatGTK.cxx22
-rw-r--r--include/Platform.h1
-rw-r--r--include/Scintilla.h2
-rw-r--r--include/Scintilla.iface7
-rw-r--r--src/Editor.cxx161
-rw-r--r--src/Editor.h5
6 files changed, 160 insertions, 38 deletions
diff --git a/gtk/PlatGTK.cxx b/gtk/PlatGTK.cxx
index 7088a5f7e..9724c38bb 100644
--- a/gtk/PlatGTK.cxx
+++ b/gtk/PlatGTK.cxx
@@ -601,8 +601,10 @@ public:
void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back);
void Copy(PRectangle rc, Point from, Surface &surfaceSource);
+ void DrawTextBase(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore);
void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);
void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);
+ void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore);
void MeasureWidths(Font &font_, const char *s, int len, int *positions);
int WidthText(Font &font_, const char *s, int len);
int WidthChar(Font &font_, char ch);
@@ -821,9 +823,8 @@ void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
#define MAX_US_LEN 5000
-void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len,
- ColourAllocated fore, ColourAllocated back) {
- FillRectangle(rc, back);
+void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, int ybase, const char *s, int len,
+ ColourAllocated fore) {
PenColour(fore);
if (gc && drawable) {
// Draw text as a series of segments to avoid limitations in X servers
@@ -896,10 +897,23 @@ void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const ch
}
}
+void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len,
+ ColourAllocated fore, ColourAllocated back) {
+ FillRectangle(rc, back);
+ DrawTextBase(rc, font_, ybase, s, len, fore);
+}
+
// On GTK+, exactly same as DrawTextNoClip
void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len,
ColourAllocated fore, ColourAllocated back) {
- DrawTextNoClip(rc, font_, ybase, s, len, fore, back);
+ FillRectangle(rc, back);
+ DrawTextBase(rc, font_, ybase, s, len, fore);
+}
+
+// On GTK+, exactly same as DrawTextNoClip
+void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len,
+ ColourAllocated fore) {
+ DrawTextBase(rc, font_, ybase, s, len, fore);
}
void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) {
diff --git a/include/Platform.h b/include/Platform.h
index b19cdce8d..bb429729e 100644
--- a/include/Platform.h
+++ b/include/Platform.h
@@ -314,6 +314,7 @@ public:
virtual void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back)=0;
virtual void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back)=0;
+ virtual void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore)=0;
virtual void MeasureWidths(Font &font_, const char *s, int len, int *positions)=0;
virtual int WidthText(Font &font_, const char *s, int len)=0;
virtual int WidthChar(Font &font_, char ch)=0;
diff --git a/include/Scintilla.h b/include/Scintilla.h
index 8df32be4c..386271bbe 100644
--- a/include/Scintilla.h
+++ b/include/Scintilla.h
@@ -395,6 +395,8 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
#define SCI_SETVSCROLLBAR 2280
#define SCI_GETVSCROLLBAR 2281
#define SCI_APPENDTEXT 2282
+#define SCI_GETTWOPHASEDRAW 2283
+#define SCI_SETTWOPHASEDRAW 2284
#define SCI_LINEDOWN 2300
#define SCI_LINEDOWNEXTEND 2301
#define SCI_LINEUP 2302
diff --git a/include/Scintilla.iface b/include/Scintilla.iface
index bade44fd2..dd4d2d37e 100644
--- a/include/Scintilla.iface
+++ b/include/Scintilla.iface
@@ -1022,6 +1022,13 @@ get bool GetVScrollBar=2281(,)
# Append a string to the end of the document without changing the selection.
fun void AppendText=2282(int length, string text)
+# Is drawing done in two phases with backgrounds drawn before faoregrounds?
+get bool GetTwoPhaseDraw=2283(,)
+
+# In twoPhaseDraw mode, drawing is performed in two phases, first the background
+# and then the foreground. This avoids chopping off characters that overlap the next run.
+set void SetTwoPhaseDraw=2284(bool twoPhase,)
+
## New messages go here
## Start of key messages
diff --git a/src/Editor.cxx b/src/Editor.cxx
index 8ac091e8d..0c540d513 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -297,6 +297,7 @@ Editor::Editor() {
mouseDownCaptures = true;
bufferedDraw = true;
+ twoPhaseDraw = true;
lastClickTime = 0;
dwellDelay = SC_TIME_FOREVER;
@@ -1764,6 +1765,34 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou
}
}
+ColourAllocated Editor::TextBackground(ViewStyle &vsDraw, bool overrideBackground,
+ ColourAllocated background, bool inSelection, int styleMain, int i, LineLayout *ll) {
+ if (inSelection) {
+ if (vsDraw.selbackset) {
+ if (primarySelection)
+ return vsDraw.selbackground.allocated;
+ else
+ return vsDraw.selbackground2.allocated;
+ }
+ } else {
+ if ((vsDraw.edgeState == EDGE_BACKGROUND) &&
+ (i >= ll->edgeColumn) &&
+ (ll->chars[i] != '\n') &&
+ (ll->chars[i] != '\r'))
+ return vsDraw.edgecolour.allocated;
+ if (overrideBackground)
+ return background;
+ }
+ return vsDraw.styles[styleMain].back.allocated;
+}
+
+void Editor::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) {
+ Point from(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0);
+ PRectangle rcCopyArea(start + 1, rcSegment.top, start + 2, rcSegment.bottom);
+ surface->Copy(rcCopyArea, from,
+ highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide);
+}
+
void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart,
PRectangle rcLine, LineLayout *ll, int subLine) {
@@ -1810,6 +1839,9 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
}
}
+ bool drawWhitespaceBackground = (vsDraw.viewWhitespace != wsInvisible) &&
+ (!overrideBackground) && (vsDraw.whitespaceBackgroundSet);
+
bool inIndentation = subLine == 0; // Do not handle indentation except on first subline.
int indentWidth = pdoc->indentInChars * vsDraw.spaceWidth;
if (indentWidth == 0)
@@ -1818,7 +1850,6 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
int posLineStart = pdoc->LineStart(line);
int posLineEnd = pdoc->LineStart(line + 1);
- int styleMask = pdoc->stylingBitsMask;
int startseg = ll->LineStart(subLine);
int subLineStart = ll->positions[startseg];
int lineStart = 0;
@@ -1827,7 +1858,63 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
lineStart = ll->LineStart(subLine);
lineEnd = ll->LineStart(subLine+1);
}
- for (int i = lineStart; i < lineEnd; i++) {
+ int i;
+
+ // Background drawing loop
+ for (i = lineStart; twoPhaseDraw && (i < lineEnd); i++) {
+
+ int iDoc = i + posLineStart;
+ // If there is the end of a style run for any reason
+ if ((ll->styles[i] != ll->styles[i + 1]) ||
+ i == (lineEnd-1) ||
+ IsControlCharacter(ll->chars[i]) || IsControlCharacter(ll->chars[i + 1]) ||
+ ((ll->selStart != ll->selEnd) && ((iDoc + 1 == ll->selStart) || (iDoc + 1 == ll->selEnd))) ||
+ (i == (ll->edgeColumn - 1))) {
+ rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
+ rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
+ // Only try to draw if really visible - enhances performance by not calling environment to
+ // draw strings that are completely past the right side of the window.
+ if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
+ int styleMain = ll->styles[i];
+ bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
+ ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, styleMain, i, ll);
+ if (ll->chars[i] == '\t') {
+ // Tab display
+ if (drawWhitespaceBackground &&
+ (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
+ textBack = vsDraw.whitespaceBackground.allocated;
+ surface->FillRectangle(rcSegment, textBack);
+ } else if (IsControlCharacter(ll->chars[i])) {
+ // Control character display
+ inIndentation = false;
+ surface->FillRectangle(rcSegment, textBack);
+ } else {
+ // Normal text display
+ surface->FillRectangle(rcSegment, textBack);
+ if (vsDraw.viewWhitespace != wsInvisible ||
+ (inIndentation && vsDraw.viewIndentationGuides)) {
+ for (int cpos = 0; cpos <= i - startseg; cpos++) {
+ if (ll->chars[cpos + startseg] == ' ') {
+ if (drawWhitespaceBackground &&
+ (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
+ PRectangle rcSpace(ll->positions[cpos + startseg] + xStart, rcSegment.top,
+ ll->positions[cpos + startseg + 1] + xStart, rcSegment.bottom);
+ surface->FillRectangle(rcSpace, vsDraw.whitespaceBackground.allocated);
+ }
+ } else {
+ inIndentation = false;
+ }
+ }
+ }
+ }
+ }
+ startseg = i + 1;
+ }
+ }
+ inIndentation = subLine == 0; // Do not handle indentation except on first subline.
+ startseg = ll->LineStart(subLine);
+ // Foreground drawing loop
+ for (i = lineStart; i < lineEnd; i++) {
int iDoc = i + posLineStart;
// If there is the end of a style run for any reason
@@ -1842,30 +1929,21 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
// draw strings that are completely past the right side of the window.
if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
int styleMain = ll->styles[i];
- ColourAllocated textBack = vsDraw.styles[styleMain].back.allocated;
ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated;
Font &textFont = vsDraw.styles[styleMain].font;
bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
- if (inSelection) {
- if (vsDraw.selbackset) {
- if (primarySelection)
- textBack = vsDraw.selbackground.allocated;
- else
- textBack = vsDraw.selbackground2.allocated;
- }
- if (vsDraw.selforeset)
- textFore = vsDraw.selforeground.allocated;
- } else {
- if (overrideBackground)
- textBack = background;
- if ((vsDraw.edgeState == EDGE_BACKGROUND) && (i >= ll->edgeColumn) && (ll->chars[i] != '\n') && (ll->chars[i] != '\r'))
- textBack = vsDraw.edgecolour.allocated;
+ if (inSelection && (vsDraw.selforeset)) {
+ textFore = vsDraw.selforeground.allocated;
}
+ ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, styleMain, i, ll);
if (ll->chars[i] == '\t') {
- // Manage tab display
- if (!overrideBackground && vsDraw.whitespaceBackgroundSet && (vsDraw.viewWhitespace != wsInvisible) && (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
- textBack = vsDraw.whitespaceBackground.allocated;
- surface->FillRectangle(rcSegment, textBack);
+ // Tab display
+ if (!twoPhaseDraw) {
+ if (drawWhitespaceBackground &&
+ (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
+ textBack = vsDraw.whitespaceBackground.allocated;
+ surface->FillRectangle(rcSegment, textBack);
+ }
if ((vsDraw.viewWhitespace != wsInvisible) || ((inIndentation && vsDraw.viewIndentationGuides))) {
if (vsDraw.whitespaceForegroundSet)
textFore = vsDraw.whitespaceForeground.allocated;
@@ -1874,10 +1952,8 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
if (inIndentation && vsDraw.viewIndentationGuides) {
for (int xIG = ll->positions[i] / indentWidth * indentWidth; xIG < ll->positions[i + 1]; xIG += indentWidth) {
if (xIG >= ll->positions[i] && xIG > 0) {
- Point from(0, ((lineVisible & 1) && (vsDraw.lineHeight & 1)) ? 1 : 0);
- PRectangle rcCopyArea(xIG + xStart + 1, rcSegment.top, xIG + xStart + 2, rcSegment.bottom);
- surface->Copy(rcCopyArea, from, (ll->xHighlightGuide == xIG) ?
- *pixmapIndentGuideHighlight : *pixmapIndentGuide);
+ DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIG + xStart, rcSegment,
+ (ll->xHighlightGuide == xIG));
}
}
}
@@ -1889,12 +1965,14 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
}
}
} else if (IsControlCharacter(ll->chars[i])) {
- // Manage control character display
+ // Control character display
inIndentation = false;
if (controlCharSymbol < 32) {
// Draw the character
const char *ctrlChar = ControlCharacterString(ll->chars[i]);
- surface->FillRectangle(rcSegment, textBack);
+ if (!twoPhaseDraw) {
+ surface->FillRectangle(rcSegment, textBack);
+ }
int normalCharHeight = surface->Ascent(ctrlCharsFont) -
surface->InternalLeading(ctrlCharsFont);
PRectangle rcCChar = rcSegment;
@@ -1918,10 +1996,16 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
cc, 1, textBack, textFore);
}
} else {
- // Manage normal display
- surface->DrawTextNoClip(rcSegment, textFont,
+ // Normal text display
+ if (twoPhaseDraw) {
+ surface->DrawTextTransparent(rcSegment, textFont,
+ rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
+ i - startseg + 1, textFore);
+ } else {
+ surface->DrawTextNoClip(rcSegment, textFont,
rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
i - startseg + 1, textFore, textBack);
+ }
if (vsDraw.viewWhitespace != wsInvisible ||
(inIndentation && vsDraw.viewIndentationGuides)) {
for (int cpos = 0; cpos <= i - startseg; cpos++) {
@@ -1931,7 +2015,8 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
textFore = vsDraw.whitespaceForeground.allocated;
if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
int xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2;
- if (!overrideBackground && vsDraw.whitespaceBackgroundSet) {
+ if (!twoPhaseDraw && drawWhitespaceBackground &&
+ (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
textBack = vsDraw.whitespaceBackground.allocated;
PRectangle rcSpace(ll->positions[cpos + startseg] + xStart, rcSegment.top, ll->positions[cpos + startseg + 1] + xStart, rcSegment.bottom);
surface->FillRectangle(rcSpace, textBack);
@@ -1945,10 +2030,8 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
if (inIndentation && vsDraw.viewIndentationGuides) {
int startSpace = ll->positions[cpos + startseg];
if (startSpace > 0 && (startSpace % indentWidth == 0)) {
- Point from(0, ((lineVisible & 1) && (vsDraw.lineHeight & 1)) ? 1 : 0);
- PRectangle rcCopyArea(startSpace + xStart + 1, rcSegment.top, startSpace + xStart + 2, rcSegment.bottom);
- surface->Copy(rcCopyArea, from, (ll->xHighlightGuide == ll->positions[cpos + startseg]) ?
- *pixmapIndentGuideHighlight : *pixmapIndentGuide);
+ DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, startSpace + xStart, rcSegment,
+ (ll->xHighlightGuide == ll->positions[cpos + startseg]));
}
}
} else {
@@ -1994,6 +2077,8 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
}
// End of the drawing of the current line
+ int styleMask = pdoc->stylingBitsMask;
+
// Fill in a PRectangle representing the end of line characters
int xEol = ll->positions[lineEnd] - subLineStart;
rcSegment.left = xEol + xStart;
@@ -5114,6 +5199,14 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
case SCI_GETBUFFEREDDRAW:
return bufferedDraw;
+ case SCI_GETTWOPHASEDRAW:
+ return twoPhaseDraw;
+
+ case SCI_SETTWOPHASEDRAW:
+ twoPhaseDraw = wParam != 0;
+ InvalidateStyleRedraw();
+ break;
+
case SCI_SETTABWIDTH:
if (wParam > 0)
pdoc->tabInChars = wParam;
diff --git a/src/Editor.h b/src/Editor.h
index 5517065b6..ed5cc6612 100644
--- a/src/Editor.h
+++ b/src/Editor.h
@@ -199,6 +199,9 @@ protected: // ScintillaBase subclass needs access to much of Editor
/** In bufferedDraw mode, graphics operations are drawn to a pixmap and then copied to
* the screen. This avoids flashing but is about 30% slower. */
bool bufferedDraw;
+ /** In twoPhaseDraw mode, drawing is performed in two phases, first the background
+ * and then the foreground. This avoids chopping off characters that overlap the next run. */
+ bool twoPhaseDraw;
int xOffset; ///< Horizontal scrolled amount in pixels
int xCaretMargin; ///< Ensure this many pixels visible on both sides of caret
@@ -348,6 +351,8 @@ protected: // ScintillaBase subclass needs access to much of Editor
LineLayout *RetrieveLineLayout(int lineNumber);
void LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout *ll,
int width=LineLayout::wrapWidthInfinite);
+ ColourAllocated TextBackground(ViewStyle &vsDraw, bool overrideBackground, ColourAllocated background, bool inSelection, int styleMain, int i, LineLayout *ll);
+ void DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight);
void DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart,
PRectangle rcLine, LineLayout *ll, int subLine=0);
void Paint(Surface *surfaceWindow, PRectangle rcArea);