| 2949 | } |
| 2950 | |
| 2951 | void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const |
| 2952 | { |
| 2953 | if (!text_end) |
| 2954 | text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. |
| 2955 | |
| 2956 | // Align to be pixel perfect |
| 2957 | pos.x = IM_FLOOR(pos.x + DisplayOffset.x); |
| 2958 | pos.y = IM_FLOOR(pos.y + DisplayOffset.y); |
| 2959 | float x = pos.x; |
| 2960 | float y = pos.y; |
| 2961 | if (y > clip_rect.w) |
| 2962 | return; |
| 2963 | |
| 2964 | const float scale = size / FontSize; |
| 2965 | const float line_height = FontSize * scale; |
| 2966 | const bool word_wrap_enabled = (wrap_width > 0.0f); |
| 2967 | const char* word_wrap_eol = NULL; |
| 2968 | |
| 2969 | // Fast-forward to first visible line |
| 2970 | const char* s = text_begin; |
| 2971 | if (y + line_height < clip_rect.y && !word_wrap_enabled) |
| 2972 | while (y + line_height < clip_rect.y && s < text_end) |
| 2973 | { |
| 2974 | s = (const char*)memchr(s, '\n', text_end - s); |
| 2975 | s = s ? s + 1 : text_end; |
| 2976 | y += line_height; |
| 2977 | } |
| 2978 | |
| 2979 | // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve() |
| 2980 | // 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) |
| 2981 | if (text_end - s > 10000 && !word_wrap_enabled) |
| 2982 | { |
| 2983 | const char* s_end = s; |
| 2984 | float y_end = y; |
| 2985 | while (y_end < clip_rect.w && s_end < text_end) |
| 2986 | { |
| 2987 | s_end = (const char*)memchr(s_end, '\n', text_end - s_end); |
| 2988 | s_end = s_end ? s_end + 1 : text_end; |
| 2989 | y_end += line_height; |
| 2990 | } |
| 2991 | text_end = s_end; |
| 2992 | } |
| 2993 | if (s == text_end) |
| 2994 | return; |
| 2995 | |
| 2996 | // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized) |
| 2997 | const int vtx_count_max = (int)(text_end - s) * 4; |
| 2998 | const int idx_count_max = (int)(text_end - s) * 6; |
| 2999 | const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; |
| 3000 | draw_list->PrimReserve(idx_count_max, vtx_count_max); |
| 3001 | |
| 3002 | ImDrawVert* vtx_write = draw_list->_VtxWritePtr; |
| 3003 | ImDrawIdx* idx_write = draw_list->_IdxWritePtr; |
| 3004 | unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; |
| 3005 | |
| 3006 | while (s < text_end) |
| 3007 | { |
| 3008 | if (word_wrap_enabled) |
no test coverage detected