diff options
| author | Matthias Melcher <fltk@matthiasm.com> | 2010-04-05 22:18:14 +0000 |
|---|---|---|
| committer | Matthias Melcher <fltk@matthiasm.com> | 2010-04-05 22:18:14 +0000 |
| commit | 61cf49ddfce0cbf26a769928df9be7093ed88366 (patch) | |
| tree | c7c080c3c370df66e696aaf5cbbc768f22337b97 | |
| parent | 07a4509a63bfc06fca31972002e2861449df49c3 (diff) | |
Another update to Fl_Text_Buffer. This is by no means perfect, but at least it currently does not crash (I am so easily satisfied :-P).
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@7449 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
| -rw-r--r-- | FL/Fl_Text_Buffer.H | 50 | ||||
| -rw-r--r-- | src/Fl_Text_Buffer.cxx | 117 | ||||
| -rw-r--r-- | src/Fl_Text_Display.cxx | 88 |
3 files changed, 131 insertions, 124 deletions
diff --git a/FL/Fl_Text_Buffer.H b/FL/Fl_Text_Buffer.H index ac4cff7ac..f5736aa8b 100644 --- a/FL/Fl_Text_Buffer.H +++ b/FL/Fl_Text_Buffer.H @@ -211,15 +211,16 @@ public: ~Fl_Text_Buffer(); /** - Returns the number of characters in the buffer. - \todo unicode check + \brief Returns the number of bytes in the buffer. + \return size of text in bytes */ int length() const { return mLength; } /** - Get the entire contents of a text buffer. Memory is allocated to contain - the returned string, which the caller must free. - \todo unicode check + \brief Get a copy of the entire contents of the text buffer. + Memory is allocated to contain the returned string, which the caller + must free. + \return newly allocated text buffer - must be free'd */ char* text() const; @@ -230,11 +231,14 @@ public: void text(const char* text); /** + \brief Get a copy of a part of the text buffer. Return a copy of the text between \p start and \p end character positions from text buffer \p buf. Positions start at 0, and the range does not include the character pointed to by \p end. When you are done with the text, free it using the free() function. - \todo unicode check + \param start byte offset to first character + \param end byte offset after last character in range + \return newly allocated text buffer - must be free'd */ char* text_range(int start, int end) const; @@ -659,22 +663,25 @@ public: control code). Returns the number of characters added to \p outStr. \p indent is the number of characters from the start of the line for figuring tabs of length \p tabDist. Output string is guaranteed - to be shorter or equal in length to FL_TEXT_MAX_EXP_CHAR_LEN + to be shorter or equal in length to FL_TEXT_MAX_EXP_CHAR_LEN Tabs and other control characters are given special treatment. - \p nulSubsChar represent the null character to be transformed in \<nul\> - \todo unicode check + \param src address of utf-8 text + \param indent + \param[out] outStr write substitution here + \param tabDist + \return number of byte in substitution */ - static int expand_character(char c, int indent, char* outStr, int tabDist); + static int expand_character(const char *src, int indent, char* outStr, int tabDist); /** Return the length in displayed characters of character \p c expanded - for display (as discussed above in expand_character() ). If the - buffer for which the character width is being measured is doing null - substitution, nullSubsChar should be passed as that character (or nul - to ignore). - \todo unicode check + for display (as discussed above in expand_character() ). + \param src address of utf-8 text + \param indent + \param tabDist + \return number of byte in substitution */ - static int character_width(char c, int indent, int tabDist); + static int character_width(const char *src, int indent, int tabDist); /** Count the number of displayed characters between buffer position @@ -689,6 +696,9 @@ public: Count forward from buffer position \p startPos in displayed characters (displayed characters are the characters shown on the screen to represent characters in the buffer, where tabs and control characters are expanded) + \param lineStartPos byte offset into buffer + \param nChars number of bytes that are sent to the display + \return byte offset in input after all output bytes are sent \todo unicode check */ int skip_displayed_characters(int lineStartPos, int nChars); @@ -929,6 +939,14 @@ 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; } + 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 */ diff --git a/src/Fl_Text_Buffer.cxx b/src/Fl_Text_Buffer.cxx index 2b091ec95..0e8884972 100644 --- a/src/Fl_Text_Buffer.cxx +++ b/src/Fl_Text_Buffer.cxx @@ -209,14 +209,19 @@ Fl_Text_Buffer::~Fl_Text_Buffer() } } + +// This function copies verbose whatever is in front and after the gap into a +// single buffer. +// - unicode ok char *Fl_Text_Buffer::text() const { - char *t = (char *) malloc(mLength + 1); //UTF8: we alloc from a string len, but as (non-utf8 aware) strlen() - // is used to affect mLength, it is equal to buffer size - 1 and thus correct. + char *t = (char *) malloc(mLength + 1); memcpy(t, mBuf, mGapStart); memcpy(&t[mGapStart], &mBuf[mGapEnd], mLength - mGapStart); t[mLength] = '\0'; return t; -} void Fl_Text_Buffer::text(const char *t) +} + +void Fl_Text_Buffer::text(const char *t) { call_predelete_callbacks(0, length()); @@ -249,6 +254,9 @@ char *Fl_Text_Buffer::text() const { free((void *) deletedText); } + +// Creates a new buffer and copies verbose from around the gap. +// - unicode ok char *Fl_Text_Buffer::text_range(int start, int end) const { char *s = NULL; @@ -284,6 +292,8 @@ char *Fl_Text_Buffer::text_range(int start, int end) const { return s; } + +// FIXME: a character must be UCS-4 encoded char Fl_Text_Buffer::character(int pos) const { if (pos < 0 || pos >= mLength) return '\0'; @@ -291,7 +301,10 @@ char Fl_Text_Buffer::character(int pos) const { return mBuf[pos]; else return mBuf[pos + mGapEnd - mGapStart]; -} void Fl_Text_Buffer::insert(int pos, const char *text) +} + + +void Fl_Text_Buffer::insert(int pos, const char *text) { /* if pos is not contiguous to existing text, make it */ if (pos > mLength) @@ -930,25 +943,23 @@ int Fl_Text_Buffer::word_end(int pos) const { } return pos; } + +// Expand from the byte representation into some readable text. +// Under unicode, this is not really needed because all characters should +// be prinatble one way or the other. But since we use this to (badly) simulate +// tabs, we can leave this here anyway. +// - unicode ok int Fl_Text_Buffer::expand_character(int pos, int indent, char *outStr) const { - char c = character(pos); - int ret = expand_character(c, indent, outStr, mTabDist); - if (ret > 1 && (c & 0x80)) - { - int i; - i = fl_utf8len(c); - while (i > 1) { - i--; - pos++; - outStr++; - *outStr = character(pos); - }} - - return ret; + const char *src = address(pos); + return expand_character(src, indent, outStr, mTabDist); } -int Fl_Text_Buffer::expand_character(char c, int indent, char *outStr, int tabDist) + +// static function and counterpart to "character_width" +// - unicode ok +int Fl_Text_Buffer::expand_character(const char *src, int indent, char *outStr, int tabDist) { + char c = *src; /* Convert tabs to spaces */ if (c == '\t') { int nSpaces = tabDist - (indent % tabDist); @@ -958,7 +969,6 @@ int Fl_Text_Buffer::expand_character(char c, int indent, char *outStr, int tabDi } /* Convert control codes to readable character sequences */ - /*... is this safe with international character sets? */ if (((unsigned char) c) <= 31) { sprintf(outStr, "<%s>", ControlCodeTable[(unsigned char) c]); return strlen(outStr); @@ -972,8 +982,9 @@ int Fl_Text_Buffer::expand_character(char c, int indent, char *outStr, int tabDi *outStr = c; return 1; } else if (c & 0x80) { - *outStr = c; - return fl_utf8len(c); + int i, n = fl_utf8len(c); + for (i=0; i<n; i++) *outStr++ = *src++; + return n; } /* Otherwise, just return the character */ @@ -981,9 +992,16 @@ int Fl_Text_Buffer::expand_character(char c, int indent, char *outStr, int tabDi return 1; } -int Fl_Text_Buffer::character_width(char c, int indent, int tabDist) + +// This function takes a character and optionally converts it into a little +// string which will replace the character on screen. This function returns +// the number of bytes in the replacement string, but *not* the number of +// bytes in the original character! +// - 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 == '\t') { return tabDist - (indent % tabDist); } else if (((unsigned char) c) <= 31) { @@ -1011,18 +1029,22 @@ int Fl_Text_Buffer::count_displayed_characters(int lineStartPos, while (pos < targetPos) charCount += expand_character(pos++, charCount, expandedChar); return charCount; -} int Fl_Text_Buffer::skip_displayed_characters(int lineStartPos, - int nChars) +} + + +// All values are number of bytes. +// - unicode ok +int Fl_Text_Buffer::skip_displayed_characters(int lineStartPos, int nChars) { int pos = lineStartPos; - char c; for (int charCount = 0; charCount < nChars && pos < mLength;) { - c = character(pos); + const char *src = address(pos); + char c = *src; if (c == '\n') return pos; - charCount += character_width(c, charCount, mTabDist); - pos++; + charCount += character_width(src, charCount, mTabDist); + pos += fl_utf8len(c); } return pos; } @@ -1488,7 +1510,7 @@ static void insertColInLine(const char *line, char *insLine, int column, for (linePtr = line; *linePtr != '\0'; linePtr++) { len = - Fl_Text_Buffer::character_width(*linePtr, indent, tabDist); + Fl_Text_Buffer::character_width(linePtr, indent, tabDist); if (indent + len > column) break; indent += len; @@ -1532,7 +1554,7 @@ static void insertColInLine(const char *line, char *insLine, int column, for (const char *c = retabbedStr; *c != '\0'; c++) { *outPtr++ = *c; len = - Fl_Text_Buffer::character_width(*c, indent, tabDist); + Fl_Text_Buffer::character_width(c, indent, tabDist); indent += len; } free((void *) retabbedStr); @@ -1583,7 +1605,7 @@ static void deleteRectFromLine(const char *line, int rectStart, if (indent > rectStart) break; len = - Fl_Text_Buffer::character_width(*c, indent, tabDist); + Fl_Text_Buffer::character_width(c, indent, tabDist); if (indent + len > rectStart && (indent == rectStart || *c == '\t')) break; indent += len; @@ -1594,7 +1616,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); + Fl_Text_Buffer::character_width(c, indent, tabDist); int postRectIndent = indent; /* If the line ended before rectEnd, there's nothing more to do */ @@ -1641,7 +1663,7 @@ static void overlayRectInLine(const char *line, char *insLine, for (; *linePtr != '\0'; linePtr++) { len = - Fl_Text_Buffer::character_width(*linePtr, inIndent, tabDist); + Fl_Text_Buffer::character_width(linePtr, inIndent, tabDist); if (inIndent + len > rectStart) break; inIndent += len; @@ -1668,7 +1690,7 @@ static void overlayRectInLine(const char *line, char *insLine, int postRectIndent = rectEnd; for (; *linePtr != '\0'; linePtr++) { inIndent += - Fl_Text_Buffer::character_width(*linePtr, inIndent, tabDist); + Fl_Text_Buffer::character_width(linePtr, inIndent, tabDist); if (inIndent >= rectEnd) { linePtr++; postRectIndent = inIndent; @@ -1697,7 +1719,7 @@ static void overlayRectInLine(const char *line, char *insLine, for (const char *c = retabbedStr; *c != '\0'; c++) { *outPtr++ = *c; len = - Fl_Text_Buffer::character_width(*c, outIndent, tabDist); + Fl_Text_Buffer::character_width(c, outIndent, tabDist); outIndent += len; } free((void *) retabbedStr); @@ -1852,8 +1874,8 @@ static void addPadding(char *string, int startIndent, int toIndent, if (useTabs) { while (indent < toIndent) { - len = - Fl_Text_Buffer::character_width('\t', indent, tabDist); + static char t = '\t'; + len = Fl_Text_Buffer::character_width(&t, indent, tabDist); if (len > 1 && indent + len <= toIndent) { *outPtr++ = '\t'; indent += len; @@ -2115,14 +2137,14 @@ static int textWidth(const char *text, int tabDist) { int width = 0, maxWidth = 0; - for (const char *c = text; *c != '\0'; c++) { + for (const char *c = text; *c != '\0'; c++) { // FIXME: increment is wrong! if (*c == '\n') { if (width > maxWidth) maxWidth = width; width = 0; } else width += - Fl_Text_Buffer::character_width(*c, width, tabDist); + Fl_Text_Buffer::character_width(c, width, tabDist); } if (width > maxWidth) return width; @@ -2145,7 +2167,7 @@ void Fl_Text_Buffer::rectangular_selection_boundaries(int lineStartPos, if (c == '\n') break; width = - Fl_Text_Buffer::character_width(c, indent, mTabDist); + Fl_Text_Buffer::character_width(&c, indent, mTabDist); // FIXME: c si not unicode if (indent + width > rectStart) { if (indent != rectStart && c != '\t') { pos++; @@ -2163,7 +2185,7 @@ void Fl_Text_Buffer::rectangular_selection_boundaries(int lineStartPos, if (c == '\n') break; width = - Fl_Text_Buffer::character_width(c, indent, mTabDist); + Fl_Text_Buffer::character_width(&c, indent, mTabDist); // FIXME: c is not unicode indent += width; if (indent > rectEnd) { if (indent - width != rectEnd && c != '\t') @@ -2220,7 +2242,7 @@ static char *expandTabs(const char *text, int startIndent, int tabDist, int *new for (c = text; *c != '\0'; c++) { if (*c == '\t') { len = - Fl_Text_Buffer::character_width(*c, indent, tabDist); + Fl_Text_Buffer::character_width(c, indent, tabDist); outLen += len; indent += len; } else if (*c == '\n') { @@ -2228,7 +2250,7 @@ static char *expandTabs(const char *text, int startIndent, int tabDist, int *new outLen++; } else { indent += - Fl_Text_Buffer::character_width(*c, indent, tabDist); + Fl_Text_Buffer::character_width(c, indent, tabDist); outLen++; } } @@ -2240,7 +2262,7 @@ static char *expandTabs(const char *text, int startIndent, int tabDist, int *new for (c = text; *c != '\0'; c++) { if (*c == '\t') { len = - Fl_Text_Buffer::expand_character(*c, indent, outPtr, tabDist); + Fl_Text_Buffer::expand_character(c, indent, outPtr, tabDist); outPtr += len; indent += len; } else if (*c == '\n') { @@ -2248,7 +2270,7 @@ static char *expandTabs(const char *text, int startIndent, int tabDist, int *new *outPtr++ = *c; } else { indent += - Fl_Text_Buffer::character_width(*c, indent, tabDist); + Fl_Text_Buffer::character_width(c, indent, tabDist); *outPtr++ = *c; } } @@ -2271,8 +2293,9 @@ static char *unexpandTabs(char *text, int startIndent, int tabDist, int *newLen) for (const char *c = text; *c != '\0';) { if (*c == ' ') { + static char tab = '\t'; len = - Fl_Text_Buffer::expand_character('\t', indent, expandedChar, tabDist); + Fl_Text_Buffer::expand_character(&tab, indent, expandedChar, tabDist); if (len >= 3 && !strncmp(c, expandedChar, len)) { c += len; *outPtr++ = '\t'; diff --git a/src/Fl_Text_Display.cxx b/src/Fl_Text_Display.cxx index 31ea985b8..0b72b39d3 100644 --- a/src/Fl_Text_Display.cxx +++ b/src/Fl_Text_Display.cxx @@ -629,7 +629,7 @@ void Fl_Text_Display::overstrike(const char* text) { startIndent = mBuffer->count_displayed_characters( lineStart, startPos ); indent = startIndent; for ( c = text; *c != '\0'; c++ ) - indent += Fl_Text_Buffer::character_width( *c, indent, buf->tab_distance() ); + indent += Fl_Text_Buffer::character_width( c, indent, buf->tab_distance() ); endIndent = indent; /* find which characters to remove, and if necessary generate additional @@ -641,7 +641,7 @@ 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() ); + indent += Fl_Text_Buffer::character_width( &ch, indent, buf->tab_distance() ); // FIXME: not unicode if ( indent == endIndent ) { p++; break; @@ -722,18 +722,12 @@ int Fl_Text_Display::position_to_xy( int pos, int* X, int* Y ) const { to "pos" to calculate the X coordinate */ xStep = text_area.x - mHorizOffset; outIndex = 0; - for ( charIndex = 0; charIndex < lineLen && charIndex < pos - lineStartPos; charIndex++ ) { - charLen = Fl_Text_Buffer::expand_character( lineStr[ charIndex ], outIndex, expandedChar, + for (charIndex = 0; + charIndex < lineLen && charIndex < pos - lineStartPos; + charIndex += fl_utf8len(lineStr[charIndex]) ) + { + charLen = Fl_Text_Buffer::expand_character( lineStr+charIndex, outIndex, expandedChar, mBuffer->tab_distance()); - if (charLen > 1 && (lineStr[ charIndex ] & 0x80)) { - int i, ii = 0;; - i = fl_utf8len(lineStr[ charIndex ]); - while (i > 1) { - i--; - ii++; - expandedChar[ii] = lineStr[ charIndex + ii]; - } - } charStyle = position_style( lineStartPos, lineLen, charIndex, outIndex ); xStep += string_width( expandedChar, charLen, charStyle ); @@ -1475,20 +1469,10 @@ void Fl_Text_Display::draw_vline(int visLineNum, int leftClip, int rightClip, that character */ X = text_area.x - mHorizOffset; outIndex = 0; - for ( charIndex = 0; ; charIndex++ ) { + for ( charIndex = 0; ; charIndex += lineStr ? fl_utf8len(lineStr[charIndex]) : 1 ) { charLen = charIndex >= lineLen ? 1 : - Fl_Text_Buffer::expand_character( lineStr[ charIndex ], outIndex, + Fl_Text_Buffer::expand_character( lineStr+charIndex, outIndex, expandedChar, buf->tab_distance()); - if (charIndex < lineLen && charLen > 1 && (lineStr[ charIndex ] & 0x80)) { - int i, ii = 0;; - i = fl_utf8len(lineStr[ charIndex ]); - while (i > 1) { - i--; - ii++; - expandedChar[ii] = lineStr[ charIndex + ii]; - } - } - style = position_style( lineStartPos, lineLen, charIndex, outIndex + dispIndexOffset ); charWidth = charIndex >= lineLen ? stdCharWidth : @@ -1513,19 +1497,13 @@ void Fl_Text_Display::draw_vline(int visLineNum, int leftClip, int rightClip, outPtr = outStr; outIndex = outStartIndex; X = startX; - for ( charIndex = startIndex; charIndex < rightCharIndex; charIndex++ ) { + for (charIndex = startIndex; + charIndex < rightCharIndex; + charIndex += lineStr ? fl_utf8len(lineStr[charIndex]) : 1 ) + { charLen = charIndex >= lineLen ? 1 : - Fl_Text_Buffer::expand_character( lineStr[ charIndex ], outIndex, expandedChar, + Fl_Text_Buffer::expand_character( lineStr+charIndex, outIndex, expandedChar, buf->tab_distance()); - if (charIndex < lineLen && charLen > 1 && (lineStr[ charIndex ] & 0x80)) { - int i, ii = 0;; - i = fl_utf8len(lineStr[ charIndex ]); - while (i > 1) { - i--; - ii++; - expandedChar[ii] = lineStr[ charIndex + ii]; - } - } charStyle = position_style( lineStartPos, lineLen, charIndex, outIndex + dispIndexOffset ); for ( i = 0; i < charLen; i++ ) { @@ -1561,19 +1539,13 @@ void Fl_Text_Display::draw_vline(int visLineNum, int leftClip, int rightClip, outPtr = outStr; outIndex = outStartIndex; X = startX; - for ( charIndex = startIndex; charIndex < rightCharIndex; charIndex++ ) { + for (charIndex = startIndex; + charIndex < rightCharIndex; + charIndex += lineStr ? fl_utf8len(lineStr[charIndex]) : 0) + { charLen = charIndex >= lineLen ? 1 : - Fl_Text_Buffer::expand_character( lineStr[ charIndex ], outIndex, expandedChar, + Fl_Text_Buffer::expand_character( lineStr+charIndex, outIndex, expandedChar, buf->tab_distance()); - if (charIndex < lineLen && charLen > 1 && (lineStr[ charIndex ] & 0x80)) { - int i, ii = 0;; - i = fl_utf8len(lineStr[ charIndex ]); - while (i > 1) { - i--; - ii++; - expandedChar[ii] = lineStr[ charIndex + ii]; - } - } charStyle = position_style( lineStartPos, lineLen, charIndex, outIndex + dispIndexOffset ); for ( i = 0; i < charLen; i++ ) { @@ -1923,18 +1895,12 @@ int Fl_Text_Display::xy_to_position( int X, int Y, int posType ) const { to find the character position corresponding to the X coordinate */ xStep = text_area.x - mHorizOffset; outIndex = 0; - for ( charIndex = 0; charIndex < lineLen; charIndex++ ) { - charLen = Fl_Text_Buffer::expand_character( lineStr[ charIndex ], outIndex, expandedChar, + for (charIndex = 0; + charIndex < lineLen; + charIndex += fl_utf8len(lineStr[charIndex]) ) + { + charLen = Fl_Text_Buffer::expand_character( lineStr+charIndex, outIndex, expandedChar, mBuffer->tab_distance()); - if (charLen > 1 && (lineStr[ charIndex ] & 0x80)) { - int i, ii = 0;; - i = fl_utf8len(lineStr[ charIndex ]); - while (i > 1) { - i--; - ii++; - expandedChar[ii] = lineStr[ charIndex + ii]; - } - } charStyle = position_style( lineStart, lineLen, charIndex, outIndex ); charWidth = string_width( expandedChar, charLen, charStyle ); if ( X < xStep + ( posType == CURSOR_POS ? charWidth / 2 : charWidth ) ) { @@ -2732,7 +2698,7 @@ void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos, colNum = 0; width = 0; } else { - colNum += Fl_Text_Buffer::character_width(c, colNum, tabDist); + colNum += Fl_Text_Buffer::character_width((char*)&c, colNum, tabDist); // FIXME: unicode if (countPixels) width += measure_proportional_character(c, colNum, p+styleBufOffset); } @@ -2762,7 +2728,7 @@ 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(c, colNum, tabDist); + colNum = Fl_Text_Buffer::character_width((char*)&c, colNum, tabDist); // FIXME: unicode if (countPixels) width = measure_proportional_character(c, colNum, p+styleBufOffset); } @@ -2814,7 +2780,7 @@ int Fl_Text_Display::measure_proportional_character(char c, int colNum, int pos) 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()); + charLen = Fl_Text_Buffer::expand_character(&c, colNum, expChar, buffer()->tab_distance()); // FIXME: unicode if (styleBuf == 0) { style = 0; } else { |
