Wednesday, September 24, 2008

CoreText - Accesing the CMAP CTFontGetGlyphsForCharacters

CoreText provides the function CTFontGetGlyphsForCharacters that will give you a conversion from a letter to a glyph through the unicode CMAP.

Sunday, September 21, 2008

Glyphs to Character Codes - revisited

My original plan to map glyphs to character codes appears doomed. There main flaw in this plan is that it looks like the glyph names are not reliable - what I mean by this is that some glyphs do not have names that can be mapped to a character code. For example the font "Li Song Pro" has glyph names names that apper to be based on glyph codes rather than character codes.

At this point I took stock what I was trying to achieve and why the character codes are necessary. Character codes are required because there are occasions in the output where a font is output that is "complete" with a correct character mapping is required. To satisfy this all the characters that are part of the "normal" mapping must be present - as well as any additional character that may be used by specific text in the output (fonts are shared across objects). Other parts of the output requires partial fonts - that is just the glyphs in a font that are actually used. In this case the character codes don't really matter. As there can be overlap when glyphs are output if they are a part of the "Standard character set" then they should be identified in order that they can have the correct character codes attributed to them.

Looking at things in this way it simplifies things. We need to identify if glyphs are a part of the standard character set. The solution that seems to present it self is this:
  1. Locate the character(s) resonsible for a paticular glyph
  2. Check if that character is a part of the stabdard character set - this can be done by mapping the character to a glyph code using the font's CMAP and checking if we get the same glyph code.

Friday, September 19, 2008

CoreText - Getting Glyph Names

Looking at the published file and its log I can see that there is a problem with the character codes that Cello is publishing. The published file format expects character codes that are then mapped to glyph indexes. Cello is feeding the code glyph indexes, it works but it is not right and will cause problems in other places where text is used. If you are not too familiar with the difference - Wikipedia has an excellent introduction here.

Getting glyph codes as a result of line layout is a natural consequence of using Core Text. Core Text takes styled text and turns it into glyph runs (lists of glyph codes) - this is exactly what I want. Core Text does all the clever bits of positioning, ligatures, alternate character sets etc. So the problem that I face is the need to convert glyph codes back to character codes.

At this point it is worth mentioning that it is not always possible to convert glyph codes back to character codes. Line layout will do things like convert some some multiple character forms to ligatures - see. Also some fonts can have different forms - for example "end swashes" where a character at the end of a line can be represented with different glyphs, and it goes on. The best you can hope for is to be able to convert most glyph codes to character codes.

I have been thinking about how to approach the problem. The best solution that I can see at the moment is to
  1. Pull the name of the each particular glyph - Core Text does not support this directly but it is possible to convert a CTFontRef to a CGFontRef using CTFontCopyGraphicsFont, and then getting the name using CGFontCopyGlyphNameForGlyph.
  2. Using Adobe's magic technique map each glyph onto a character code as described here.

Wednesday, September 17, 2008

CoreText - Bold, Italic and CTFontCreateCopyWithSymbolicTraits

[build 0047] The text publishing is slowly falling into place. I have managed to get to the bottom of most of the positioning problems. The side-by-side comparison shows publishing under OSX text is quite similar. The vertical positioning is a little different. Also under OSX the text is kerned - something that fell out from using Core Text.
More complex example (an unpleasent combination of styling) is also close.

There seems to be a bug that means that a small section of underline is missing - but more obviously some characters are not italic.

The lack of itallics is due to the way that Core Text handles fonts within a font family. A true italic font is actually a seperate font that has been designed and created specificaly by the font foudry, as is a bold version of a font. If you ask for the bold or italic form of a font (CTFontCreateCopyWithSymbolicTraits and friends) Core Text will look for an approriate font in the family - if there is not one it will fail. This is typographically the correct thing to do.

Many programs will synthesize an italic font by slanting the regular font - this works but looks a little ropey. This is what the PC version does. It is also posible to synthesize bold forms of a font. This is done by out setting the contours of each glyph. If a synthesized italic font is a bit ropey a synthesized bold tends to be a bit ugly. It is quite possible to do both in Core Text but I currenty do not plan to do it.

Friday, September 12, 2008

CoreText - flipped coordinates and glyph curves.

Text output is requires partial fonts to be included in the file format. This is done by having the glyph outlines embedded in the file. As described earlier I am using Core Text to get the glyph outlines (see). Unfortunately (looking at the output) the outlines are flipped.

This particular problem is caused by CoreGraphics (Quartz) having a flipped y-axis, so zero is at the bottom rather that the top. This can be corrected by passing an appropriate transform (flipping allong the baseline) through to CTFontCreatePathForGlyph. This snippet calculates an appropriate flipped transform.

sFlipTransform = CGAffineTransformIdentity;
sFlipTransform = CGAffineTransformScale
(sFlipTransform, 1, -1);
Which results in the glyphs being correctly orientated.

Thursday, September 11, 2008

CoreText and Typographic Bounds

[build 44] Having got the simple file with text to open the next stage was to get the brute to publish. The first attempt at publishing yielded nothing - white space. Looking at the debug log that dumps the published movie it was because the text object that was published was empty i.e. had no text.

The primary cause of this was due the conversion of floating point to integer values. Within Cello all object coordinates and dimensions are expressed as integers - Core Text, like CoreGraphics, is floating point. The issue here is that Cello has auto hight boxes whose height is based on the typographic bounds of the text. So a height of 31.2 was being truncated to 31. Giving a CTFramesetter anything less than the typographic height of the first line when it creates the CTFrame results in a frame with no lines of text. So no text. I found a report of a similar problem here.

Following a fix to a crash in some very early asci->uft8 code I wrote before I started writing unit tests Cello publishes it's first text.
The glyphs are not in the right positions and everything is inverted (coordinate space in Quartz is flipped so this kind of problem is not uncommon or unexpected) but it is not that far away.

Wednesday, September 10, 2008

CoreText & Cocoa Text - what is RTF?

[build 42] Cello will open some simple files with text, The question "what is RTF" seems suddenly quite poignant. The reading of a file with text fails because the reading of the RTF (within the file) fails. Cocoa believes the RTF to be bad and throws up it's hands in horror. Cross checking my results with TextEdit (I added some code to squirt out the RTF on its own in a file) yields the same result.


My assumption was that Cello's RTF could be read by the Cocoa RTF reader. Lawrence Harris (one of the most notable and helpful contributors to Apple's Carbon Dev mailing list) frequently points out the fallacy of relying on assumptions. The relevant RTF snippet is happily gobbled up by MSWord so it can't be all that bad, but my assumption was.

I spent some time thinking of the best way to deal with this. My feeling is that I need to be able to read files from the PC version to be able to do any kind of testing, my approach relies on working through files created on the PC version. My solution is to take Cello's RTF reader out of the "bad-list" and to use it as a fall-back for reading RTF.

Getting the RTF import to work was not a huge amount of work- probably the biggest surprise was the discovery that all text sizes in cello are represented in 10ths of a pt. Other than this I compiled out the inbuilt RTF export - this is currently not required and getting it to compile will just take time.