diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c9899383..2d216d03 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,6 +56,8 @@ Other Changes: - BeginChild(): Fixed BeginChild(const char*, ...) variation erroneously not applying the ID stack to the provided string to uniquely identify the child window. This was undoing an intentional change introduced in 1.50 and broken in 1.60. (#1698, #894, #713). +- TextUnformatted(): Fixed a case where large-text path would read bytes past the text_end marker depending + on the position of new lines in the buffer (it wasn't affecting the output but still not the right thing to do!) - BeginMenu(): Fixed menu popup horizontal offset being off the item in the menu bar when WindowPadding=0.0f. - ArrowButton(): Fixed arrow shape being horizontally misaligned by (FramePadding.y-FramePadding.x) if they are different. - Drag and Drop: Added GetDragDropPayload() to peek directly into the payload (if any) from anywhere. (#143) diff --git a/imgui.cpp b/imgui.cpp index aef64e0d..52ca8002 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1203,10 +1203,8 @@ char* ImStrdup(const char *str) const char* ImStrchrRange(const char* str, const char* str_end, char c) { - for ( ; str < str_end; str++) - if (*str == c) - return str; - return NULL; + const char* p = (const char*)memchr(str, (int)c, str_end - str); + return p; } int ImStrlenW(const ImWchar* str) @@ -1216,6 +1214,13 @@ int ImStrlenW(const ImWchar* str) return n; } +// Find end-of-line. Return pointer will point to either first \n, either str_end. +const char* ImStreolRange(const char* str, const char* str_end) +{ + const char* p = (const char*)memchr(str, '\n', str_end - str); + return p ? p : str_end; +} + const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line { while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n') @@ -8343,29 +8348,17 @@ void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* for (;;) { // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry. - const char* line_end = text_remaining; - while (line_end < text_end) - if (*line_end == '\n') - break; - else - line_end++; - if (line_end >= text_end) - line_end = NULL; - - const bool is_first_line = (text == text_remaining); - bool is_last_line = false; - if (line_end == NULL) + const char* line_start = text_remaining; + const char* line_end = ImStreolRange(line_start, text_end); + const bool is_first_line = (line_start == text); + const bool is_last_line = (line_end == text_end); + if (!is_last_line || (line_start != line_end)) { - is_last_line = true; - line_end = text_end; - } - if (line_end != NULL && !(is_last_line && (line_end - text_remaining)==0)) - { - const int char_count = (int)(line_end - text_remaining); + const int char_count = (int)(line_end - line_start); if (log_new_line || !is_first_line) - LogText(IM_NEWLINE "%*s%.*s", tree_depth*4, "", char_count, text_remaining); + LogText(IM_NEWLINE "%*s%.*s", tree_depth*4, "", char_count, line_start); else - LogText(" %.*s", char_count, text_remaining); + LogText(" %.*s", char_count, line_start); } if (is_last_line) diff --git a/imgui_internal.h b/imgui_internal.h index 124f0875..9ebcdd78 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -141,7 +141,8 @@ IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); IMGUI_API char* ImStrdup(const char* str); IMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end, char c); IMGUI_API int ImStrlenW(const ImWchar* str); -IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line +IMGUI_API const char* ImStreolRange(const char* str, const char* str_end); // End end-of-line +IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end); IMGUI_API void ImStrTrimBlanks(char* str); IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 67650e2d..9cecc547 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -133,8 +133,9 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) { // Long text! // Perform manual coarse clipping to optimize for long multi-line text - // From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled. - // We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line. + // - From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled. + // - We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line. + // - We use memchr(), pay attention that well optimized versions of those str/mem functions are much faster than a casually written loop. const char* line = text; const float line_height = GetTextLineHeight(); const ImRect clip_rect = window->ClipRect; @@ -153,7 +154,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) int lines_skipped = 0; while (line < text_end && lines_skipped < lines_skippable) { - const char* line_end = strchr(line, '\n'); + const char* line_end = (const char*)memchr(line, '\n', text_end - line); if (!line_end) line_end = text_end; line = line_end + 1; @@ -169,15 +170,15 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height)); while (line < text_end) { - const char* line_end = strchr(line, '\n'); if (IsClippedEx(line_rect, 0, false)) break; + const char* line_end = (const char*)memchr(line, '\n', text_end - line); + if (!line_end) + line_end = text_end; const ImVec2 line_size = CalcTextSize(line, line_end, false); text_size.x = ImMax(text_size.x, line_size.x); RenderText(pos, line, line_end, false); - if (!line_end) - line_end = text_end; line = line_end + 1; line_rect.Min.y += line_height; line_rect.Max.y += line_height; @@ -188,7 +189,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) int lines_skipped = 0; while (line < text_end) { - const char* line_end = strchr(line, '\n'); + const char* line_end = (const char*)memchr(line, '\n', text_end - line); if (!line_end) line_end = text_end; line = line_end + 1;