Hi Steve,

   I warned you that text was tricky ;)

Steve Lamont wrote:
   Text is quite tricky.  You need to manipulate the TextPaintInfo
object that is attached to the AttributedString associated with the
TextNode.  The tricky bit is that all of the tspan's are built into
the one AttributedString so if you have 'complex' text you would have
to track down the proper TextPaintInfo to update.

Do you mean `AttributedCharacterIterator'? I see no AttributedString' in a `TextNode'.

The AttributedCharacterIterator comes from the AttributedString built in the TextBridge.

Is there a reason why all of this is so darned Byzantine?

Because Text is _extremely_ complex. The text handling portion of Batik is by far the most complex part.

Why, for instance, is a `StrokingTextPainter' so radically different
than a 'StrokeShapePainter'?

Because text can change color in the middle, and it also needs to support being reordered to handle bi-directional text (like Arabic or Hebrew).

In the `StrokeShapePainter' there's a `setPaint()' method that allows one to set the color of the object, whereas in the `StrokingTextPainter' no such method exists and one has to go through extraordinary contortions to get at the `TextPaintInfo' for each individual *character* in a text string in order to set color:

This is because unlike a shape in the worst case every character can have a different color. They all share one StrokingTextPainter so it can do bidi reordering. In most cases you don't need to modify the text paint info for every character you only need to do it for runs. All the characters in a run share a single TextPaintInfo, so modifying the TPI on the first character in the run will update all the characters in the run.

   The ACI has methods to find the end of a "run" so you can
quickly update an entire string.

    private void updateTextNodeColor( Color rgb, TextNode text_node )
    {

        AttributedCharacterIterator aci =
            text_node.getAttributedCharacterIterator();

        for( char c = aci.first();
             c != CharacterIterator.DONE;
             c = aci.next() ) {

TextPaintInfo tpi =
( TextPaintInfo ) aci.getAttribute( TextNode.PAINT_INFO );
if ( tpi.fillPaint != null )
tpi.fillPaint = rgb;
if ( tpi.strokePaint != null )
tpi.strokePaint = rgb;


        }

    }

It took me most of a day to figure out that you had to slog through
each character, one by one, in order to get all the characters in the
same string the same color.

I'm as sure as I can be that you only need to do this for the first character in a Run

I beg your pardon but that's just bizarre.

Well this basic approach is the one used by the JDK for complex text so it's not like we invented it. We did extend it because we need to do things like under/overline & strikethrough with fill/stroke as well as stuff like text on a path. However the concept of per char attributes that control rendering is a common one for text rendering systems that need to deal with realities like bidi text, vertical languages, mid string font/color changes, etc.

Oh, one minor point.  In `TextPaintInfo', the method name
`equivilent()' should be `equivalent()'.  I know in computing that
spelling doesn't necessarily have to be correct, but still. . .

Thanks I'll fix this and deprecate the misspelling.

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to