I've had some hope to show working bytecode stuff at the beginning of May, but things are a bit more complicated, unfortunately: While the library has been extended to support generated bytecode already, I have first to define some auxiliary bytecode functions to support hinting similar to FreeType's autohinter.
On the other hand, I have now an outline how things will work: I will run the autohinter for a set of sizes which are then hardcoded as bytecode. Contrary to the autohinter, TrueType instructions can only handle integer values for PPEM sizes; this reduces a lot the number of configurations to test for. Some weeks ago I've adapted the autohinter logging stuff to standard FreeType tracing (at level 5); now can you actually see the `high-level hints' the autohinter is going to apply with the usual tracing methods as outlined in FreeType's `DEBUG' documentation file. As an example, here are the messages for vertical hinting of glyph `R' from pala.ttf at the 10ppem: BLUE: edge 0 (opos=0.00) snapped to (0.00), was (0.00) LINK: edge 1 (opos=0.30) linked to (0.30), dist was 0.30, now 0.30 BLUE: edge 4 (opos=7.34) snapped to (8.00), was (7.34) LINK: edge 3 (opos=6.97) linked to (7.62), dist was -0.38, now -0.38 SERIF_LINK1: edge 2 (opos=3.95) snapped to (4.31) from 1 (opos=0.30) I'll skip a detailed explanation here; you might read the comments in file `afhints.h' for more. The most important fact which can be seen from the above output is that `LINK' commands don't snap to pixel borders. This is intentional. Except for blue zones where either the top or the bottom line of a stem gets aligned with a pixel border (the width of small stems gets increased if necessary), the autohinter aligns the *center* of stems, applying some rounding voodoo to the stem width. To imitate this behaviour, I'm diving right now into the world of writing bytecode assembler code. Here an example. The following code is taken from `af_latin_compute_stem_width', transformed into some pseudo code which can be easier converted to bytecode: Function: compute_stem_width in: width is_serif is_round out: new_width CVT: std_width dist = ABS(width) if is_serif && dist < 3*64: return width else if is_round: if dist < 80 dist = 64 else: dist = MIN(56, dist) delta = ABS(dist - std_width) if delta < 40: dist = MIN(48, std_width) goto End if dist < 3*64: delta = dist dist = FLOOR(dist) delta = delta - dist if delta < 10: dist = dist + delta else if delta < 32: dist = dist + 10 else if delta < 54: dist = dist + 54 else dist = dist + delta else dist = ROUND(dist) End: if width < 0: dist = -dist return dist This corresponds to the following (still untested) bytecode: // In the comments below, the top of the stack (`s:') // is the rightmost element. // Function 0: compute_stem_width // // in: width // is_serif // is_round // out: new_width // CVT: std_width 0xB0, // PUSHB_1 0x00, // 0 0x2C, // FDEF 0x20, // DUP 0x64, // ABS -- s: is_round is_serif width dist 0x20, // DUP 0xB0, // PUSHB_1 0xC0, // 3*64 0x50, // LT -- (dist < 3*64) 0xB0, // PUSHB_1 0x04, // 4 0x26, // MINDEX -- s: is_round width dist (dist<3*64) is_serif 0x5A, // AND -- (is_serif && dist < 3*64) 0x58, // IF -- s: is_round width dist 0x21, // POP 0x23, // SWAP 0x21, // POP -- s: width 0x1B, // ELSE 0x8A, // ROLL -- s: width dist is_round 0x58, // IF -- s: width dist 0x20, // DUP 0xB0, // PUSHB_1 0x50, // 80 0x50, // LT -- (dist < 80) 0x58, // IF -- s: width dist 0x21, // POP 0xB0, // PUSHB_1 0x40, // 64 -- dist = 64 0x59, // EIF 0x1B, // ELSE 0xB0, // PUSHB_1 0x38, // 56 0x8C, // MIN -- dist = min(56, dist) 0x59, // EIF 0x20, // DUP -- s: width dist dist 0xB0, // PUSHB_1 %c, // index of std_width 0x45, // RCVT 0x61, // SUB 0x64, // ABS -- s: width dist delta 0xB0, // PUSHB_1 0x28, // 40 0x50, // LT -- (delta < 40) 0x58, // IF -- s: width dist 0x21, // POP 0xB1, // PUSHB_2 0x30, // 48 %c, // index of std_width 0x45, // RCVT 0x8C, // MIN -- dist = min(48, std_width) 0x1B, // ELSE 0x20, // DUP -- s: width dist dist 0xB0, // PUSHB_1 0xC0, // 3*64 0x50, // LT -- (dist < 3*64) 0x58, // IF 0x20, // DUP -- s: width delta dist 0x66, // FLOOR -- dist = FLOOR(dist) 0x20, // DUP -- s: width delta dist dist 0x8A, // ROLL 0x8A, // ROLL -- s: width dist delta dist 0x61, // SUB -- delta = delta - dist 0x20, // DUP -- s: width dist delta delta 0xB0, // PUSHB_1 0x0A, // 10 0x50, // LT -- (delta < 10) 0x58, // IF -- s: width dist delta 0x60, // ADD -- dist = dist + delta 0x1B, // ELSE 0x20, // DUP 0xB0, // PUSHB_1 0x20, // 32 0x50, // LT -- (delta < 32) 0x58, // IF 0x21, // POP 0xB0, // PUSHB_1 0x0A, // 10 0x60, // ADD -- dist = dist + 10 0x1B, // ELSE 0x20, // DUP 0xB0, // PUSHB_1 0x36, // 54 0x50, // LT -- (delta < 54) 0x58, // IF 0x21, // POP 0xB0, // PUSHB_1 0x36, // 54 0x60, // ADD -- dist = dist + 54 0x1B, // ELSE 0x60, // ADD -- dist = dist + delta 0x59, // EIF 0x59, // EIF 0x59, // EIF 0x1B, // ELSE 0xB0, // PUSHB_1 0x20, // 32 0x60, // ADD 0x66, // FLOOR -- dist = round(dist) 0x59, // EIF 0x59, // EIF 0x23, // SWAP -- s: dist width 0xB0, // PUSHB_1 0x00, // 0 0x50, // LT -- (width < 0) 0x65, // NEG -- dist = -dist 0x59, // EIF 0x2D, // ENDF It took me three hours to write that small bit of code, but meanwhile it's getting much faster :-) Werner _______________________________________________ Freetype-devel mailing list Freetype-devel@nongnu.org https://lists.nongnu.org/mailman/listinfo/freetype-devel