Skip to content

Commit 4391214

Browse files
committed
2026Q1 retrospective
1 parent f23cff5 commit 4391214

7 files changed

Lines changed: 395 additions & 12 deletions

File tree

build.el

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
<link rel=\"stylesheet\" href=\"/css/styles.css\">
2828
<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">
2929
<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>
30-
<link href=\"https://fonts.googleapis.com/css2?family=Baskervville:ital,wght@0,400..700;1,400..700&family=Fira+Code:wght@300..700&family=Sen:wght@400..800&display=swap\" rel=\"stylesheet\">
30+
<link href=\"https://fonts.googleapis.com/css2?family=Baskervville:wght@700&family=Fira+Code:wght@300..700&family=Sen:wght@400..800&display=swap\" rel=\"stylesheet\">
3131
"
3232
;; When doing syntax highlighting, output as CSS classes instead of the default
3333
;; inline CSS. The color theme is defined in ./content/css/htmlize-styles.css. To get

content/css/styles.css

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ th {
6363
font-size: 18px;
6464
}
6565
h1, h2, h3, h4, h5, h6 {
66-
font-family: "Baskervville";
66+
font-family: "Baskervville", serif;
6767
}
6868
h1 { font-size: 36px; }
6969
h2 { font-size: 32px; }
@@ -80,14 +80,24 @@ label.org-src-name {
8080
font-size: 14px;
8181
color: #666666;
8282
}
83-
code, pre {
84-
font-family: "Fira Code";
83+
.post-date {
8584
font-size: 14px;
85+
color: #666666;
8686
}
87-
code {
87+
.figure p {
88+
margin: 0 !important;
8889
font-size: 14px;
89-
border: 1px solid #e5e5e5;
90+
color: #666666;
91+
}
92+
div.figure {
93+
margin: 1.5rem 0;
94+
}
95+
code, pre {
96+
font-family: "Fira Code", monospace;
97+
font-size: 14px;
98+
9099
}
100+
code {border: 1px solid #e5e5e5;}
91101
div.org-src-container {
92102
margin: 1rem 0;
93103
}

content/index.org

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,21 @@
33

44
* Recent
55

6+
[[file:post/2026/04/11/fonts-q1.org][Fonts Q1]] @@html:<span class="post-date">2026-04-11</span>@@
7+
68
[[file:post/2026/03/31/function-ptrs.org][Functional Dispatch]] @@html:<span class="post-date">2026-03-31</span>@@
79

810
[[file:post/2026/02/21/lisp-3.org][Building a Lisp Interpreter (with Rust) Part 3]] @@html:<span class="post-date">2026-02-21</span>@@
911

1012
[[file:post/2026/01/25/lisp-2.org][Building a Lisp Interpreter (with Rust) Part 2]] @@html:<span class="post-date">2026-01-25</span>@@
1113

12-
[[file:post/2026/01/14/2025-recap.org][2025 Recap]] @@html:<span class="post-date">2026-01-14</span>@@
13-
1414

1515
* Archive
1616

1717
** General
1818

1919
[[file:post/2026/03/31/function-ptrs.org][Functional Dispatch]] @@html:<span class="post-date">2026-03-31</span>@@
2020

21-
[[file:post/2026/01/14/2025-recap.org][2025 Recap]] @@html:<span class="post-date">2026-01-14</span>@@
22-
2321
[[file:post/2024/12/18/new-years-resolution-evaluation-reading.org][New Years Resolution Evaluation - Reading]] @@html:<span class="post-date">2024-12-18</span>@@
2422

2523
[[file:post/2024/08/22/zigging-out.org][Zigging Out]] @@html:<span class="post-date">2024-08-22</span>@@
@@ -28,6 +26,11 @@
2826

2927
[[file:post/2024/05/13/github-gitlab.org][GitHub or GitLab for Hobby Projects]] @@html:<span class="post-date">2024-05-13</span>@@
3028

29+
** Retrospectives
30+
31+
[[file:post/2026/04/11/fonts-q1.org][Fonts Q1]] @@html:<span class="post-date">2026-04-11</span>@@
32+
33+
[[file:post/2026/01/14/2025-recap.org][2025 Recap]] @@html:<span class="post-date">2026-01-14</span>@@
3134

3235
** Tutorials
3336

content/post/2026/03/31/function-ptrs.org

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Tiny Skia compiles to a ~Context~ to store parameters and a sequence of simple
3434
enums is converted into a sequence of function pointers that run one after
3535
another.
3636

37-
#+CAPTION: Implementation of the ~Transform~ step. It tweaks some registers and moves on to the next stage.
37+
#+CAPTION: Implementation of the Transform step. It tweaks some registers and moves on to the next stage.
3838
#+BEGIN_SRC rust
3939
fn transform(p: &mut Pipeline) {
4040
let ts = &p.ctx.transform;
@@ -658,7 +658,7 @@ if let (
658658

659659
// The combined instruction sits at the LoadLocal(0) slot, so the jump offset
660660
// must be increased by 2 to reach the same target as the original JumpIf.
661-
data.extend_from_slice(&[n.wrapping_add(2) as u8, 0, 0]);
661+
data.extend_from_slice(&[n as u8 + 2, 0, 0]);
662662
i += 3;
663663
continue;
664664
}
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
#+title: Fonts Q1
2+
#+date: <2026-04-11 Sat>
3+
#+author: Will S. Medrano
4+
5+
* Introduction
6+
:PROPERTIES:
7+
:ID: 8441fc9d-1865-439c-95de-5de5833e41f0
8+
:END:
9+
10+
I just completed my first full quarter on my new team[fn:startdate], the Google
11+
Fonts team. It went about as I expected; I learned a lot of stuff, but wish I
12+
had learned it all faster.
13+
14+
So what does the Google Fonts team do? Quite a bit of random stuff here and
15+
there, some of it internal to Google, and some of it open source. It's easy to
16+
talk about the more open stuff than the internal.
17+
18+
** Google Fonts
19+
:PROPERTIES:
20+
:ID: eae09021-7a19-4c3f-acd7-c48c0c58f804
21+
:END:
22+
23+
The easiest thing to explain under my team's purview is [[https://fonts.google.com/][fonts.google.com]]. You
24+
have probably used this! Many websites load their fonts from the Google Fonts
25+
catalog. Google Fonts lets you browse a catalog of fonts. Once the fonts have
26+
been selected, the site gives you a link to embed the font files into your
27+
website.
28+
29+
#+BEGIN_SRC html
30+
<link rel="preconnect" href="https://fonts.googleapis.com">
31+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
32+
<link href="https://fonts.googleapis.com/css2?family=Baskervville:wght@700&family=Sen:wght@400..800&display=swap" rel="stylesheet">
33+
#+END_SRC
34+
35+
The neat part about the Google Fonts API is that:
36+
37+
1. Google Fonts provides the font hosting. No need to download and serve the fonts.
38+
2. Efficient (enough) formatting. If you look at the generated CSS, you can see
39+
a few different technologies to better serve fonts.
40+
41+
#+CAPTION: Note the use of the efficient /woff2/ format and splitting the font based on the =unicode-range= to split the font into pieces. On the day this was written, only the /latin/ unicode ranges are needed.
42+
#+BEGIN_SRC css
43+
/* latin-ext */
44+
@font-face {
45+
font-family: 'Baskervville';
46+
font-style: normal;
47+
font-weight: 700;
48+
src: url(https://fonts.gstatic.com/s/baskervville/v20/YA9Br0yU4l_XOrogbkun3kQ6vLFYXmpq8sRsYgfsigq4dC1F.woff2) format('woff2');
49+
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
50+
}
51+
/* latin */
52+
@font-face {
53+
font-family: 'Baskervville';
54+
font-style: normal;
55+
font-weight: 700;
56+
src: url(https://fonts.gstatic.com/s/baskervville/v20/YA9Br0yU4l_XOrogbkun3kQ6vLFYXmpq8sRsYgfsigS4dA.woff2) format('woff2');
57+
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
58+
}
59+
/* latin-ext */
60+
@font-face {
61+
font-family: 'Sen';
62+
font-style: normal;
63+
font-weight: 400 800;
64+
src: url(https://fonts.gstatic.com/s/sen/v12/6xKjdSxYI9_3kvWNEmo.woff2) format('woff2');
65+
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
66+
}
67+
/* latin */
68+
@font-face {
69+
font-family: 'Sen';
70+
font-style: normal;
71+
font-weight: 400 800;
72+
src: url(https://fonts.gstatic.com/s/sen/v12/6xKjdSxYI9_3nPWN.woff2) format('woff2');
73+
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
74+
}
75+
#+END_SRC
76+
77+
** Font Compiler
78+
:PROPERTIES:
79+
:ID: 346f6172-0f28-4b18-b41f-a27789e7c580
80+
:END:
81+
82+
Google maintains and develops [[https://github.com/googlefonts/fontc][fontc]], a Rust-based compiler that takes font sources
83+
and converts them into ttf/otf files. It's a lot quicker than the previous Python
84+
font compiler, [[https://github.com/googlefonts/fontmake][fontmake]], which was also developed and maintained by Google.
85+
86+
** Fontations
87+
:PROPERTIES:
88+
:ID: 412ffb16-9652-4652-bb99-d3abac6383b3
89+
:END:
90+
91+
The Rust [[https://github.com/googlefonts/fontations][Fontations]] libraries provide a foundation to read and write font
92+
data. This library is used in =fontc= as well as Skia, the 2D graphics engine
93+
used by Chrome, Chromium, Firefox, and Android.
94+
95+
* Accomplishments
96+
:PROPERTIES:
97+
:ID: b806dbeb-ba06-497c-8f8d-3d733cff1d16
98+
:END:
99+
100+
I'll go over my accomplishments. Most of what I did was open source, though I
101+
did do some uneventful internal-only changes as well.
102+
103+
** colrv1/RadialGradients
104+
105+
*** Task
106+
107+
My starter project was to fix [[https://github.com/googlefonts/sleipnir][Sleipnir]] rendering of color fonts like
108+
[[https://fonts.google.com/specimen/Nabla?query=nabla&preview.script=Latn][Nabla]]. Sleipnir is a Rust library that can render text and icons into png or
109+
svg.
110+
111+
This one was quite a rabbit hole. The most important skill I picked up was
112+
understanding the font format. Fonts (ttf/otf files) are composed of tables. The
113+
tables define things such as contours, supported unicodes, ligatures, kerning,
114+
and lots of other stuff; it's a fairly extensible format.
115+
116+
To inspect the contents of a font, you can open it with the =ttx= command from
117+
[[https://github.com/fonttools/fonttools][fonttools]]. This produces an =xml= representation of the tables. To help me out,
118+
I even made an Emacs package that adds the ability to open ttf, otf, and
119+
woff2[fn:woff2] font files. Check out [[https://github.com/wmedrano/ttx-mode][=ttx-mode=]] if interested.
120+
121+
*** Detour
122+
123+
It turns out that getting Nabla to work was not too complicated. However, the
124+
underlying 2D graphics library did not have the full expressiveness of Radial
125+
Gradients and was missing Sweep Gradients entirely. I originally was going to
126+
leave it as is, but my manager encouraged me to continue. So I ended up learning
127+
some math and implementing [[https://github.com/linebender/tiny-skia/pull/164][radial gradient]] and [[https://github.com/linebender/tiny-skia/pull/166][sweep gradients]].
128+
129+
What's rewarding about this is that it affects a few other users. Once /typst/
130+
updates their dependencies, they should have better gradients ([[https://github.com/typst/typst/issues/7760][issues]]). I also
131+
[[https://github.com/linebender/resvg/pull/1014][completed]] /resvg/ integration to better render radial gradients. Both of these
132+
are pretty popular open source tools.
133+
134+
** IFT Support for TTX
135+
:PROPERTIES:
136+
:ID: 3642f9d0-72a4-417b-b4b1-8e39420c65f4
137+
:END:
138+
139+
*** Background
140+
:PROPERTIES:
141+
:ID: 5bb31103-5b81-476f-a9d3-079015baac71
142+
:END:
143+
144+
The main project I should be working on at the moment is landing IFT on the
145+
client. I said should since I've spent most of this quarter procrastinating and
146+
failing to comprehend specs. At least I've made a bit of progress.
147+
148+
IFT stands for Incremental Font Transfer. It is a font technology that
149+
theoretically enables more efficient transfer of fonts. One of my coworkers has
150+
been working on the spec and prototype for a while. He's done a great job at
151+
authoring the [[https://www.w3.org/TR/IFT/][W3 Spec]] for it.
152+
153+
IFT requires 2 components:
154+
155+
1. A font must be IFT encoded. This splits the font into a base font and a
156+
collection of patches.
157+
2. Client support. Clients (web browsers) must be able to request and apply the
158+
patches as needed.
159+
160+
#+BEGIN_SRC dot :file ift-encoder.svg :exports results
161+
digraph IFT {
162+
rankdir=LR;
163+
node [fontname="sans-serif"; fontsize=12; shape=record;];
164+
font [label="Font File"];
165+
base [label="Base Font"];
166+
patches [label="Patch 0|Patch 1|⋮|Patch N"];
167+
encoder [label="IFT\nEncoder"];
168+
font -> encoder;
169+
encoder -> base;
170+
encoder -> patches;
171+
}
172+
#+END_SRC
173+
174+
#+CAPTION: The encoder converts a font file into a font and its patches.
175+
#+RESULTS:
176+
[[file:ift-encoder.svg]]
177+
178+
#+BEGIN_SRC dot :file ift-client.svg :exports results
179+
digraph IFTClient {
180+
rankdir=LR;
181+
node [fontname="sans-serif"; fontsize=12; shape=record;];
182+
183+
webpage [label="Web Page"];
184+
browser [label="Browser"];
185+
186+
subgraph cluster_cdn {
187+
label="CDN";
188+
style="rounded";
189+
color=gray;
190+
fontname="sans-serif";
191+
fontsize=12;
192+
193+
basefont [label="Base Font"];
194+
patches [label="Patches"];
195+
}
196+
197+
webpage -> browser;
198+
basefont -> browser;
199+
patches -> browser;
200+
}
201+
#+END_SRC
202+
203+
#+CAPTION: The client must download and apply the relevant patches at runtime.
204+
#+RESULTS:
205+
[[file:ift-client.svg]]
206+
207+
So why is it useful to split up a font? This is all to reduce download sizes and
208+
make things load quickly and more consistently. When using a font, a web page
209+
may not need all the glyphs (characters) or styles (italic/bold/underline).
210+
211+
*** Actual Deliverables
212+
:PROPERTIES:
213+
:ID: 0894041b-86cb-4551-818e-95c382fee073
214+
:END:
215+
216+
Well, I've been really procrastinating on this since it's rather
217+
intimidating. I've read some spec, IFT code, and Chromium code, but that's not
218+
really a deliverable[fn:ift-progress].
219+
220+
However, at the end of the quarter I managed to squeeze in =fonttools= support
221+
([[https://github.com/fonttools/fonttools/pull/4072][PR]]). This allows us to inspect the =IFT= table with the very useful =ttx=
222+
tool[fn:ttx]. This is useful for debugging the feature as =IFT= contains all the
223+
metadata for defining the available patches.
224+
225+
*** Next
226+
:PROPERTIES:
227+
:ID: ac6005e1-8823-4c19-be1e-b92839a10764
228+
:END:
229+
230+
I will continue to read the Chromium code and implement IFT support. My main
231+
goal is to have a deep understanding of this problem by the end of Q2.
232+
233+
* Footnotes
234+
:PROPERTIES:
235+
:ID: 94bb74e4-b31a-4b91-bc53-55343586c83d
236+
:END:
237+
238+
[fn:startdate] I actually started on the team in late November, but it's a short
239+
quarter between all the holidays, nobody being present, and some unexpected sick
240+
days💩.
241+
242+
[fn:woff2] A woff2 font is just a compressed version of a font.
243+
244+
[fn:ift-progress] At the time this was written, my grasp is a lot better. That's
245+
a relief, but it would be a 2026Q2 update!
246+
247+
[fn:ttx] You know, the thing I talked about earlier. The font file to xml
248+
converter.

0 commit comments

Comments
 (0)