Fl_Text_Buffer/Display fixes for UTF-8 / STR-2158 (part 1)
fixes to handle incorrect counting of UTF-8 characters by checking for complete UTF-8 encodings in char* rather than char by char. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@7527 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
parent
1cd1045572
commit
9545e033bb
@ -248,6 +248,18 @@ public:
|
||||
*/
|
||||
unsigned int character(int pos) const;
|
||||
|
||||
/**
|
||||
Convert a byte offset in buffer into a memory address.
|
||||
*/
|
||||
const char *address(int pos) const
|
||||
{ return (pos < mGapStart) ? mBuf+pos : mBuf+pos+mGapEnd-mGapStart; }
|
||||
|
||||
/**
|
||||
Convert a byte offset in buffer into a memory address.
|
||||
*/
|
||||
char *address(int pos)
|
||||
{ return (pos < mGapStart) ? mBuf+pos : mBuf+pos+mGapEnd-mGapStart; }
|
||||
|
||||
/**
|
||||
Returns the text from the given rectangle. When you are done
|
||||
with the text, free it using the free() function.
|
||||
@ -681,6 +693,7 @@ public:
|
||||
\return number of byte in substitution
|
||||
*/
|
||||
static int character_width(const char *src, int indent, int tabDist);
|
||||
static int character_width(const char c, int indent, int tabDist);
|
||||
|
||||
/**
|
||||
Count the number of displayed characters between buffer position
|
||||
@ -934,18 +947,6 @@ protected:
|
||||
*/
|
||||
void update_selections(int pos, int nDeleted, int nInserted);
|
||||
|
||||
/**
|
||||
Convert a byte offset in buffer into a memory address.
|
||||
*/
|
||||
const char *address(int pos) const
|
||||
{ return (pos < mGapStart) ? mBuf+pos : mBuf+pos+mGapEnd-mGapStart; }
|
||||
|
||||
/**
|
||||
Convert a byte offset in buffer into a memory address.
|
||||
*/
|
||||
char *address(int pos)
|
||||
{ return (pos < mGapStart) ? mBuf+pos : mBuf+pos+mGapEnd-mGapStart; }
|
||||
|
||||
Fl_Text_Selection mPrimary; /**< highlighted areas */
|
||||
Fl_Text_Selection mSecondary; /**< highlighted areas */
|
||||
Fl_Text_Selection mHighlight; /**< highlighted areas */
|
||||
|
@ -251,7 +251,7 @@ class FL_EXPORT Fl_Text_Display: public Fl_Group {
|
||||
bool countLastLineMissingNewLine = true) const;
|
||||
void find_line_end(int pos, bool start_pos_is_line_start, int *lineEnd,
|
||||
int *nextLineStart) const;
|
||||
int measure_proportional_character(char c, int colNum, int pos) const;
|
||||
int measure_proportional_character(const char *s, int colNum, int pos) const;
|
||||
int wrap_uses_character(int lineEndPos) const;
|
||||
int range_touches_selection(const Fl_Text_Selection *sel, int rangeStart,
|
||||
int rangeEnd) const;
|
||||
|
@ -975,6 +975,8 @@ int Fl_Text_Buffer::expand_character(int pos, int indent, char *outStr) const {
|
||||
|
||||
// static function and counterpart to "character_width"
|
||||
// - unicode ok
|
||||
// FIXME: harmonise with new character_width(char*...) version
|
||||
//
|
||||
int Fl_Text_Buffer::expand_character(const char *src, int indent, char *outStr, int tabDist)
|
||||
{
|
||||
char c = *src;
|
||||
@ -1018,8 +1020,27 @@ int Fl_Text_Buffer::expand_character(const char *src, int indent, char *outStr,
|
||||
// - unicode ok
|
||||
int Fl_Text_Buffer::character_width(const char *src, int indent, int tabDist)
|
||||
{
|
||||
/* Note, this code must parallel that in Fl_Text_Buffer::ExpandCharacter */
|
||||
char c = *src;
|
||||
if ((c & 0x80) && (c & 0x40)) { // first byte of UTF-8 sequence
|
||||
int len = fl_utf8len(c);
|
||||
int ret = 0;
|
||||
unsigned int ucs = fl_utf8decode(src, src+len, &ret);
|
||||
int width = 1; // mk_wcwidth((wchar_t)ucs); // FIXME
|
||||
// fprintf(stderr, "mk_wcwidth(%x) -> %d (%d, %d, %s)\n", ucs, width, len, ret, s);
|
||||
return width;
|
||||
}
|
||||
if ((c & 0x80) && !(c & 0x40)) { // other byte of UTF-8 sequence
|
||||
return 0;
|
||||
}
|
||||
return character_width(c, indent, tabDist);
|
||||
}
|
||||
|
||||
// FIXME: merge the following with the char* version above.
|
||||
// but the question then is: how to reorganise expand_character()?
|
||||
//
|
||||
int Fl_Text_Buffer::character_width(const char c, int indent, int tabDist)
|
||||
{
|
||||
/* Note, this code must parallel that in Fl_Text_Buffer::ExpandCharacter */
|
||||
if (c == '\t') {
|
||||
return tabDist - (indent % tabDist);
|
||||
} else if (((unsigned char) c) <= 31) {
|
||||
@ -1032,7 +1053,8 @@ int Fl_Text_Buffer::character_width(const char *src, int indent, int tabDist)
|
||||
#endif
|
||||
return 1;
|
||||
} else if (c & 0x80) {
|
||||
return fl_utf8len(c);
|
||||
// return fl_utf8len(c);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -1529,8 +1551,7 @@ static void insertColInLine(const char *line, char *insLine, int column,
|
||||
const char *linePtr;
|
||||
|
||||
for (linePtr = line; *linePtr != '\0'; linePtr++) {
|
||||
len =
|
||||
Fl_Text_Buffer::character_width(linePtr, indent, tabDist);
|
||||
len = Fl_Text_Buffer::character_width(linePtr, indent, tabDist);
|
||||
if (indent + len > column)
|
||||
break;
|
||||
indent += len;
|
||||
@ -1573,8 +1594,7 @@ static void insertColInLine(const char *line, char *insLine, int column,
|
||||
&len);
|
||||
for (const char *c = retabbedStr; *c != '\0'; c++) {
|
||||
*outPtr++ = *c;
|
||||
len =
|
||||
Fl_Text_Buffer::character_width(c, indent, tabDist);
|
||||
len = Fl_Text_Buffer::character_width(c, indent, tabDist);
|
||||
indent += len;
|
||||
}
|
||||
free((void *) retabbedStr);
|
||||
@ -1624,8 +1644,7 @@ static void deleteRectFromLine(const char *line, int rectStart,
|
||||
for (c = line; *c != '\0'; c++) {
|
||||
if (indent > rectStart)
|
||||
break;
|
||||
len =
|
||||
Fl_Text_Buffer::character_width(c, indent, tabDist);
|
||||
len = Fl_Text_Buffer::character_width(c, indent, tabDist);
|
||||
if (indent + len > rectStart && (indent == rectStart || *c == '\t'))
|
||||
break;
|
||||
indent += len;
|
||||
@ -1635,8 +1654,7 @@ static void deleteRectFromLine(const char *line, int rectStart,
|
||||
|
||||
/* skip the characters between rectStart and rectEnd */
|
||||
for (; *c != '\0' && indent < rectEnd; c++)
|
||||
indent +=
|
||||
Fl_Text_Buffer::character_width(c, indent, tabDist);
|
||||
indent += Fl_Text_Buffer::character_width(c, indent, tabDist);
|
||||
int postRectIndent = indent;
|
||||
|
||||
/* If the line ended before rectEnd, there's nothing more to do */
|
||||
@ -1682,8 +1700,7 @@ static void overlayRectInLine(const char *line, char *insLine,
|
||||
const char *linePtr = line;
|
||||
|
||||
for (; *linePtr != '\0'; linePtr++) {
|
||||
len =
|
||||
Fl_Text_Buffer::character_width(linePtr, inIndent, tabDist);
|
||||
len = Fl_Text_Buffer::character_width(linePtr, inIndent, tabDist);
|
||||
if (inIndent + len > rectStart)
|
||||
break;
|
||||
inIndent += len;
|
||||
@ -1709,8 +1726,7 @@ static void overlayRectInLine(const char *line, char *insLine,
|
||||
/* skip the characters between rectStart and rectEnd */
|
||||
int postRectIndent = rectEnd;
|
||||
for (; *linePtr != '\0'; linePtr++) {
|
||||
inIndent +=
|
||||
Fl_Text_Buffer::character_width(linePtr, inIndent, tabDist);
|
||||
inIndent += Fl_Text_Buffer::character_width(linePtr, inIndent, tabDist);
|
||||
if (inIndent >= rectEnd) {
|
||||
linePtr++;
|
||||
postRectIndent = inIndent;
|
||||
@ -1738,8 +1754,7 @@ static void overlayRectInLine(const char *line, char *insLine,
|
||||
realignTabs(insLine, 0, rectStart, tabDist, useTabs, &len);
|
||||
for (const char *c = retabbedStr; *c != '\0'; c++) {
|
||||
*outPtr++ = *c;
|
||||
len =
|
||||
Fl_Text_Buffer::character_width(c, outIndent, tabDist);
|
||||
len = Fl_Text_Buffer::character_width(c, outIndent, tabDist);
|
||||
outIndent += len;
|
||||
}
|
||||
free((void *) retabbedStr);
|
||||
@ -1895,7 +1910,7 @@ static void addPadding(char *string, int startIndent, int toIndent,
|
||||
if (useTabs) {
|
||||
while (indent < toIndent) {
|
||||
static char t = '\t';
|
||||
len = Fl_Text_Buffer::character_width(&t, indent, tabDist);
|
||||
len = Fl_Text_Buffer::character_width("\t", indent, tabDist);
|
||||
if (len > 1 && indent + len <= toIndent) {
|
||||
*outPtr++ = '\t';
|
||||
indent += len;
|
||||
@ -2272,6 +2287,7 @@ static char *expandTabs(const char *text, int startIndent, int tabDist, int *new
|
||||
indent = startIndent;
|
||||
outLen++;
|
||||
} else {
|
||||
// FIXME: character_width does not return number of bytes for UTF-8!
|
||||
indent +=
|
||||
Fl_Text_Buffer::character_width(c, indent, tabDist);
|
||||
outLen++;
|
||||
@ -2292,6 +2308,7 @@ static char *expandTabs(const char *text, int startIndent, int tabDist, int *new
|
||||
indent = startIndent;
|
||||
*outPtr++ = *c;
|
||||
} else {
|
||||
// FIXME: character_width does not return number of bytes for UTF-8!
|
||||
indent +=
|
||||
Fl_Text_Buffer::character_width(c, indent, tabDist);
|
||||
*outPtr++ = *c;
|
||||
|
@ -644,7 +644,8 @@ void Fl_Text_Display::overstrike(const char* text) {
|
||||
ch = buf->character( p );
|
||||
if ( ch == '\n' )
|
||||
break;
|
||||
indent += Fl_Text_Buffer::character_width( &ch, indent, buf->tab_distance() ); // FIXME: not unicode
|
||||
const char *s = buf->address(p);
|
||||
indent += Fl_Text_Buffer::character_width(s, indent, buf->tab_distance() ); // FIXME: not unicode
|
||||
if ( indent == endIndent ) {
|
||||
p++;
|
||||
break;
|
||||
@ -1635,7 +1636,6 @@ void Fl_Text_Display::draw_string( int style, int X, int Y, int toX,
|
||||
clear_rect( style, X, Y, toX - X, mMaxsize );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set font, color, and gc depending on style. For normal text, GCs
|
||||
for normal drawing, or drawing within a Fl_Text_Selection or highlight are
|
||||
pre-allocated and pre-configured. For syntax highlighting, GCs are
|
||||
@ -2717,9 +2717,10 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
|
||||
colNum = 0;
|
||||
width = 0;
|
||||
} else {
|
||||
colNum += Fl_Text_Buffer::character_width((char*)&c, colNum, tabDist); // FIXME: unicode
|
||||
const char *s = buf->address(p);
|
||||
colNum += Fl_Text_Buffer::character_width(s, colNum, tabDist); // FIXME: unicode
|
||||
if (countPixels)
|
||||
width += measure_proportional_character(c, colNum, p+styleBufOffset);
|
||||
width += measure_proportional_character(s, colNum, p+styleBufOffset);
|
||||
}
|
||||
|
||||
/* If character exceeded wrap margin, find the break point
|
||||
@ -2737,7 +2738,7 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
|
||||
for (i=b+1; i<p+1; i++) {
|
||||
width += measure_proportional_character(
|
||||
// FIXME: character is ucs-4
|
||||
buf->character(i), colNum,
|
||||
buf->address(i), colNum,
|
||||
i+styleBufOffset);
|
||||
colNum++;
|
||||
}
|
||||
@ -2749,9 +2750,10 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
|
||||
}
|
||||
if (!foundBreak) { /* no whitespace, just break at margin */
|
||||
newLineStart = max(p, lineStart+1);
|
||||
colNum = Fl_Text_Buffer::character_width((char*)&c, colNum, tabDist); // FIXME: unicode
|
||||
const char *s = buf->address(b);
|
||||
colNum = Fl_Text_Buffer::character_width(s, colNum, tabDist); // FIXME: unicode
|
||||
if (countPixels)
|
||||
width = measure_proportional_character(c, colNum, p+styleBufOffset);
|
||||
width = measure_proportional_character(s, colNum, p+styleBufOffset);
|
||||
}
|
||||
if (p >= maxPos) {
|
||||
*retPos = maxPos;
|
||||
@ -2783,9 +2785,9 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
|
||||
}
|
||||
|
||||
/**
|
||||
Measure the width in pixels of a character "c" at a particular column
|
||||
"colNum" and buffer position "pos". This is for measuring characters in
|
||||
proportional or mixed-width highlighting fonts.
|
||||
Measure the width in pixels of the first character of string "s" at a
|
||||
particular column "colNum" and buffer position "pos". This is for measuring
|
||||
characters in proportional or mixed-width highlighting fonts.
|
||||
**
|
||||
A note about proportional and mixed-width fonts: the mixed width and
|
||||
proportional font code in nedit does not get much use in general editing,
|
||||
@ -2796,12 +2798,13 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos,
|
||||
insertion/deletion, though static display and wrapping and resizing
|
||||
should now be solid because they are now used for online help display.
|
||||
*/
|
||||
int Fl_Text_Display::measure_proportional_character(char c, int colNum, int pos) const {
|
||||
|
||||
int Fl_Text_Display::measure_proportional_character(const char *s, int colNum, int pos) const {
|
||||
int charLen, style;
|
||||
char expChar[ FL_TEXT_MAX_EXP_CHAR_LEN ];
|
||||
Fl_Text_Buffer *styleBuf = mStyleBuffer;
|
||||
|
||||
charLen = Fl_Text_Buffer::expand_character(&c, colNum, expChar, buffer()->tab_distance()); // FIXME: unicode
|
||||
charLen = Fl_Text_Buffer::expand_character(s, colNum, expChar, buffer()->tab_distance()); // FIXME: unicode
|
||||
if (styleBuf == 0) {
|
||||
style = 0;
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user