You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-dev@xmlgraphics.apache.org by Glenn Adams <gl...@skynav.com> on 2010/08/30 14:19:23 UTC

upcoming change to IFPainter.drawText()

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

Re: upcoming change to IFPainter.drawText()

Posted by Glenn Adams <gl...@skynav.com>.
Thanks, that's a good suggestion. I've been contemplating that for a while
now.

On Tue, Aug 31, 2010 at 9:24 PM, Vincent Hennebert <vh...@gmail.com>wrote:

> Hi Glenn,
>
> A dedicated class with meaningful fields (e.g., xPlacement, xAdvance)
> would probably be preferable to an array of 4 int. This would be safer
> and easier to understand and use.
>
> For the rest, that sounds good.
>
> Vincent
>
>
> Glenn Adams 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
> >
>

Re: upcoming change to IFPainter.drawText()

Posted by Vincent Hennebert <vh...@gmail.com>.
Hi Glenn,

A dedicated class with meaningful fields (e.g., xPlacement, xAdvance)
would probably be preferable to an array of 4 int. This would be safer
and easier to understand and use.

For the rest, that sounds good.

Vincent


Glenn Adams 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
> 

Re: upcoming change to IFPainter.drawText()

Posted by Glenn Adams <gl...@skynav.com>.
Oops, that code snippet should read:

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 ( *d* != 0 ) {
        gpos[i][0] += d; // reconcile x placement adjustment
        gpos[i][2] += d; // reconcile x advance adjustment
      }
    }
  }
}


On Tue, Aug 31, 2010 at 4:51 AM, Glenn Adams <gl...@skynav.com> wrote:

> 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-adjust attribute, 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
>>
>>
>>
>>
>

Re: upcoming change to IFPainter.drawText()

Posted by Glenn Adams <gl...@skynav.com>.
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
>
>
>
>