Perhaps it is useful to indicate how the existing dx[] adjustments map into the more generalized gpos[][] adjustments. Given a dx[] array or a gpos[][] array or neither, they are reconciled as follows:
int[][] reconcileAdjustments(int[] dx, int[][] gpos) { if ( dx == null ) { return gpos; } else { if ( gpos == null ) { gpos = new int[dx.length][4]; } for ( int i = 0; i < dx.length; i++ ) { int d = dx[i]; if ( dx != 0 ) { gpos[i][0] += d; // reconcile x placement adjustment gpos[i][2] += d; // reconcile x advance adjustment } } } } The current semantics of dx[i] cause the current point to be adjusted to curPointX + dx[i] prior to rendering glyph[i], after which the implicit x advancement (width) of glyph[i] is added to curPointX. In the reconciliation of dx[] and gpos[][] above, dx[i] is added to both the x placement adjustment and the x advance adjustment of glyph[i], the net effect of which is that the x origin of glyph[i] is translated by dx[i], and then the current point x coordinate is advanced by the sum of the implicit glyph advancement and the x advance adjustment. Together, these yield the same behavior as presently indicated by the non-generalized form of drawText. There are a number of places in the existing code where this reconciliation could take place, including: (1) just prior to creating a word area, in which case a word area would carry only the gpos[][] adjustments; (2) just prior to calling IFPainter.drawText, i.e., in IFRenderer.TextUtil.flush(); In both cases, the externalized, AT form of WordArea changes. In case (1), the letter-adjust attribute is effectively merged into a new position-adjustattribute, with letter-adjust being removed. In case (2), a new position-adjust attribute is added to hold gpos[][], but the existing letter-adjust attribute is retained as is. I have tentatively decided to use case (2), since this does not create any test regressions for the handful of tests that make reference to the letter-adjust attribute. It could always be moved further back, e.g., to (1), at a future date. Comments? G. On Mon, Aug 30, 2010 at 8:19 PM, Glenn Adams <gl...@skynav.com> wrote: > Folks, > > I'd like to mention a change I will implement on IFPainter#drawText method > in order to accommodate complex scripts (as well as non-complex script usage > in a variety of written languages). I'm bringing this up now so there can be > discussion ahead of time if needed. > > Basically, the change is to generalize the int[] dx parameter to be a two > dimensional array of glyph placement/advancement adjustments. > > The current interface is: > > void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, > String text) throws IFException; > > The modified method interface would read as follows: > > void drawText(int x, int y, int letterSpacing, int wordSpacing, int[][] > adjustments, String text) throws IFException; > > The adjustments array is optional (in which case it is null). If non-null, > it is effectively typed as int[][4], i.e., an array of int[4] arrays, where > the four elements of each row are: > > a[0] = x placement adjustment > a[1] = y placement adjustment > a[2] = x advance adjustment > a[3] = y advance adjustment > > The [x,y] placement adjustments are added to the current point to determine > the effective glyph (char) origin, and the [x,y] advance adjustments are > applied to the current point after rendering the glyph (char) and performing > the default (implicit) advance. > > To be more explicit, the algorithm using these adjustments is effectively > as follows (ignoring word and letter spacing for the moment): > > int curPointX = x; > int curPointY = y; > for ( int i = 0, n = glyphs.length; i < n; i++ ) { > int g = glyphs [ i ]; > int gx = curPointX; > int gy = curPointY; > int[] a = ( adjustments != null ) ? adjustments[i] : null; > if ( a != null ) { > gx += a[0]; > gy += a[1]; > } > drawGlyph ( g, gx, gy ); > curPointX += font.getGlyphAdvanceX ( g ); > curPointY += font.getGlyphAdvanceY ( g ); > if ( a != null ) { > curPointX += a[2]; > curPointY += a[3]; > } > } > > It is mandatory to provide this generality in order to support not only > complex scripts, but also non-complex scripts (e.g, Latin, Greek, Cyrillic, > CJK, etc) when used with non-spacing marks (in many written languages) and > also for other advanced typographic effects. > > Attached is a simple example of the use of this feature in order to adjust > the placement (and advance) of U+064E ARABIC FATHA and U+0650 ARABIC KASRA, > respectively, the upper and lower non-spacing marks shown in this example. > > Regards, > Glenn > > > >