August 24, 2010

Implicit Conversions in the Atom Library

A few years ago I began building my most polished project to date—the NerdSince1984.Syndication.Atom library. As you may have guessed, it’s a library for representing the Atom Syndication Format, including Feed Paging and Archiving and the Atom Publishing Protocol. The concepts behind the structure of an Atom feed are simple enough, but implementing them as .NET objects is trickier than you may think.

For example, each entry in a feed contains a title represented by an <atom:title> tag, so you could easily expose the Title property of an AtomEntry object as a string, right? Actually, the <atom:title> tag is an atomTextConstruct according to the documentation, which defines it in RelaxNG as:

atomTextConstruct = atomPlainTextConstruct | atomXHTMLTextConstruct

atomPlainTextConstruct =
  atomCommonAttributes,
  attribute type { "text" | "html" }?,
  text

atomXHTMLTextConstruct =
  atomCommonAttributes,
  attribute type { "xhtml" },
  xhtmlDiv

Not just a simple string anymore, is it? In addition to the atomCommonAttributes, the <atom:title> tag can have a type attribute that defines the type of content it contains—plain text, HTML, or XHTML. For a library to fully support the Atom Syndication Format, it must support simple tags like

<atom:title>Implicit Conversions in the Atom Library</atom:title>

and complex tags like

<atom:title xml:lang="fr-CA" custom:generatedby="http://translate.google.com/">
  Les conversions implicites dans la bibliothèque Atom
</atom:title>

To accomplish the above, we could employ code à la NerdSince1984.Syndication.Atom like below.

XNamespace custom = "http://example.org/";
AtomEntry frenchEntry = new AtomEntry(...);
frenchEntry.Title = "Les conversions implicites dans la bibliothèque Atom";
frenchEntry.Title.Add(new XAttribute(XNamespace.Xml + "lang", "fr-CA"));
frenchEntry.Title.Add(new XAttribute(custom + "generatedby",
    "http://translate.google.com/"));

Notice how we are able to set the Title property as if it expects a string, yet we are also able to call a method on it to add an extension attribute. That's because the Title property is of type AtomTitle, which exposes a from-string implicit conversion operator. Anything that expects an AtomTitle can take a string instead, which gets implicitly converted to an AtomTitle. AtomTitle also derives from AtomTextNode, which exposes a to-string implicit conversion operator, so anything that expects a string can take an AtomTextNode instead.

The NerdSince1984.Syndication.Atom library is replete with implicit conversions, not only for strings, but for DateTime objects and especially XElements. To find out for yourself, download the library in your favorite flavor—3.5 or 4.0.

March 25, 2008

Why font-size-adjust Is a Good Thing

Take a look at these two lines:

This line of text uses Georgia font at 12px.

This line of text uses Garamond font at 12px.

Notice how much smaller the second line appears, not to mention harder to read, even though they are both set to a font size of 12px. This is due to the different x-height properties of the two fonts. The x-height of a font is the height of its lowercase x. In this case the x-height of Garamond is 21% smaller than the x-height of Georgia, making it appear smaller.

This may not seem like a big deal at first; we can just increase the font size of Garamond by 26% to compensate for the smaller x-height, right? But what if we use font-family: georgia, garamond; in a style sheet and the user doesn’t have the Georgia font? We can’t set a font-size for each font we list, so the user either gets a reasonably sized Georgia or a tiny Garamond. That’s where the CSS property font-size-adjust will play its part.

font-size-adjust adjusts the sizes of fonts based on their x-height property. The value of this property is the ratio of x-height to font-size, or aspect value. For example, the aspect value of Georgia is 0.48 and Garamond’s is 0.38. This means that if you have font-size-adjust: 0.48; the size of text in Georgia will stay the same, but text in Garamond will increase by 26% to meet an aspect value of 0.48. Here’s an example:

p {
  font-size: 12px;
  font-size-adjust: 0.48;
}
...
<p style="font-family: georgia;">
  The quick brown fox jumps over the lazy dog.</p>

<p style="font-family: garamond;">
  The quick brown fox jumps over the lazy dog.</p>

The browser will render this:

The quick brown fox jumps over the lazy dog.

The quick brown fox jumps over the lazy dog.

Notice the increase in font size on the second line. No more worrying about legibility problems due to lack of fonts on the user’s end. But it serves another purpose. Let’s say we use the ubiquitous Verdana font for normal text, but we don’t like the way it looks when italicized. So we choose a serif font, like Times New Roman, when italicizing text instead. The problem we face is that most serif fonts have a smaller x-height than Verdana resulting in very small italics. But if we use font-size-adjust: 0.55; our serif font size gets adjusted like this:

Sans-serif text with some italicized serif text.

I’ll mention a few more things about font-size-adjust before I close. Here’s a quote directly from the CSS3 specification:

Font size adjustments take place when computing the actual value of 'font-size'. Since inheritance is based on the computed value, child elements will inherit unadjusted values. Font size adjustments are applied to all fonts used by child elements, substituted or not.

CSS3 module: Fonts

Although font-size-adjust changes the appearance of text, it does not change the computed value of the font-size property. This means that computed line height and em values will still be based on the font-size property and not the adjusted font size. Whether this is good or bad is arguable depending on the situation.

font-size-adjust is part of the CSS2 specification but was removed in the 2.1 revision due to lack of browser support. As of this writing, Mozilla is the only brower that supports it, but it’s part of the CSS3 Fonts module and should eventually be supported by all of the latest browsers. Until then, we’ll just have to keep fiddling with font sizes and sticking with ubiquitous fonts.