As of 2016-02-26, there will be no more posts for this blog. s/blog/pba/
Showing posts with label font. Show all posts

The current monospace/programming font on this blog iswas Adobe's Source Code Pro via Google Web Fonts and I am not entirely satisfied with it. It has different font size, so I can fit 80 characters in one-line within the post width. So, I want to find another monospace font from Google Web Fonts. Unfortunately, there is no easy way. No option for selecting monospace fonts and I can't find anyone who has kindly spent time to make a list of that.

Since I clone entire Google Web Fonts, therefore it could be easier to generate a list programmically instead of going through the fonts via Google Web Fonts' interface.

In pangocairo, pangocairo.cairo_font_map_get_default() returns a pango.FontMap which can be used to list all font families. With those, pango.FontFamily.is_monospace() gives me what I look for, whether a font is monospace.

The following simple Python script lists all monospaces along with font's faces:
Sample output:
 ~/p/single [git:master] $ ./list-monospace-fonts-pangocairo.py
AR PL KaitiM Big5 : Regular Italic Bold Bold Italic
AR PL KaitiM GB : Regular Italic Bold Bold Italic
AR PL Mingti2L Big5 : Reguler Italic Bold Bold Italic
AR PL New Kai ExtB : Regular Italic Bold Bold Italic
[...]
Source Code Pro : Regular Black ExtraLight Light Bold Semibold Italic Bold Italic
Ubuntu Mono : Regular Bold Italic Bold Italic
Ubuntu Monospaced : Regular Bold Italic Bold Italic
VT323 : Regular Italic Bold Bold Italic
Now it's time to make the list by generating two lists, one from script above, another from fc-list
./list-monospace-fonts-pangocairo.py | sed 's/ *:.*$//' > monospace.lst
fc-list : file family | grep googlefontdirectory | grep -v ' \\- subset of ' | cut -d ' ' -f 2- | sed 's/,/\n/g' | sort | uniq > gwf.lst
sort monospace.lst gwf.lst | uniq -c | grep ' 2 '
Only taking the font family part. The list of Google Web Fonts requires little processing, it makes sure the list only contains fonts from the clone directory.

The list:
      2 Anonymous Pro
2 Courier
2 Cousine
2 Cutive Mono
2 Droid Sans Mono
2 Inconsolata
2 Lekton
2 NanumGothicCoding
2 NovaMono
2 Oxygen Mono
2 PT Mono
2 Press Start 2P
2 Share Tech Mono
2 Source Code Pro
2 Ubuntu Mono
2 Ubuntu Monospaced
2 VT323
Only 1716 fonts are monospace from Google Web Fonts, as of 2012-12-16T10:35:54Z. Note that: the Courier is not a mis-match, there is a Thabit in Early Access, the courier matches font files under Thabit's directory, /ofl/thabit/src/cour/*. The fonts in Early Access are not shown in Google Web Fonts' main browser.

Updated @ 2012-12-16T14:41:05Z:
  1. I have changed programming font to Inconsolata, one I used to use on my computer. It's not the best option but it's one of final four I picked up: Inconsolata, NanumGothicCoding, Lekton, and Ubuntu. I want the font isn't big and easy to read and fits 80 chars in width of 640px, these four met my criteria. Envy Code R still is the best in my opinion.
  2. The amount of fonts should be reduced by 1, because I found Ubuntu Mono seems to be synonym to Ubuntu Monospaced. I didn't actually check if they are, but that makes sense.

This blog uses external1 fonts, which are served from http://www.yjl.im/font/. Chromium (5.0) is my main browser and it renders with those fonts correctly. Some time ago, I noticed that Firefox (3.6) didn’t render with those fonts but it did download them. I couldn’t figure out why Chromium and Opera (10.10) works fine but Firefox doesn’t, and it’s not as if Firefox can’t render with fonts because it uses fonts at http://www.yjl.im/. (Internet Explorer (7) doesn’t, either, it’s same reason. But I don’t really care about IE)

I suddenly had a guess, a cross-domain thing. So I googled and found the answer2, it refers to Web Font linking and Cross-Origin Resource Sharing, my guess was confirmed.

Short story: you can’t use a font (in Firefox) which is not at same domain (origin). I think it’s right for a browser to have such behavior. Some people like stealing stuff.

Anyway, the solution is to add a response header Access-Control-Allow-Origin:


<FilesMatch "\.(ttf|otf|eot)$">
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
</FilesMatch>

If you uses Apache and you do know how to configure your server, the code above is right for you.

However, many people do not have a webserver, if they do, they probably would host a WordPress blog already and wouldn’t encounter this issue. Moreover, Google Sites is probably some people’s file hosting options if they user Blogger, you have no way to add a header. So a normal blogger without skill or knowledge or money, probably wouldn’t have a chance to use @font-face. Say what? Data URI? For Green’s sake, don’t use that to serve a font.

As for me, I use Google App Engine at http://www.yjl.im (source code, BSD License). You only need to write a code3. font.py does the job, the following code is the main part:


class FontFile(webapp.RequestHandler):

# Chromium don't use fonts with text/html as we want.
EXT_TYPES = {
'.otf': 'application/x-font-otf',
'.ttf': 'application/x-font-ttf',
'.eot': 'application/vnd.ms-fontobject',
'.svg': 'image/svg+xml',
'.js': 'application/x-javascript',
'.woff': 'application/octet-stream',
}

def get(self, fontpath):

fontpath = os.path.normpath(fontpath)
# Does someone try to get other files?
if fontpath.startswith('.') or fontpath.startswith('/'):
self.error(403)
return

# Is requested file a font file?
ext = os.path.splitext(fontpath)[1]
if ext not in FontFile.EXT_TYPES.keys():
self.error(403)
return

fontpath = 'font/%s' % fontpath
# Does this font exist?
if not os.path.exists(fontpath):
self.error(404)
return

if 'Origin' not in self.request.headers:
self.response.headers.add_header('Access-Control-Allow-Origin', 'http://www.yjl.im')
elif os.environ['SERVER_NAME'] == 'localhost' or \
self.request.headers['Origin'] in ['http://www.yjl.im', 'https://yjlv.blogspot.com']:
self.response.headers.add_header('Access-Control-Allow-Origin', self.request.headers['Origin'])
else:
self.response.headers.add_header('Access-Control-Allow-Origin', 'http://www.yjl.im')
self.error(403)
return

self.response.headers['Content-Type'] = FontFile.EXT_TYPES[ext]

expires = datetime.datetime.utcnow() + datetime.timedelta(365)
self.response.headers.add_header('Expires', expires.strftime("%d %b %Y %H:%M:%S GMT"))
self.response.headers['Cache-Control'] = 'public, max-age=%d' % (86400 * 365)

f = open(fontpath)
self.response.out.write(f.read())
f.close()

The code is fairly simple. First, it checks to make sure no one is trying to do something bad. Then it check the Origin of request header (if client browsers sends it) to see if it is an allowed source. If the request is from an allowed source, then it sets the Access-Control-Allow-Origin to be Origin of request header, same value. Why? Because Access-Control-Allow-Origin can only have one origin assigned, this is the only way to have multiple-origin. Of course you can use *, but that means You are all welcome to hotlink my fonts!.

If it’s not an allowed source, it sets to http://www.yjl.im and returns 403 status code because it’s obviously not from allowed source. You can be more creative, serving a special font. ;)

If client browser doesn’t send Origin (Chromium doesn’t send it), then it sets the header to http://www.yjl.im and sends the font file.

As you can see, I also assign a proper Content-Type. Chromium wouldn’t use the font if you don’t tell it the right type. (But it doesn’t care about cross-origin)

The fonts I use are all downloaded from Font Squirrel‘s @font-face Kit4. I don’t know much about EOT (Embedded OpenType), but I think the EOT from kit are only allowed to use from same origin. Access-Control-Allow-Origin also works for those EOTs from kit, IE didn’t use external fonts but it did after I started to use that header.

[1]Blogger is not a file hosting provider, so if your Blogger blogs need some file for your blog, you have to find other options to host the files.
[2]http://www.thebrightlines.com/2010/01/12/implementing-font-face-cross-domain/ is gone. (2015-12-14T22:15:10Z)
[3]app.yaml doesn’t allow you to add header for static file.
[4]It packages all types of a font you need plus stylesheet in one ZIP archive.