Making the Korean and Japanese web beautiful & fast한국어 웹을 아름답고 빠르게
高速で美しい日本語のウェブをWhat is "Google Fonts"?
●

Free, open-source, font collection●

Free, public, content delivery●

We want to serve all Google users

Proprietary + Confidential

What is "Google Fonts"?
●

Free, open-source, font collection●

Free, public, content delivery●

We want to serve all Google users

Proprietary + Confidential

What does Google Fonts DO?
●

Maintain & publish collection●

Web API for our collection●

Android API for our collection●

Helps maintain tools and supporting
technologies

Proprietary + Confidential

No CJK Support :(●Blocked due to latency for a long time

●We had Early Access (beta) support

Proprietary + Confidential

Imagery

Korean is live onGoogle Fonts!
25 korean font families are now
available on fonts.google.com

ImageryJapanese is live
on Google Fonts!
8 japanese font families are now
available on fonts.google.com

Imagery

Google Docs ftw
Japanese and Korean fonts available in Google Docs!

What took so long?

AB
C
DEFGHIJKLMNOPQRSTUVWXYZ가각갂갃간갅갆갇갈갉갊갋갌갍갎갏감갑값갓갔강갖갗갘같갚갛개객갞갟갠갡갢갣갤갥갦갧갨갩갪갫갬갭갮갯갰갱갲갳갴갵갶갷갸갹갺갻갼갽갾갿걀걁걂걃걄걅걆걇걈걉걊걋걌걍걎걏걐걑걒걓걔걕걖걗걘걙걚걛

一二三四五六七八
九十百千
上下左右
中大小月
日年早木
林山川土
空田天生
花草虫犬
人名女男
子目耳口
手足見音
力気円入
出立休先
夕本文字
学校村町
森正水火
玉王石竹
糸貝車金雨赤青白
数多少万半形太細広長点丸

What took so long?
●High cost per character●Lots of characters●

We want a CSS solution●Browser features

AB
C
DE
F
G
H
I
JKL
M
NO
P
QRS
TUVWX
YZ

가각갂갃
간갅갆갇갈갉갊갋갌갍갎갏감갑값갓갔강갖갗갘같갚갛개객갞갟갠갡갢갣갤갥갦갧갨갩갪갫갬갭갮갯갰갱갲갳갴갵갶갷갸갹갺갻갼갽갾갿걀걁걂걃걄걅걆걇걈걉걊걋걌걍걎걏걐걑걒걓걔걕걖걗걘걙걚걛

一二三四五六七八九十百千
上下左右
中大小月
日年早木林山川土空田天生
花草虫犬
人名女男子目耳口
手足見音
力気円入
出立休先
夕本文字
学校村町
森正水火
玉王石竹
糸貝車金雨赤青白
数多少万
半形太細広長点丸

What took so long?
●High cost per character●Lots of characters●

We want a CSS solution●Browser features

ABC
D
E
FG
H
IJK
L
M
NO
PQR
STUVWXYZ

가각갂갃
간갅갆갇
갈갉갊갋
갌갍갎갏
감갑값갓
갔강갖갗
갘같갚갛
개객갞갟
갠갡갢갣
갤갥갦갧
갨갩갪갫
갬갭갮갯
갰갱갲갳
갴갵갶갷
갸갹갺갻
갼갽갾갿
걀걁걂걃
걄걅걆걇
걈걉걊걋
걌걍걎걏
걐걑걒걓
걔걕걖걗
걘걙걚걛

一二三四五六七八九十百千
上下左右中大小月
日年早木
林山川土空田天生
花草虫犬
人名女男
子目耳口
手足見音
力気円入
出立休先
夕本文字
学校村町
森正水火
玉王石竹
糸貝車金雨赤青白
数多少万半形太細広長点丸

Cheap to transfer (52 pts)

Expensive to transfer (147 pts)

What took so long?
●High cost per character●Lots of characters●We want a CSS solution●Browser features

ABCDEFGH
IJKL
MNO
PQR
S
TUVW
X
YZ

가각갂갃
간갅갆갇
갈갉갊갋
갌갍갎갏
감갑값갓
갔강갖갗
갘같갚갛
개객갞갟
갠갡갢갣
갤갥갦갧
갨갩갪갫
갬갭갮갯
갰갱갲갳
갴갵갶갷
갸갹갺갻
갼갽갾갿
걀걁걂걃
걄걅걆걇
걈걉걊걋
걌걍걎걏
걐걑걒걓
걔걕걖걗
걘걙걚걛

一二三四五六七八九十百千
上下左右中大小月
日年早木林山川土空田天生
花草虫犬人名女男
子目耳口
手足見音
力気円入
出立休先
夕本文字
学校村町
森正水火
玉王石竹
糸貝車金雨赤青白
数多少万半形太細広長点丸

Lots of characters●

Many US sites fit Basic Latin●

Going to Europe? Extended Latin

Lots of characters●Off we go to Greece, still fine●Generally ≤ 1,000 characters

Lots of characters●On to Seoul●latin ≤ 1,000 characters●

korean > 10,000 characters

Lots of characters
●

Tokyo

●

Even more complex characters●> 10,000 characters

What took so long?
●High cost per character●

Lots of characters●

We want a CSS solution●Browser featuresAB
CDEFGHIJKLMNOPQRSTUVWXYZ가각갂갃간갅갆갇갈갉갊갋갌갍갎갏감갑값갓갔강갖갗갘같갚갛개객갞갟갠갡갢갣갤갥갦갧갨갩갪갫갬갭갮갯갰갱갲갳갴갵갶갷갸갹갺갻갼갽갾갿걀걁걂걃걄걅걆걇
걈걉걊걋걌걍걎걏걐걑걒걓걔걕걖걗
걘걙걚걛

一二三四五六七八九十百千
上下左右中大小月
日年早木林山川土空田天生
花草虫犬
人名女男
子目耳口
手足見音
力気円入
出立休先
夕本文字
学校村町
森正水火
玉王石竹
糸貝車金雨赤青白
数多少万
半形太細広長点丸We want a CSS solution
CSS only, no API changes●API aims for simplicity
and ease of use●

Should work like anyother font●Allows us to deploy
ongoing optimizationstransparently

We want a CSS solution: subsetting●

71% of web pages on httparchive.org use fonts○ Trend toward more and larger fonts○ https://httparchive.org/reports/page-weight●Most pages use a small set of characters●Cut fonts into pieces, let user pick●

Doesn't work for CJK●Subsets are prohibitively large
Proprietary + Confidential

What took so long?
●High cost per character●Lots of characters●

We want a CSS solution●Browser features

ABC
DEFGH
IJKLMNOPQRSTUVWXYZ가각갂갃간갅갆갇갈갉갊갋갌갍갎갏감갑값갓갔강갖갗갘같갚갛개객갞갟갠갡갢갣갤갥갦갧갨갩갪갫갬갭갮갯갰갱갲갳갴갵갶갷갸갹갺갻갼갽갾갿걀걁걂걃걄걅걆걇걈걉걊걋걌걍걎걏걐걑걒걓걔걕걖걗걘걙걚걛一二三四五六七八九十百千
上下左右中大小月日年早木林山川土空田天生
花草虫犬
人名女男
子目耳口
手足見音
力気円入
出立休先
夕本文字
学校村町
森正水火
玉王石竹
糸貝車金雨赤青白
数多少万半形太細広長点丸

Browser features: WOFF2●

Rewrite parts of the font to be smaller●Compress with Brotli●

25–30% smaller than Zip

Nanum Gothic.ttf, 4.2MB
Nanum Gothic.zip, 2.3MB
Nanum Gothic.woff2, 1.7MB

Browser features: WOFF2●

It's good … but not good enough for CJK← Roboto Basic Latin.woff2, 0.02 MB
Nanum Gothic.ttf, 4.2MB
Nanum Gothic.zip, 2.3MB
Nanum Gothic.woff2, 1.7MB

Browser features: unicode-range
http://fonts.googleapis.com/css?family=Merriweather/* cyrillic */@font-facefont-family: 'Merriweather';src: url(http://fonts.gstatic.com/s/merriweather/cyrillic.woff2);
unicode-range: U+0400-045F;/* latin */@font-facefont-family: 'Merriweather';src: url(http://fonts.gstatic.com/s/merriweather/latin.woff2);
unicode-range: U+0000-00FF;

Browser features: unicode-range
http://fonts.googleapis.com/css?family=Merriweather

Download this/* cyrillic */@font-facefont-family: 'Merriweather';src: url(http://fonts.gstatic.com/s/merriweather/cyrillic.woff2);
unicode-range: U+0400-045F;/* latin */@font-facefont-family: 'Merriweather';src: url(http://fonts.gstatic.com/s/merriweather/latin.woff2);
unicode-range: U+0000-00FF;

Browser features: unicode-range
http://fonts.googleapis.com/css?family=Merriweather

Download this/* cyrillic */@font-facefont-family: 'Merriweather';src: url(http://fonts.gstatic.com/s/merriweather/cyrillic.woff2);
unicode-range: U+0400-045F;

If the page uses this/* latin */@font-facefont-family: 'Merriweather';src: url(http://fonts.gstatic.com/s/merriweather/latin.woff2);
unicode-range: U+0000-00FF;

Browser features: unicode-range
http://fonts.googleapis.com/css?family=Merriweather

Download this/* cyrillic */@font-facefont-family: 'Merriweather';src: url(http://fonts.gstatic.com/s/merriweather/cyrillic.woff2);
unicode-range: U+0400-045F;

If the page uses thisDownload thisIf the page uses this/* latin */@font-facefont-family: 'Merriweather';src: url(http://fonts.gstatic.com/s/merriweather/latin.woff2);
unicode-range: U+0000-00FF;

Font bytes

Browser features: WOFF2 + unicode-range

time
https://developers.googleblog.com/2015/02/smaller-fonts-with-woff-20-and-unicode.html

Browser features: cross-site caching●Key benefit of centrally hosted fonts●Less downloads as a font gets usedmore●

Our stats suggest this is very effective

Website 1

Website 2

Website 3

Roboto-Thin.woff2
Browser CacheBrowser features: HTTP/2●HTTP/1.1 queues aggressively○ < 10 fragments should be actively used

●HTTP/2 is more concurrency-enthused○ 10's of fragments can be actively used

Browser features: Critical Mass
{Chrome, Firefox, Safari, Edge}●unicode-range●WOFF2●HTTP/2

How do we ship Korean?
1.

Cut the fonts into lots ofpieces2.

Tell the browser about thepieces via unicode-range

Great! How exactly do you wantthose fonts segmented?

Proprietary + Confidential

Korean in use:
extremely skewed toward popular characters
PageTotalcharacters

UniqueCharacters

News site> 50K729

YouTube video + comments

1,848

394

Combined> 50K734

The YouTube page added only 5 more unique characters.
We should gather this type of data for a large set of Korean web pages!

Define problem space+ data source●

Define "Korean"○ Set of characters○ 17.4k total●

Look at usage○ Google indexes the web○ Examine a set of Koreansamples
Proprietary + Confidential

Examine data●●

Find the set of charactersused on each sample page
○ Ignore multiple useson same page
Count # of pages using
each character

Character #Pages Description
0xB2E492 다 HANGUL SYLLABLE DA
0xC7580 의 HANGUL SYLLABLE YI
0xB3004012 대 HANGUL SYLLABLE DAE...17k more...

Proprietary + ConfidentialFrequency of Korean characters
Examined millions of Korean web pages

Great! How exactly do
you want those fonts
segmented?

Proprietary + Confidential

Ways to segment

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Do Nothing●Ship the whole font in a single segment●Provides baseline for comparison

One giant font fileWays to segment

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Equal Bins
●Sort by codepoint●

Divide into 100 equal size groups...
Sort by codepoint

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Ways to segmentFrequency●Sort by usage frequency●Make 100 equal size groups

2000

1000

...
Sort by frequency

Ways to segment

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Hybrid sort
●Take two big blocks based on frequency●

Sort the rest by codepoint, make equal size groups

2000

1000

Sort by frequency...
Sort leftovers by codepoint

Ways to segment

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Learned Sort
●Take two big blocks based on frequency●Organize the rest using a topic model and a genetic
algorithm
2000

1000

Sort by frequency...
Sort by magicHow do we compare segmentation strategies?
●Fewer bytes transferred is better●

Fewer fonts used is better

These two goals can be at odds with each otherAll characters in
one file

One font file percharacter

Loadingtime

Delay fortransferringbytes

Number of segments

All characters inone file

One font file percharacter

Loadingtime
Delay fromnetwork,
renderingoverhead

Delay fortransferring
bytes

Number of segments

All characters inone fileLoadingtime

One font file percharacter

Total loading time

Delay fromnetwork,
renderingoverhead

Delay fortransferring
bytes

Number of segments

Test to find the best strategy●

Simulations and cost functions are fun●Live testing is better○ What if your cost function is wrong?

●

We have N strategies we think might work
○ Send Y% of production traffic to each one○ Let it run for a while○ Measure and compare!

●Save >= 60% of bytes vs baseline to win

Results: Hybrid Sort is the winner
Saved from both font data and CSS (higher is better)

GoodBetter
Best% Improvement

What we learned
Sometimes simpler is better●

Outperformed more complex
strategies.

A few big segments + many smaller
segments works surprisingly well●

Provides a good tradeoff between bytes
transferred and number of font requests.

At this point we shipped Korean, much rejoicing :)Korean adoption

Korean fonts
announced

Korean usage
From fonts.google.com:384M

Number of times Google Fonts API servedNanum Gothic over the last week. Nanum
Gothic is featured in more than 20,000
websites.

Round 2, fight!
●Hybrid Sort is king of the hill
○ we can do better

I have thistiny problem
where I always
want moreHow many high-frequency codepoints?
Is 3000 too many? Too few?
ConsiderMore high-frequency subsets (HTTP/1 vs HTTP/2)
Changing the boundary between high- and low-frequency codepoints

KeepLow-frequency characters ordered by codepoint … smaller CSS

Next batch of experiments
Adjust the high-frequency boundary: 1000, 2000
More aggressively subset high-frequency codepoints
10 and 20 subsets, rather than 2Reminder: the baseline is Hybrid Sort
Spoiler alert: improved by 29 - 38% more … nice!

DNUOR2

High frequency line at 3,000
Experiments: 10 and 20 subsets

3420 Subsets
29

10 Subsets
0%

10%

20%
% Improvement

30%

Conclusion: more high-frequency subsets performed better

High frequency line at 1,000
Experiments: 10 and 20 subsets

3520 Subsets
31

10 Subsets
0%10%20%% Improvement

30%

Conclusion: more high-frequency subsets performed better

High frequency line at 2,000
Experiments: 10 and 20 subsets

3820 Subsets
3310 Subsets
0%10%20%% Improvement

30%

Conclusion: more high-frequency subsets performed better10 Subsets

20 Subsets

Overall results
2000

38

1000

3534

3000

33

2000
31

1000

29

3000
0%

10%

20%% Improvement
on top of Hybrid Sort

30%

Conclusions for Korean fonts
Combining rounds 1 and 2, we’re saving ~93%
20 subsets always out-performed 10 subsets (regardless of thehigh-frequency line)
High-frequency line at 2000 performed best for both 10 and 20 subsets
The best line appears to be somewhere between 1000 and 2000

On to JapaneseExamined the character frequency
Ran similar tests
Reduced the bytes transferred by ~83%
Compared to sending the whole font

Frequency of Japanese characters on the web

Japanese and Korean frequencies

Conclusions for Japanese fonts
We shipped Japanese!
Japanese characters are more complex than Korean
Japanese has more high-frequency characters
A high-frequency line of 3000 narrowly outperformed 2000

Room for improvement
Improve the preferred high-frequency line¹
Refine the # of high-frequency subsets
Equal-sized high-frequency subsets may not be the best¹¹ Running these experiments right now

Room for improvement
Support Chinese, both simplified and traditional
使中文网络美丽而快速使中文網絡美麗而快速Trouble in paradise
Server: Hey buddy, here's my best guess at how I should cut up this font:
A B C D E F G H I J K L M N O P Q R S T U V W X Y ZBrowser: I need to render "Awesome" so I'll take these pieces:
A B C D E F

J K L M N O P Q R S T U V WProblems● Layout features don't work across segments○ AW won't kern
○ Indic, Arabic, and others rely heavily on layout● We still downloaded a lot of stuff we didn't use

Transfer optionsA)

unicode-range○ Cut font up, tell browser about pieces○ This is what we do today○ WAY better than whole font, but far from optimal○ User often "pays" for unused codepoints

Transfer options
B)

WOFF2 Deltas○ Each time user needs more codepoints, send a woff2 of the delta○ Layout will break horribly and unpredictably○ Not useful, but interesting for size comparison

Transfer options
C)

Incremental Transfer○ Each time user needs more codepoints, send a patch○ Layout will just work
○ User doesn't "pay" for unused codepoints○ Currently only achievable with JavascriptTransfer optionsD) Send woff2 of exactly what user will need
○ Requires a priori knowledge of content user will viewi) Currently impossible○ Compute this as "optimal" when comparing other solutions

Trouble in paradise
Imagine we want to render "Awesome" in MontserratTrouble in paradise
Next we browse to a page that uses VietnameseIncremental Transfer: HTTP interaction●HTTP is fine, no new protocol required :)●Request○ I have {current codepoints}○ I need {desired codepoints}●Response○ binary patch to desired state■ If {current codepoints} empty, a WOFF2 of desired state●

One cache key, update when you get a patch

Incremental Transfer: Subsetting●

Request○ I have {current codepoints}○ I need {desired codepoints}●

To compute patchcurrent = subset (current codepoints)
desired = subset (desired codepoints)
patch = binary patch (current, desired)●What luck! We are building a fast subsetter :)○ Faster Horse, https://github.com/harfbuzz/harfbuzz

Incremental Transfer: Patching
Page 1 "Meows"
Meosw

Incremental Transfer: Patching
Page 1: "Meows"

Page 2: "Awesome"

MAe

Moesmwosw
kern Aw

Incremental Transfer: Patching
Current State

Desired StateMAe

M

oesmw

osw
kern Aw

Incremental Transfer: Patching
Current State+Patch=

Desired StateM

insert AAereuse old bytes

Moinsert mes

reuse old bytesmw

insert kerno

Brotli Shared
Dictionarysw
kern Aw

Let's standardize Incremental Transfer!
The Brotli library used by WOFF2 can handle patching
The hb-subset library can be used to do very fast subsetting
Subset <current codeponts> → current
Subset <desired codepoints> → desired
Compress desired using Brotli Shared Dictionary, dictionary = current
Proof of concept: tinyurl.com/incxfer-demo
The WebFonts Working Group is considering writing a standard :)The End. Questions?
Speaker Evaluationwww.unicodeconference.org/eval-sp
References
fonts.google.com(choose Japanese or Korean from Languages)
tinyurl.com/incxfer-demo