A rendering engine library for Go supporting both SDL2 and WebAssembly (HTML Canvas) targets.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.3 KiB

  1. package canvas
  2. // Text rendering functions using the HTML 5 canvas.
  3. import (
  4. "fmt"
  5. "path/filepath"
  6. "strings"
  7. "git.kirsle.net/apps/doodle/lib/render"
  8. )
  9. // FontFilenameToName converts a FontFilename to its CSS font name.
  10. //
  11. // The CSS font name is set to the base of the filename, without the .ttf
  12. // file extension. For example, "fonts/DejaVuSans.ttf" uses the CSS font
  13. // family name "DejaVuSans" and that's what this function returns.
  14. //
  15. // Fonts must be defined in the index.html style sheet when serving the
  16. // wasm build of Doodle.
  17. //
  18. // If filename is "", returns "serif" as a sensible default.
  19. func FontFilenameToName(filename string) string {
  20. if filename == "" {
  21. return "DejaVuSans,serif"
  22. }
  23. return strings.TrimSuffix(filepath.Base(filename), filepath.Ext(filename))
  24. }
  25. // DrawText draws text on the canvas.
  26. func (e *Engine) DrawText(text render.Text, point render.Point) error {
  27. font := FontFilenameToName(text.FontFilename)
  28. e.canvas.ctx2d.Set("font",
  29. fmt.Sprintf("%dpx %s,serif", text.Size, font),
  30. )
  31. e.canvas.ctx2d.Set("textBaseline", "top")
  32. write := func(dx, dy int, color render.Color) {
  33. e.canvas.ctx2d.Set("fillStyle", color.ToHex())
  34. e.canvas.ctx2d.Call("fillText",
  35. text.Text,
  36. int(point.X)+dx,
  37. int(point.Y)+dy,
  38. )
  39. }
  40. // Does the text have a stroke around it?
  41. if text.Stroke != render.Invisible {
  42. e.canvas.ctx2d.Set("fillStyle", text.Stroke.ToHex())
  43. write(-1, -1, text.Stroke)
  44. write(-1, 0, text.Stroke)
  45. write(-1, 1, text.Stroke)
  46. write(1, -1, text.Stroke)
  47. write(1, 0, text.Stroke)
  48. write(1, 1, text.Stroke)
  49. write(0, -1, text.Stroke)
  50. write(0, 1, text.Stroke)
  51. }
  52. // Does it have a drop shadow?
  53. if text.Shadow != render.Invisible {
  54. write(1, 1, text.Shadow)
  55. }
  56. // Draw the text itself.
  57. write(0, 0, text.Color)
  58. return nil
  59. }
  60. // ComputeTextRect computes and returns a Rect for how large the text would
  61. // appear if rendered.
  62. func (e *Engine) ComputeTextRect(text render.Text) (render.Rect, error) {
  63. font := FontFilenameToName(text.FontFilename)
  64. e.canvas.ctx2d.Set("font",
  65. fmt.Sprintf("%dpx %s,serif", text.Size, font),
  66. )
  67. measure := e.canvas.ctx2d.Call("measureText", text.Text)
  68. rect := render.Rect{
  69. // TODO: the only TextMetrics widely supported in browsers is
  70. // the width. For height, use the text size for now.
  71. W: int32(measure.Get("width").Int()),
  72. H: int32(text.Size),
  73. }
  74. return rect, nil
  75. }