Tuesday, September 30, 2008

Canned Effects

[build 0062] Having got to the end of Text I found that Sprites, Gradients, Buttons and TimeLines fell out in a few hours. In some ways this is strange because progress has been pretty hard fought for with text. In getting the text to work I had to replace a font scalar, plumb in CoreText - none of this is small beer. The Sprites, Gradients etc are little more than getting the files to compile - registering them with object factory and testing, Later, when it comes to writing UI the shoe will be on the other foot.

The next step for Cello is getting the various canned effects to work. The canned effects are animation effects that are applied to an object in a single hit and just "work". The effects come in different classes. Logically I should probably have attacked the text effects first as they would mesh into the text and probably would lift out any remaining bugs in the area. However having done two months of text I have decided to start with some of the other effects first. My thought was it would be well, just nice, to appear to make a little progress. So I have started the effects in alphabetical order.

The first effect is an effect that takes a shape and maps it onto all four sides of a spinning cube. Getting the files to compile (there were nine new files) took two or so hours - and afterwards it well almost worked - just objects are wrongly positioned and spin, well, strangely.

The reason made me smile. I had to add an implementation of CenterPoint to my MFC CRect class. The function was so trivial that I did not write a unit test. I was lucky to spot the error when I did a brief code review before checking my changes into CVS.

Monday, September 29, 2008

CoreText - Setting styles on empty AttributedStrings

[build 0058] Text in Cello appears to be completed - for the moment at least.

The last problem with text was something of a classic. Within Cello the text and style runs are stored as CFAttributedStrings. This works out really well as this is what CoreText consumes. The problem comes with empty strings. If you have an empty string then it is impossible to set any attributes on it. Also if you try and find the bounds of the string CoreText will give you an empty rectangle. This is not necessary what is wanted. If Cello is calculating the height of a text box then if text styling has been set then it needs to be able to set the styling of the text box and to use this to calculate the height of the box.

The solution to this problem is to introduce the idea of the NULL style. The NULL style is a style that is set and exists when there is a need to set the style at a point rather than over a selection of text. So, when there is no text, setting the style of a text flow will just set the NULL style. Then when text is actually added we grab the NULL style and style the newly added text with it. A similar concept can be used when you set the style at an insertion point.

As far as getting the height of text when thee is none - a solution that works is to give CoreText a single space character and to style it with the NULL style. Then the normal code that is used to calculate the box height will just work.

Thursday, September 25, 2008

CoreText Typography - Ligatures

[build 0051] The great fight with text is slowly coming to a close. I have a few outstanding bugs before I move on to editable text but I can see the end.

Ligatures appear correctly in the output.
Having spent some time looking into glyphs and glyph codes ligatures are the easiest test case for non-standard glyphs because it is possible to type in normal letters like "f" and "i" in the PC version of Cello, save the file, open them under OSX and then to let the CoreText layout transform the pair into a ligature during normal line layout. My conjecture is that the treatment of ligatures will prove a reasonable test case for non-standard glyphs (e.g. various alternate character forms) in general. As Cello shapes up more it will be possible to test this further.

If you are interested in typography here is a link to SIL International has some good information here.

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.

Tuesday, September 9, 2008

Text - the first test and the first crash

[build 41] I have got as far as linking in the text related files for reading, writing and publishing. This means that all the code that is required to read a text object, write it, and publish it has been added to Cello. As my first test I have created a text file in the PC version of Cello with the single word "Text".


Attempting to open this crashes - this, of course, is progress. I have isolated the crash and added it to the unit test which also crashes. This means that when I have the fix I can cast the fix in 'stone'.