TinyLine 2D Programming Guide

6 Text and Fonts

6.1 Introduction

In TinyLine 2D texts are rendered like other graphics elements. Thus, coordinate system transformations, painting - all TinyState graphics state attributes apply to text elements in the same way as they apply to shapes such as paths or rectangles.

Tiny2D does not perform automatic line breaking or word wrapping. To achieve the effect of multiple lines of text, you need to look at the TextLines.java example that follows at the end of this chapter.

Tiny2D provides a low-level interface for drawing texts. The following Tiny2D function draws the outline of the character array using the TinyState current graphics state. The entire character array is styled using the specified font and font size. The base line of the first character is defined by the position (x,y) and the alignment anchor.

public final void drawChars(TinyFont font,
                            int fontSize,
                            char[] ac,
                            int off,
                            int len,
                            int x,
                            int y,
                            int anchor)

Parameters:
font - the font object.
fontSize - the size of the font.
ac - array of characters.
off - the initial array offset.
len - the length of array.
x - the x-axis coordinate of the current text position
y - the y-axis coordinate of the current text position
anchor - the text alignement.

6.2 Fonts and Glyphs

As you may noticed, Tiny2D uses a font (TinyFont object), which has sets of shapes that are associated with characters, to draw text.

The TinyFont defines a collection of glyphs together with the information necessary to use those glyphs. The TinyFont includes the information necessary to map characters to glyphs, to determine the size of glyph areas and to position the glyph area.

The characteristics and attributes of TinyFont correspond closely to the SVG fonts. Various font metrics, such as advance values and baseline locations, and the glyph outlines themselves, are expressed in units that are relative to an abstract square whose height is the intended distance between lines of type in the same type size.

This square is called the EM square and it is the design grid on which the glyph outlines are defined. The value of the units-per-em attribute on the TinyFont specifies how many units the EM square is divided into. Common values are, for example, 1000 (Type 1) and 2048 (TrueType, TrueType GX and Open-Type).

The design grid for TinyFont fonts, along with the initial coordinate system for the glyphs, has the y-axis pointing upward for consistency with accepted industry practice for many popular font formats.

The TinyGlyph class specifies a glyph representing a unit of rendered content within a font.

Each TinyGlyph object consists of an identifier (unicode char) along with drawing instructions (TinyPath) for rendering that particular glyph. The horizAdvX is a metric that is used to describe how the glyph must be placed and managed when rendering text.

How to read TinyFont from TinyLine 2D data stream

In your application you will load TinyFont object using loadFont function defined in MIDPTiny2DCanvas (or PPTiny2DCanvas )

        /* Loads the font */
        font = canvas.loadFont("/tarial.bin");

where the loadFont() function uses TinyInputStream:

        TinyFont f = null;
        InputStream is = null;
        TinyInputStream tis = null;

         . . .

         // Reads and parses the stream
         tis =  new TinyInputStream(is);
         f = tis.readTinyFont();

How to write TinyFont to TinyLine 2D data stream

In order to store the TinyFont object to TinyLine 2D data stream you can use SVGT2Bin tool.

    1. Reads SVG Tiny 1.1 font from an input stream and parses it into TinyFont object.
    2. Writes TinyFont object into TinyLine 2D data stream.

6.3 Bounds and hit test

As we said before every shape in TinyLine 2D has a bounding box. The same apply to texts as well. The bounding box is a rectangle that fully encloses the shape's geometry. Bounding boxes are used to determine whether or not an object has been selected or "hit" by the user or what area the object occupies on the canvas.

We use TinyRect class for bounding boxes.

The following example is interesting from many points of view including bounding boxes and coordinate spaces.

Example: HitText.java

hittext

View the example as applet (Java-enabled browsers only)

The example shows how to use hitPath function for moving the text around the canvas.

We will move the text over the canvas with the help of pointer device (or mouse in the case of the desktop). Make sure that you run this example on devices with a pointer device otherwise, you will not have a fun with it.

Please look at the HitText.java code.

Because the hitTest function in Tiny2D needs a path as its input, we need to create a text outline for the later use.

       /* The text outline */
       path = Tiny2D.charsToPath(font, engText, 0, engText.length, Tiny2D.TEXT_DIR_LR);
       /* The cmat matrix */
       cmat = Tiny2D.charToUserTransform(path, font, fontSize, X, Y, Tiny2D.TEXT_ANCHOR_START);

In addition, we calculated the cmat - transformation matrix from character space to user space.

When the mouse or the pointer has been pressed in the canvas, we define if the pixel where the pointer device has been pressed "hits" our path - the text outline.

        hit = t2d.hitPath(pressedX, pressedY, path, cmat);

If the path (text outline) was hit, we want to move it onto the new position. For that, we change the transformation matrix:

        if(hit)
        {
            matrix.tx -= (pressedX - x) <<Tiny2D.FIX_BITS;
            matrix.ty -= (pressedY - y) <<Tiny2D.FIX_BITS;
        }

6.4 Measuring text before drawing

If text measurements are important to your application, it is possible to calculate those using Tiny2D functions.

Example: TextLines.java

textlines

View the example as applet (Java-enabled browsers only)

The example shows how to fit a paragraph of text within a certain width.

We want to fit our text into some shape, for example the bounding box bbox.

We go over a long character array, calculating the bounds of accumulated characters and break the current line when we touch the bbox.

    /*
     * How to line-break and draw a paragraph
     */
    public void drawTextLines()
    {
        /* We want to fit our text into some shape,
         * for example bbox (20.0, 80.0, 120.0, 120.0) */
        TinyRect bbox = new TinyRect( (20<<Tiny2D.FIX_BITS),
                                      (100<<Tiny2D.FIX_BITS),
                                      (120<<Tiny2D.FIX_BITS),
                                      (140<<Tiny2D.FIX_BITS) );

        TinyFont f = arialfont;
        int fontSize = (16<<Tiny2D.FIX_BITS);

        /* We go over a long character array, calculating the
         * bounds of accumulated characters and break the
         * current line when we touch the bbox
         */
        int Y = bbox.ymin;   /* The current line Y */
        int off = 0;         /* The current char pointer */
        int len = 0;         /* The current length of the line */

        while ( (off + len) < longLine.length && Y < bbox.ymax)
        {
             TinyRect cbox = Tiny2D.charsBounds(f, fontSize, longLine,
                             off, off+len, Tiny2D.TEXT_DIR_LR);
             if( (cbox.xmax - cbox.xmin) >  (bbox.xmax - bbox.xmin) )
             {
                /* We need to break the current line */
                len--;
                /* Draw the current line */
                t2d.matrix = new TinyMatrix();
                t2d.drawChars(f, fontSize, longLine, off, off+len,
                 bbox.xmin, Y, Tiny2D.TEXT_ANCHOR_START );

                /* Advance one line */
                off += len;
                len = 0;
                Y += (cbox.ymax - cbox.ymin);
             }
             len++;
        }
    }

In addition, the example shows how to draw text using different text layouts: left-to-right, right-to-left and top-bottom.

            /* Draws the vertical CJK text */
            tstate.textDir = Tiny2D.TEXT_DIR_TB;
            tstate.fillColor = color2;
            t2d.drawChars(cjkfont,
			 (32<<Tiny2D.FIX_BITS),
                         cjkText,0,cjkText.length,
                         (120<<Tiny2D.FIX_BITS),
                         (80<<Tiny2D.FIX_BITS),
                         Tiny2D.TEXT_ANCHOR_START);

            /* Draws the horizontal right-to-left text */
            tstate.fillColor = (color1);
            tstate.textDir = Tiny2D.TEXT_DIR_RL;
            t2d.drawChars(hebfont,
			 (20<<Tiny2D.FIX_BITS),
                         hebText,0,hebText.length,
                         (100<<Tiny2D.FIX_BITS),
                         (80<<Tiny2D.FIX_BITS),
                         Tiny2D.TEXT_ANCHOR_START);
© 2008 TinyLine. All rights reserved.