Re-composite a UTF-8 string into an existing TextBuffer.
Always clears the buffer before compositing. Render bounds and atlas are read from the target buffer. When the target has a pre-allocated vertical budget the compositing bounds are the budget dimensions, so no VKImage rebuild occurs as long as content fits.
321{
322 if (!target) {
323 MF_ERROR(Journal::Component::Portal, Journal::Context::API,
324 "repress: target buffer is null");
325 return false;
326 }
327
328 GlyphAtlas* atlas = resolve_atlas(nullptr);
329 if (!atlas) {
330 return false;
331 }
332
333 target->clear_accumulated_text();
334 target->reset_cursor();
335
336 const uint32_t buf_w = target->get_budget_width();
337 const uint32_t buf_h = target->get_budget_height();
338 const uint32_t bound_h = target->get_render_bounds_h();
339
340 const auto result = composite(text, *atlas, color, buf_w, bound_h,
341 static_cast<float>(atlas->line_height()));
342 if (!result) {
343 MF_WARN(Journal::Component::Portal, Journal::Context::API,
344 "repress: no glyphs produced for '{}'", std::string(text));
345 return false;
346 }
347
348 if (result->h > buf_h && policy == RedrawPolicy::Fit) {
349 const uint32_t new_h = std::min(result->h, bound_h);
350 target->resize_texture(buf_w, new_h);
351 target->set_budget(buf_w, new_h);
352 target->set_pixel_data(result->pixels.data(), result->pixels.size());
353 target->get_cursor_x() = result->cursor_x;
354 target->get_cursor_y() = result->cursor_y;
355 target->set_accumulated_text(text);
356
357 MF_DEBUG(Journal::Component::Portal, Journal::Context::API,
358 "repress(Fit): resized to {}x{}", buf_w, new_h);
359 return true;
360 }
361
362 const size_t buf_bytes = static_cast<size_t>(buf_w) * buf_h * 4;
363 std::vector<uint8_t> cleared(buf_bytes, 0);
364
365 const uint32_t copy_h = std::min(result->h, buf_h);
366 for (uint32_t row = 0; row < copy_h; ++row) {
367 std::memcpy(
368 cleared.data() + static_cast<size_t>(row) * buf_w * 4,
369 result->pixels.data() + static_cast<size_t>(row) * buf_w * 4,
370 static_cast<size_t>(buf_w) * 4);
371 }
372
373 target->set_pixel_data(cleared.data(), buf_bytes);
374 target->get_cursor_x() = result->cursor_x;
375 target->get_cursor_y() = result->cursor_y;
376
377 target->set_accumulated_text(text);
378
379 MF_DEBUG(Journal::Component::Portal, Journal::Context::API,
380 "repress(Clip): '{}' -> {}x{} into {}x{} budget",
381 std::string(text), buf_w, result->h, buf_w, buf_h);
382
383 return true;
384}
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)