Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
| 4013 | |
| 4014 | // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. |
| 4015 | void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const |
| 4016 | { |
| 4017 | if (!text_end) |
| 4018 | text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. |
| 4019 | |
| 4020 | // Align to be pixel perfect |
| 4021 | float x = IM_TRUNC(pos.x); |
| 4022 | float y = IM_TRUNC(pos.y); |
| 4023 | if (y > clip_rect.w) |
| 4024 | return; |
| 4025 | |
| 4026 | const float start_x = x; |
| 4027 | const float scale = size / FontSize; |
| 4028 | const float line_height = FontSize * scale; |
| 4029 | const bool word_wrap_enabled = (wrap_width > 0.0f); |
| 4030 | |
| 4031 | // Fast-forward to first visible line |
| 4032 | const char* s = text_begin; |
| 4033 | if (y + line_height < clip_rect.y) |
| 4034 | while (y + line_height < clip_rect.y && s < text_end) |
| 4035 | { |
| 4036 | const char* line_end = (const char*)memchr(s, '\n', text_end - s); |
| 4037 | if (word_wrap_enabled) |
| 4038 | { |
| 4039 | // FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA(). |
| 4040 | // If the specs for CalcWordWrapPositionA() were reworked to optionally return on \n we could combine both. |
| 4041 | // However it is still better than nothing performing the fast-forward! |
| 4042 | s = CalcWordWrapPositionA(scale, s, line_end ? line_end : text_end, wrap_width); |
| 4043 | s = CalcWordWrapNextLineStartA(s, text_end); |
| 4044 | } |
| 4045 | else |
| 4046 | { |
| 4047 | s = line_end ? line_end + 1 : text_end; |
| 4048 | } |
| 4049 | y += line_height; |
| 4050 | } |
| 4051 | |
| 4052 | // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve() |
| 4053 | // Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer without a newline will likely crash atm) |
| 4054 | if (text_end - s > 10000 && !word_wrap_enabled) |
| 4055 | { |
| 4056 | const char* s_end = s; |
| 4057 | float y_end = y; |
| 4058 | while (y_end < clip_rect.w && s_end < text_end) |
| 4059 | { |
| 4060 | s_end = (const char*)memchr(s_end, '\n', text_end - s_end); |
| 4061 | s_end = s_end ? s_end + 1 : text_end; |
| 4062 | y_end += line_height; |
| 4063 | } |
| 4064 | text_end = s_end; |
| 4065 | } |
| 4066 | if (s == text_end) |
| 4067 | return; |
| 4068 | |
| 4069 | // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized) |
| 4070 | const int vtx_count_max = (int)(text_end - s) * 4; |
| 4071 | const int idx_count_max = (int)(text_end - s) * 6; |
| 4072 | const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; |
no test coverage detected