Skip to content

Commit

Permalink
karm-gfx+ttf: Reduced the amount of glyphId lookup.
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepy-monax committed Aug 11, 2023
1 parent 9ff6373 commit 19db5ea
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 57 deletions.
2 changes: 1 addition & 1 deletion src/libs/karm-base/distinct.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ struct Distinct {

constexpr Distinct() = default;

constexpr Distinct(T value) : _value(value) {}
constexpr explicit Distinct(T value) : _value(value) {}

constexpr T value() const { return _value; }

Expand Down
31 changes: 24 additions & 7 deletions src/libs/karm-gfx/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ void Context::fill(Math::Vec2i pos, Media::Icon icon) {
_useSpaa = false;
}

void Context::stroke(Math::Vec2f baseline, Rune rune) {
void Context::stroke(Math::Vec2f baseline, Media::Glyph rune) {
auto f = textFont();

_useSpaa = true;
Expand All @@ -312,7 +312,7 @@ void Context::stroke(Math::Vec2f baseline, Rune rune) {
_useSpaa = false;
}

void Context::fill(Math::Vec2f baseline, Rune rune) {
void Context::fill(Math::Vec2f baseline, Media::Glyph rune) {
auto f = textFont();

_useSpaa = true;
Expand All @@ -326,20 +326,37 @@ void Context::fill(Math::Vec2f baseline, Rune rune) {
_useSpaa = false;
}

void Context::stroke(Math::Vec2f baseline, Rune rune) {
stroke(baseline, textFont().glyph(rune));
}

void Context::fill(Math::Vec2f baseline, Rune rune) {
fill(baseline, textFont().glyph(rune));
}

void Context::stroke(Math::Vec2f baseline, Str str) {
auto f = textFont();
for (auto r : iterRunes(str)) {
stroke(baseline, r);
baseline.x += f.advance(r);

bool first = true;
Media::Glyph prev{0};
for (auto rune : iterRunes(str)) {
auto curr = f.glyph(rune);
if (not first)
baseline.x += f.kern(prev, curr);
stroke(baseline, curr);
baseline.x += f.advance(curr);
first = false;
prev = curr;
}
}

void Context::fill(Math::Vec2f baseline, Str str) {
auto f = textFont();

bool first = true;
Rune prev = 0;
for (auto curr : iterRunes(str)) {
Media::Glyph prev{0};
for (auto rune : iterRunes(str)) {
auto curr = f.glyph(rune);
if (not first)
baseline.x += f.kern(prev, curr);
fill(baseline, curr);
Expand Down
6 changes: 6 additions & 0 deletions src/libs/karm-gfx/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@ struct Context {
// Fill an icon
void fill(Math::Vec2i pos, Media::Icon icon);

// Stroke a text glyph
void stroke(Math::Vec2f baseline, Media::Glyph glyph);

// Fill a text glyph
void fill(Math::Vec2f baseline, Media::Glyph glyph);

// Stroke a text rune
void stroke(Math::Vec2f baseline, Rune rune);

Expand Down
14 changes: 9 additions & 5 deletions src/libs/karm-media/font-ttf.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,20 @@ struct TtfFontface : public Fontface {
};
}

f64 advance(Rune c) const override {
return _ttf.glyphMetrics(c).advance;
Glyph glyph(Rune rune) const override {
return _ttf.glyph(rune);
}

f64 kern(Rune prev, Rune curr) const override {
f64 advance(Glyph glyph) const override {
return _ttf.glyphMetrics(glyph).advance;
}

f64 kern(Glyph prev, Glyph curr) const override {
return _ttf.glyphKern(prev, curr);
}

void contour(Gfx::Context &g, Rune rune) const override {
_ttf.glyphContour(g, rune);
void contour(Gfx::Context &g, Glyph glyph) const override {
_ttf.glyphContour(g, glyph);
}

f64 units() const override {
Expand Down
17 changes: 10 additions & 7 deletions src/libs/karm-media/font-vga.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,24 @@ struct VgaFontface : public Fontface {
};
}

f64 advance(Rune) const override {
Glyph glyph(Rune rune) const override {
One<Ibm437> one;
encodeOne<Ibm437>(rune, one);
return Glyph(one);
}

f64 advance(Glyph) const override {
return 8;
}

f64 kern(Rune, Rune) const override {
f64 kern(Glyph, Glyph) const override {
return 0;
}

void contour(Gfx::Context &g, Rune rune) const override {
One<Ibm437> one;
encodeOne<Ibm437>(rune, one);

void contour(Gfx::Context &g, Glyph glyph) const override {
for (isize y = 0; y < HEIGHT; y++) {
for (isize x = 0; x < WIDTH; x++) {
u8 byte = DATA[one * HEIGHT + y];
u8 byte = DATA[glyph.value() * HEIGHT + y];
if (byte & (0x80 >> x)) {
g.rect(Math::Recti{x, y - 8, 1, 1}.cast<f64>());
}
Expand Down
14 changes: 9 additions & 5 deletions src/libs/karm-media/font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,19 @@ FontMetrics Font::metrics() const {
return m;
}

f64 Font::advance(Rune c) const {
return fontface->advance(c) * scale();
Glyph Font::glyph(Rune rune) const {
return fontface->glyph(rune);
}

f64 Font::kern(Rune prev, Rune curr) const {
f64 Font::advance(Glyph glyph) const {
return fontface->advance(glyph) * scale();
}

f64 Font::kern(Glyph prev, Glyph curr) const {
return fontface->kern(prev, curr) * scale();
}

FontMesure Font::mesureRune(Rune r) const {
FontMesure Font::mesure(Glyph r) const {
auto m = metrics();
auto adv = advance(r);

Expand All @@ -54,7 +58,7 @@ FontMesure Font::mesureRune(Rune r) const {
FontMesure Font::mesureStr(Str str) const {
f64 adv = 0;
for (auto r : iterRunes(str)) {
adv += advance(r);
adv += advance(glyph(r));
}

auto m = metrics();
Expand Down
19 changes: 13 additions & 6 deletions src/libs/karm-media/font.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <karm-base/distinct.h>
#include <karm-base/rc.h>
#include <karm-math/rect.h>

Expand Down Expand Up @@ -74,18 +75,22 @@ struct FontMesure {
Math::Vec2f baseline;
};

using Glyph = Distinct<usize, struct _GlyphTag>;

struct Fontface {
static Strong<Fontface> fallback();

virtual ~Fontface() = default;

virtual FontMetrics metrics() const = 0;

virtual f64 advance(Rune c) const = 0;
virtual Glyph glyph(Rune rune) const = 0;

virtual f64 advance(Glyph glyph) const = 0;

virtual f64 kern(Rune prev, Rune curr) const = 0;
virtual f64 kern(Glyph prev, Glyph curr) const = 0;

virtual void contour(Gfx::Context &g, Rune rune) const = 0;
virtual void contour(Gfx::Context &g, Glyph glyph) const = 0;

virtual f64 units() const = 0;
};
Expand All @@ -101,11 +106,13 @@ struct Font {

FontMetrics metrics() const;

f64 advance(Rune c) const;
Glyph glyph(Rune rune) const;

f64 advance(Glyph glyph) const;

f64 kern(Rune prev, Rune curr) const;
f64 kern(Glyph prev, Glyph curr) const;

FontMesure mesureRune(Rune r) const;
FontMesure mesure(Glyph glyph) const;

FontMesure mesureStr(Str str) const;
};
Expand Down
4 changes: 2 additions & 2 deletions src/libs/karm-media/icon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ void Icon::fill(Gfx::Context &g, Math::Vec2i pos) const {
g.begin();
g.origin(pos + Math::Vec2i{0, (isize)(face->metrics().ascend * scale)});
g.scale(scale);
face->contour(g, (Rune)_code);
face->contour(g, face->glyph((Rune)_code));
g.fill();
g.restore();
}
Expand All @@ -33,7 +33,7 @@ void Icon::stroke(Gfx::Context &g, Math::Vec2i pos) const {
g.begin();
g.origin(pos + Math::Vec2i{0, (isize)(face->metrics().ascend * scale)});
g.scale(scale);
face->contour(g, (Rune)_code);
face->contour(g, face->glyph((Rune)_code));
g.stroke();
g.restore();
}
Expand Down
24 changes: 11 additions & 13 deletions src/specs/ttf/spec.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,14 @@ struct Font {
return Error::other("table not found");
}

GlyphMetrics glyphMetrics(Rune rune) const {
auto glyphId = _cmapTable.glyphIdFor(rune);
Media::Glyph glyph(Rune rune) const {
return _cmapTable.glyphIdFor(rune);
}

auto glyfOffset = _loca.glyfOffset(glyphId, _head);
GlyphMetrics glyphMetrics(Media::Glyph glyph) const {
auto glyfOffset = _loca.glyfOffset(glyph.value(), _head);
auto glyf = _glyf.metrics(glyfOffset);
auto hmtx = _hmtx.metrics(glyphId, _hhea);
auto hmtx = _hmtx.metrics(glyph.value(), _hhea);

return {
(f64)glyf.xMin,
Expand All @@ -196,26 +198,22 @@ struct Font {
};
}

f64 glyphKern(Rune prev, Rune curr) const {
f64 glyphKern(Media::Glyph prev, Media::Glyph curr) const {
if (not _gpos.present())
return 0;

auto prevGlyphId = _cmapTable.glyphIdFor(prev);
auto currGlyphId = _cmapTable.glyphIdFor(curr);

auto positioning = _gpos.adjustments(prevGlyphId, currGlyphId);
auto positioning = _gpos.adjustments(prev.value(), curr.value());

if (not positioning)
return 0;

return positioning.unwrap().car.xAdvance;
}

void glyphContour(Gfx::Context &g, Rune rune) const {
auto glyphId = _cmapTable.glyphIdFor(rune);
auto glyfOffset = _loca.glyfOffset(glyphId, _head);
void glyphContour(Gfx::Context &g, Media::Glyph glyph) const {
auto glyfOffset = _loca.glyfOffset(glyph.value(), _head);

if (glyfOffset == _loca.glyfOffset(glyphId + 1, _head))
if (glyfOffset == _loca.glyfOffset(glyph.value() + 1, _head))
return;

_glyf.contour(g, glyfOffset);
Expand Down
23 changes: 12 additions & 11 deletions src/specs/ttf/table-cmap.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <karm-logger/logger.h>
#include <karm-media/font.h>

#include "../bscan.h"

Expand All @@ -20,7 +21,7 @@ struct Cmap : public BChunk {
return slice;
}

usize _glyphIdForType4(Rune r) const {
Media::Glyph _glyphIdForType4(Rune r) const {
u16 segCountX2 = begin().skip(6).nextU16be();
u16 segCount = segCountX2 / 2;

Expand All @@ -42,18 +43,18 @@ struct Cmap : public BChunk {
u16 idRangeOffset = s.skip(segCountX2).peekU16be();

if (idRangeOffset == 0) {
return (r + idDelta) & 0xFFFF;
} else {
auto offset = idRangeOffset + (r - startCode) * 2;
return s.skip(offset).nextU16be();
return Media::Glyph((r + idDelta) & 0xFFFF);
}

auto offset = idRangeOffset + (r - startCode) * 2;
return Media::Glyph(s.skip(offset).nextU16be());
}

logWarn("ttf: Glyph not found for rune {x}", r);
return 0;
return Media::Glyph(0);
}

usize _glyphForType12(Rune r) const {
Media::Glyph _glyphForType12(Rune r) const {
auto s = begin().skip(12);
u32 nGroups = s.nextU32be();

Expand All @@ -69,21 +70,21 @@ struct Cmap : public BChunk {
continue;

if (r >= startCode and r <= endCode) {
return (r - startCode) + glyphOffset;
return Media::Glyph((r - startCode) + glyphOffset);
}
}

logWarn("ttf: glyph not found for rune {x}", r);
return 0;
return Media::Glyph(0);
}

usize glyphIdFor(Rune r) const {
Media::Glyph glyphIdFor(Rune r) const {
if (type == 4) {
return _glyphIdForType4(r);
} else if (type == 12) {
return _glyphForType12(r);
} else {
return 0;
return Media::Glyph(0);
}
}
};
Expand Down

0 comments on commit 19db5ea

Please sign in to comment.