There have been a few reports of Scintilla failing to display long
lines of text on Windows. There was a "Files opening blank?" thread
about this on the SciTE mailing list in August. Finally I saw this and
so was able to track it down and try to fix it. The problem appears to
be based on the size in pixels of the text with larger fonts
disappearing with fewer characters. Helpfully the ExtTextOut call
always returned false for me when it fails so that can be a signal to
choose a different method.
At the largest size tried, displaying 1500 characters at a time
always worked, so allowing for users that choose larger fonts or have
a lot of 'W's in their text, displaying in segments of 512 characters
should be reasonably safe. The problem in displaying multiple segments
is working out where to break the text. For double byte character sets
used for Japanese, Chinese, and Korean, fixed length segments will
often break in the middle of a character leading to results like the
second line of
http://scintilla.sourceforge.net/Chinese8.png
Even with Unicode there will be problems when, for example, a
combining diacritic is found at the start of a segment as shown in the
second line of
http://scintilla.sourceforge.net/Auno.png
Work could be put into taking these into account when splitting
into segments but the platform knows about many similar factors such
as ligatures and contextual forms so it is probably best to rely on
the platform as far as possible. Therefore, the main method for
display will be to call ExtTextOut with the whole string and only if
that fails, display in 512 byte segments. This may not work if there
are circumstances in which the error status is not returned correctly.
There is a reimplementation of SurfaceImpl::DrawTextCommon from
scintilla/win32/PlatWin.cxx attached to this mail for anyone who wants
to check if it fixes the problem for them or if it causes more
problems.
Neil
void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, int ybase, const char *s, int len, UINT fuOptions) {
SetFont(font_);
RECT rcw = RectFromPRectangle(rc);
SIZE sz={0,0};
int pos = 0;
int x = rc.left;
// Text drawing may fail if the text is too big.
// If it does fail, slice up into segments and draw each segment.
const int maxSegmentLength = 0x200;
if ((!unicodeMode) && (IsNT() || (codePage==0) || win9xACPSame)) {
// Use ANSI calls
int lenDraw = Platform::Minimum(len, maxLenText);
if (!::ExtTextOutA(hdc, x, ybase, fuOptions, &rcw, s, lenDraw, NULL)) {
while (lenDraw > pos) {
int seglen = Platform::Minimum(maxSegmentLength, lenDraw - pos);
if (!::ExtTextOutA(hdc, x, ybase, fuOptions, &rcw, s+pos, seglen, NULL)) {
::OutputDebugString("Failed\n");
return;
}
::GetTextExtentPoint32A(hdc, s+pos, seglen, &sz);
x += sz.cx;
pos += seglen;
}
}
} else {
// Use Unicode calls
wchar_t tbuf[MAX_US_LEN];
int tlen;
if (unicodeMode) {
tlen = UCS2FromUTF8(s, len, tbuf, MAX_US_LEN);
} else {
// Support Asian string display in 9x English
tlen = ::MultiByteToWideChar(codePage, 0, s, len, NULL, 0);
if (tlen > MAX_US_LEN)
tlen = MAX_US_LEN;
::MultiByteToWideChar(codePage, 0, s, len, tbuf, tlen);
}
if (!::ExtTextOutW(hdc, x, ybase, fuOptions, &rcw, tbuf, tlen, NULL)) {
while (tlen > pos) {
int seglen = Platform::Minimum(maxSegmentLength, tlen - pos);
if (!::ExtTextOutW(hdc, x, ybase, fuOptions, &rcw, tbuf+pos, seglen, NULL)) {
::OutputDebugString("Failed\n");
return;
}
::GetTextExtentPoint32W(hdc, tbuf+pos, seglen, &sz);
x += sz.cx;
pos += seglen;
}
}
}
}
_______________________________________________
Scintilla-interest mailing list
[email protected]
http://mailman.lyra.org/mailman/listinfo/scintilla-interest