Skip to content

Commit

Permalink
Add text drawing style bindings to ctx2d
Browse files Browse the repository at this point in the history
  • Loading branch information
thetarnav committed May 7, 2024
1 parent 47dadf5 commit 98cece2
Show file tree
Hide file tree
Showing 2 changed files with 248 additions and 16 deletions.
148 changes: 140 additions & 8 deletions wasm/ctx2d/ctx2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,89 @@ export function Ctx2d_State() {
}

/** @type {Record<number, CanvasFillRule>} */
const CANVAS_FILL_RULE = {
const FILL_RULE = {
0: "nonzero",
1: "evenodd",
}

/** @type {Record<number, CanvasLineCap>} */
const CANVAS_LINE_CAP = {
const LINE_CAP = {
0: "butt",
1: "round",
2: "square",
}

/** @type {Record<number, CanvasLineJoin>} */
const CANVAS_LINE_JOIN = {
const LINE_JOIN = {
0: "miter",
1: "round",
2: "bevel",
}

/** @type {Record<number, CanvasDirection>} */
const DIRECTION = {
0: "inherit",
1: "ltr",
2: "rtl",
}

/** @type {Record<number, CanvasFontKerning>} */
const FONT_KERNING = {
0: "auto",
1: "none",
2: "normal",
}

/** @type {Record<number, CanvasFontStretch>} */
const FONT_STRETCH = {
0: "normal",
1: "ultra-condensed",
2: "extra-condensed",
3: "condensed",
4: "semi-condensed",
5: "semi-expanded",
6: "expanded",
7: "extra-expanded",
8: "ultra-expanded",
}

/** @type {Record<number, CanvasFontVariantCaps>} */
const FONT_VARIANT_CAPS = {
0: "normal",
1: "petite-caps",
2: "all-petite-caps",
3: "small-caps",
4: "all-small-caps",
5: "titling-caps",
6: "unicase",
}

/** @type {Record<number, CanvasTextAlign>} */
const TEXT_ALIGN = {
0: "start",
1: "end",
2: "left",
3: "right",
4: "center",
}

/** @type {Record<number, CanvasTextBaseline>} */
const TEXT_BASELINE = {
0: "alphabetic",
1: "top",
2: "hanging",
3: "middle",
4: "ideographic",
5: "bottom",
}

/** @type {Record<number, CanvasTextRendering>} */
const TEXT_RENDERING = {
0: "auto",
1: "optimizeSpeed",
2: "optimizeLegibility",
3: "geometricPrecision",
}

/**
* @param {Wasm_State} wasm
Expand Down Expand Up @@ -110,15 +174,15 @@ export function make_odin_ctx2d(wasm, s) {
clip(
/** @type {number} */ fill_rule,
) {
s.ctx.clip(CANVAS_FILL_RULE[fill_rule]);
s.ctx.clip(FILL_RULE[fill_rule]);
},
/**
* Fills the current path.
* @returns {void} */
fill(
/** @type {number} */ fill_rule,
) {
s.ctx.fill(CANVAS_FILL_RULE[fill_rule])
s.ctx.fill(FILL_RULE[fill_rule])
},
/**
* Checks if the given point is inside the current path.
Expand All @@ -128,7 +192,7 @@ export function make_odin_ctx2d(wasm, s) {
/** @type {number} */ y,
/** @type {number} */ fill_rule,
) {
return s.ctx.isPointInPath(x, y, CANVAS_FILL_RULE[fill_rule])
return s.ctx.isPointInPath(x, y, FILL_RULE[fill_rule])
},
/**
* Checks if the given point is inside the current stroke.
Expand Down Expand Up @@ -278,7 +342,7 @@ export function make_odin_ctx2d(wasm, s) {
lineCap(
/** @type {number} */ cap,
) {
s.ctx.lineCap = CANVAS_LINE_CAP[cap]
s.ctx.lineCap = LINE_CAP[cap]
},
/** @returns {void} */
lineDashOffset(
Expand All @@ -290,7 +354,7 @@ export function make_odin_ctx2d(wasm, s) {
lineJoin(
/** @type {number} */ join,
) {
s.ctx.lineJoin = CANVAS_LINE_JOIN[join]
s.ctx.lineJoin = LINE_JOIN[join]
},
/** @returns {void} */
lineWidth(
Expand Down Expand Up @@ -451,5 +515,73 @@ export function make_odin_ctx2d(wasm, s) {
mem.store_offset_f32(data, offset, metrics.ideographicBaseline)
mem.store_offset_f32(data, offset, metrics.width)
},

// ------------------------------ /
// TEXT DRAWING STYLES /
// ------------------------------ /

/** @returns {void} */
direction(
/** @type {number} */ value,
) {
s.ctx.direction = DIRECTION[value]
},
/** @returns {void} */
font(
/** @type {number} */ ptr,
/** @type {number} */ len,
) {
s.ctx.font = mem.load_string_raw(wasm.memory.buffer, ptr, len)
},
/** @returns {void} */
fontKerning(
/** @type {number} */ value,
) {
s.ctx.fontKerning = FONT_KERNING[value]
},
/** @returns {void} */
fontStretch(
/** @type {number} */ value,
) {
s.ctx.fontStretch = FONT_STRETCH[value]
},
/** @returns {void} */
fontVariantCaps(
/** @type {number} */ value,
) {
s.ctx.fontVariantCaps = FONT_VARIANT_CAPS[value]
},
/** @returns {void} */
letterSpacing(
/** @type {number} */ ptr,
/** @type {number} */ len,
) {
s.ctx.letterSpacing = mem.load_string_raw(wasm.memory.buffer, ptr, len)
},
/** @returns {void} */
textAlign(
/** @type {number} */ value,
) {
s.ctx.textAlign = TEXT_ALIGN[value]
},
/** @returns {void} */
textBaseline(
/** @type {number} */ value,
) {
s.ctx.textBaseline = TEXT_BASELINE[value]
},
/** @returns {void} */
textRendering(
/** @type {number} */ value,
) {
s.ctx.textRendering = TEXT_RENDERING[value]
},
/** @returns {void} */
wordSpacing(
/** @type {number} */ ptr,
/** @type {number} */ len,
) {
s.ctx.wordSpacing = mem.load_string_raw(wasm.memory.buffer, ptr, len)
},
}
}
116 changes: 108 additions & 8 deletions wasm/ctx2d/ctx2d.odin
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package ctx2d

import "core:strconv"

foreign import "ctx2d"

@(default_calling_convention="contextless")
Expand Down Expand Up @@ -51,7 +53,7 @@ foreign ctx2d {
// DRAW PATH /
// ------------------------------ /

CanvasFillRule :: enum {
FillRule :: enum {
nonzero = 0,
evenodd = 1,
}
Expand All @@ -61,11 +63,11 @@ foreign ctx2d {
// Begins a new path.
beginPath :: proc () ---
// Clips the current path.
clip :: proc (fill_rule: CanvasFillRule = .nonzero) ---
clip :: proc (fill_rule: FillRule = .nonzero) ---
// Fills the current path.
fill :: proc (fill_rule: CanvasFillRule = .nonzero) ---
fill :: proc (fill_rule: FillRule = .nonzero) ---
// Checks if the given point is inside the current path.
isPointInPath :: proc (x, y: f32, fill_rule: CanvasFillRule = .nonzero) -> bool ---
isPointInPath :: proc (x, y: f32, fill_rule: FillRule = .nonzero) -> bool ---
// Checks if the given point is inside the current stroke.
isPointInStroke :: proc (x, y: f32) -> bool ---
// Strokes the current path.
Expand Down Expand Up @@ -106,23 +108,23 @@ foreign ctx2d {
// PATH DRAWING STYLES /
// ------------------------------ /

CanvasLineCap :: enum {
LineCap :: enum {
butt = 0,
round = 1,
square = 2,
}

CanvasLineJoin :: enum {
LineJoin :: enum {
miter = 0,
round = 1,
bevel = 2,
}

@(default_calling_convention="contextless")
foreign ctx2d {
lineCap :: proc (cap: CanvasLineCap) ---
lineCap :: proc (cap: LineCap) ---
lineDashOffset :: proc (offset: f32) ---
lineJoin :: proc (join: CanvasLineJoin) ---
lineJoin :: proc (join: LineJoin) ---
lineWidth :: proc (width: f32) ---
miterLimit :: proc (limit: f32) ---
setLineDash :: proc (segments: []f32) ---
Expand Down Expand Up @@ -199,3 +201,101 @@ getTextMetrics :: proc (text: string) -> (metrics: TextMetrics) {
return
}

// ------------------------------ /
// TEXT DRAWING STYLES /
// ------------------------------ /

Direction :: enum {
inherit = 0,
ltr = 1,
rtl = 2,
}

FontKerning :: enum {
auto = 0,
none = 1,
normal = 2,
}

FontStretch :: enum {
normal = 0,
ultra_condensed = 1,
extra_condensed = 2,
condensed = 3,
semi_condensed = 4,
semi_expanded = 5,
expanded = 6,
extra_expanded = 7,
ultra_expanded = 8,
}

FontVariantCaps :: enum {
normal = 0,
petite_caps = 1,
all_petite_caps = 2,
small_caps = 3,
all_small_caps = 4,
titling_caps = 5,
unicase = 6,
}

TextAlign :: enum {
start = 0,
end = 1,
left = 2,
right = 3,
center = 4,
}

TextBaseline :: enum {
alphabetic = 0,
top = 1,
hanging = 2,
middle = 3,
ideographic = 4,
bottom = 5,
}

TextRendering :: enum {
auto = 0,
optimizeSpeed = 1,
optimizeLegibility = 2,
geometricPrecision = 3,
}

@(default_calling_convention="contextless")
foreign ctx2d {
direction :: proc (Direction) ---
font :: proc (string) ---
fontKerning :: proc (FontKerning) ---
fontStretch :: proc (FontStretch) ---
fontVariantCaps :: proc (FontVariantCaps) ---
@(link_name="letterSpacing")
letterSpacingString :: proc (string) ---
textAlign :: proc (TextAlign) ---
textBaseline :: proc (TextBaseline) ---
textRendering :: proc (TextRendering) ---
@(link_name="wordSpacing")
wordSpacingString :: proc (string) ---
}

px_to_string :: proc (buf: []byte, val: int) -> string {
val_str := strconv.append_int(buf, i64(val), 10)
val_len := len(val_str)
buf[val_len+0] = 'p'
buf[val_len+1] = 'x'
return string(buf[:val_len+2])
}

letterSpacingPx :: proc (val: int) {
buf: [32]byte
letterSpacingString(px_to_string(buf[:], val))
}

wordSpacingPx :: proc (val: int) {
buf: [32]byte
wordSpacingString(px_to_string(buf[:], val))
}

letterSpacing :: proc {letterSpacingString, letterSpacingPx}
wordSpacing :: proc {wordSpacingString, wordSpacingPx}

0 comments on commit 98cece2

Please sign in to comment.