Skip to content

Commit

Permalink
karm-gfx: Fix edge cases when redering editor caret.
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepy-monax committed Apr 30, 2024
1 parent bd2b302 commit c75f5dd
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 25 deletions.
15 changes: 13 additions & 2 deletions src/libs/karm-gfx/text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ void Text::_measureBlocks() {
first = false;

cell.pos = adv;
adv += _style.font.advance(cell.glyph);
cell.adv = _style.font.advance(cell.glyph);
adv += cell.adv;
prev = cell.glyph;
}
block.width = adv;
Expand Down Expand Up @@ -205,7 +206,17 @@ void Text::paint(Context &ctx) const {
for (auto const &line : sub(_lines, si, ei)) {
for (auto &block : line.blocks(*this)) {
for (auto &cell : block.cells(*this)) {
ctx.fill({block.pos + cell.pos, line.baseline}, cell.glyph);
auto glyph = cell.glyph;

if (glyph == Media::Glyph::TOFU) {
ctx.rect(Math::Rectf::fromTwoPoint(
{block.pos + cell.pos, line.baseline - m.ascend},
{block.pos + cell.pos + cell.adv, line.baseline + m.descend}
));
ctx.stroke();
} else {
ctx.fill({block.pos + cell.pos, line.baseline}, cell.glyph);
}
}
}
}
Expand Down
61 changes: 41 additions & 20 deletions src/libs/karm-gfx/text.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ struct Text {
urange runeRange;
Media::Glyph glyph;
f64 pos = 0; //< Position of the glyph within the block
f64 adv = 0; //< Advance of the glyph

MutSlice<Rune> runes(Text &t) {
return mutSub(t._runes, runeRange);
Expand Down Expand Up @@ -182,51 +183,65 @@ struct Text {

void paintCaret(Context &g, usize runeIndex, Gfx::Color color) const {
auto m = _style.font.metrics();
auto baseline = queryPosition(runeIndex).cast<isize>();
auto cs = baseline - Math::Vec2i{0, (isize)m.ascend};
auto ce = baseline + Math::Vec2i{0, (isize)m.descend};
auto baseline = queryPosition(runeIndex);
auto cs = baseline - Math::Vec2f{0, m.ascend};
auto ce = baseline + Math::Vec2f{0, m.descend};

g.plot(Math::Edgei{cs, ce}, color);
g.moveTo(cs);
g.lineTo(ce);
g.stroke(Gfx::stroke(color).withAlign(Gfx::CENTER_ALIGN).withWidth(2));
}

struct Lbc {
usize li, bi, ci;
};

Lbc lbcAt(usize runeIndex) const {
auto li = searchLowerBound(
auto maybeLi = searchLowerBound(
_lines, [&](Line const &l) {
return l.runeRange.start <=> runeIndex;
}
);

if (not li)
return {};
if (not maybeLi)
return {0, 0, 0};

auto li = *maybeLi;

auto &line = _lines[*li];
auto &line = _lines[li];

auto bi = searchLowerBound(
auto maybeBi = searchLowerBound(
line.blocks(*this), [&](Block const &b) {
return b.runeRange.start <=> runeIndex;
}
);

if (not bi)
return {li.unwrap(), 0, 0};
if (not maybeBi)
return {li, 0, 0};

auto &block = line.blocks(*this)[*bi];
auto bi = *maybeBi;

auto ci = searchLowerBound(
auto &block = line.blocks(*this)[bi];

auto maybeCi = searchLowerBound(
block.cells(*this), [&](Cell const &c) {
return c.runeRange.start <=> runeIndex;
}
);

return {
li.unwrap(),
bi.unwrap(),
tryOr(ci, 0),
};
if (not maybeCi)
return {li, bi, 0};

auto ci = *maybeCi;

auto cell = block.cells(*this)[ci];

if (cell.runeRange.end() == runeIndex) {
// Handle the case where the rune is the last of the text
ci++;
}

return {li, bi, ci};
}

Math::Vec2f queryPosition(usize runeIndex) const {
Expand All @@ -238,12 +253,18 @@ struct Text {
auto &line = _lines[li];

if (isEmpty(line.blocks(*this)))
return {};
return {0, line.baseline};

auto &block = line.blocks(*this)[bi];

if (isEmpty(block.cells(*this)))
return {};
return {block.pos, line.baseline};

if (ci >= block.cells(*this).len()) {
// Handle the case where the rune is the last of the text
auto &cell = last(block.cells(*this));
return {block.pos + cell.pos + cell.adv, line.baseline};
}

auto &cell = block.cells(*this)[ci];

Expand Down
8 changes: 7 additions & 1 deletion src/libs/karm-media/font.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,13 @@ struct FontMeasure {
Math::Vec2f baseline;
};

using Glyph = Distinct<usize, struct _GlyphTag>;
struct Glyph : public Distinct<usize, struct _GlyphTag> {
using Distinct<usize, struct _GlyphTag>::Distinct;

static Glyph const TOFU;
};

constexpr Glyph Glyph::TOFU{Limits<usize>::MIN};

struct Fontface {
static Strong<Fontface> fallback();
Expand Down
4 changes: 2 additions & 2 deletions src/libs/karm-ui/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,8 @@ struct Input : public View<Input> {

auto &text = _ensureText();

text.paint(g);
text.paintCaret(g, _model->_cur.head, Ui::GRAY50);
text.paintCaret(g, _model->_cur.head, Ui::ACCENT500);
text.paint(g);

g.restore();
if (debugShowLayoutBounds)
Expand Down

0 comments on commit c75f5dd

Please sign in to comment.