PfExtentTextCharPositions(), PfExtentTextCharPositionsCx()

Calculate individual character positions

Synopsis:

#include <photon/Pf.h>
int PfExtentTextCharPositions(
        PhRect_t * ptsExtent,
        PhPoint_t * ptsPos,
        char * psz,
        const char * pckFont,
        int32_t * piIndices,
        int32_t * piPenPositions,
        int32_t iArrayLen,
        uint32_t ulFlags,
        int32_t iBytes,
        uint32_t uiExtentLen,
        PhRect_t const * pktsClip );

#include <photon/Pf.h>
int PfExtentTextCharPositionsCx(
       struct _Pf_ctrl *context,
       PhRect_t *ptsExtent,
       PhPoint_t *ptsPos,
       char *psz,
       const char *pckFont,
       long adata,
       long bdata,
       int32_t *piIndices,
       int32_t *piPenPositions,
       int32_t iArrayLen,
       uint32_t ulFlags,
       int32_t iBytes,
       uint32_t uiExtentLen,
       PhRect_t const *pktsClip );

Arguments:

context
(PfExtentTextCharPositionsCx() only) A pointer to the font context to use, returned by PfAttachCx() or PfAttachDllCx().
ptsExtent
A pointer to a PhRect_t structure that's used to store the extent of the string.
ptsPos
A pointer to a PhPoint_t structure that's used as an offset to apply against the extent. If NULL, no offset is added to the extent values.
psz
A pointer to a NUL-terminated character string.
pckFont
The font name, as created by PfGenerateFontName().
adata
(PfExtentTextCharPositionsCx() only) The horizontal fractional point size, if you set PF_FRACTIONAL in the flags argument.
bdata
(PfExtentTextCharPositionsCx() only) The vertical fractional point size, if you set PF_FRACTIONAL in the flags argument.
iArrayLen
The number of integer entries in the piIndices and piPenPositions arrays.
piIndices
A pointer to an integer array of length iArrayLen. An index corresponds to a location within the string pointed to by psz.

For example, index 0 relates to the pen's x position at the start of the string, index 1 corresponds to the pen's x position after character 1, index 2 corresponds to the pen's x position after character 2, and so on.

In order to function as expected, the indexes must be in numerical order.

piPositions
A pointer to an integer array of length iArrayLen. This array contains the resulting pen x values (in pixels) for each index.
ulFlags
A 32-bit value used for flags. Values that can be ORed in are:
iBytes
The number of bytes in the string. If this is 0, the function assumes that the number of bytes is:
strlen( psz ) / wstrlen( psz )
  
uiExtentLen
The number of characters from the beginning of the string to include in the extent. If 0, the entire string is extented, as permitted by the clipping rectangle.
pktsClip
A clipping rectangle to be used to reduce processing, depending on the value of pktsClip->lr.x (in pixels). If pktsClip is NULL, no clipping is applied.

Library:

PfExtentTextCharPositions()
ph
PfExtentTextCharPositionsCx()
font

Description:

These functions calculate the extent up to uiExtentLen code points. They record horizontal pen positions for each code point referenced in piIndices, and continue processing until pktsClip, if defined, or to the end of the input string psz.

Returns:

0
Success.
-1
An error occurred; errno is set.

Errors:

PfExtentTextCharPositions():

ERANGE
The font manager couldn't fulfill the request; one of the following is true:
EFAULT
One of ptsExtent, piIndices, piPenPositions, pckFont, or psz is NULL.
EINVAL
The font is fixed-width, and an error occurred when trying to retrieve the common width of all characters in that particular font.
EMORE
Something unexpected occurred while processing a run of characters.

PfExtentTextCharPositionsCx():

EBADF
Connection has gone stale, or device error occurred.
ENETUNREACH
Bad message buffer.
ELIBACC
Unable to locate render plugin for specified font.
EFAULT
Unable to locate font description.
ENOENT
Unable to locate suitable base font entry.
ENOMEM
Insufficient memory to allocate scaling resources.
EINVAL
Fixed width font has invalid size.
EINVAL
Failure to load resources for specified font.

Examples:

PfExtentTextCharPositionsCx():

/* Typographic positioning example.  Demonstrates how to manipulate
 * characters, and sub-strings properly at a typographic pen level.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <Ph.h>
#include <Pt.h>
#include <errno.h>
#include <font_api.h>

int draw( PtWidget_t * ptsWidget, PhTile_t * ptsDamage );

#define FALSE 0
#define __WIN_SIZE_X_ 1000

extern struct _Ph_ctrl *_Ph_;

int main (int argc, char *argv[])
{   PtArg_t args[8];
    PhPoint_t win_size, pntPOS, pntDIM;
    int i = 0;
    PtWidget_t * win = NULL;

    fprintf(stderr, "POINT : Pen.\n");

    if(PtInit (NULL) == -1)
    {  fprintf(stderr, "NOTE : PtInit failed, errno %d.\n", errno);
       fprintf(stderr, "FAIL : Pen.\n");
       exit(EXIT_FAILURE);
    }

    //  set base win parms
    win_size.x = 800;
    win_size.y = 600;

    PtSetArg(&args[i++],Pt_ARG_DIM, &win_size, 0);
    // window title = name  of program
    PtSetArg(&args[i++],Pt_ARG_WINDOW_TITLE, "Pen Test Suite", 0);


    if((win = PtCreateWidget (PtWindow, NULL, i, args)) == NULL)
    {  fprintf(stderr, "NOTE : Unable to create main window, errno %d.\n", errno);
       fprintf(stderr, "FAIL : Pen.\n");
       exit(EXIT_FAILURE);
    }

    i = 0;
    pntPOS.y = 100;
    pntPOS.x = 75;
    pntDIM.x = __WIN_SIZE_X_ - 75 - 10;
    pntDIM.y = 300;
    PtSetArg(&args[i++], Pt_ARG_POS, &pntPOS, 0);
    PtSetArg(&args[i++], Pt_ARG_DIM, &pntDIM, 0);
    PtSetArg(&args[i++], Pt_ARG_RAW_DRAW_F, draw, 0L);
    PtSetArg(&args[i++], Pt_ARG_POINTER, "Hello, this is big Bobby!!", 0L);

    if(PtCreateWidget(PtRaw, win, i, args) == NULL)
    {  fprintf(stderr, "NOTE : Unable to create raw canvas, errno %d.\n", errno);
       fprintf(stderr, "FAIL : Pen.\n");
       exit(EXIT_FAILURE);
    }

    PtRealizeWidget(win);
    PtMainLoop ();
    return(0);
}

int draw( PtWidget_t * ptsWidget, PhTile_t * ptsDamage )
{   char const * text;

    if(PtGetResource(ptsWidget, Pt_ARG_POINTER, &text, 0L) == 0)
    {  FontName pucFont;
       struct _Pf_ctrl * ctx = _Ph_->font;

       if(PfGenerateFontNameCx(ctx, "PrimaSans BT", 0L, 12L, pucFont) != NULL)
       {  int * piIndx = NULL;
          int * piPos = NULL;
          PhPoint_t pnt;
          pf_point_t tsPos = {0, 0};
          pf_rect_t tsExtent;
          short n = 0, m = 0;
          PgColor_t old;
          PhRect_t tsClip;
          int len = strlen(text);
          char const * str = text;
          int max_chars = 0;

          if((piIndx = (int *)calloc(50, sizeof(int))) == NULL)
          {  fprintf(stderr, "NOTE : Unable to alloc indices, errno %d.\n", errno);
             fprintf(stderr, "FAIL : Pen.\n");
             exit(EXIT_FAILURE);
          }

          if((piPos = (int *)calloc(50, sizeof(int))) == NULL)
          {  fprintf(stderr, "NOTE : Unable to alloc positions, errno %d.\n", errno);
             fprintf(stderr, "FAIL : Pen.\n");
             exit(EXIT_FAILURE);
          }

          PtCalcCanvas(ptsWidget, &tsClip);
          PtClipAdd(ptsWidget, &tsClip);
          PtSuperClassDraw( PtBasic, ptsWidget, ptsDamage );
          tsClip.ul.x += 2;
          tsClip.ul.y += 10;
          PgSetTranslation (&tsClip.ul, Pg_RELATIVE);

          while(len > 0)
          {  wchar_t wc;
             int cl;

             if((cl = mbtowc(&wc, str, MB_CUR_MAX)) <= 0)
             {  --len, ++str;

                if (cl) continue;
                wc = 0;
             }
             else
             {  len -= cl, str += cl;
                max_chars++;
             }
          }
          len = strlen(text);

          for(n = 0; n < max_chars; n++)
            piIndx[n] = n + 1;

          old = PgSetStrokeColor(Pg_BLACK);
          PgSetFont(pucFont);
          PgSetTextColor(Pg_BLACK);

          if(PfExtentCx(ctx, &tsExtent, &tsPos, pucFont, 0L, 0L, text, len, 0,
                        NULL) == 0)
          {  //__STRING_DRAW_
             fprintf(stderr, "NOTE : start Draw text string.\n");
             pnt.x = 10 + tsClip.ul.x;
             pnt.y = 10 + tsClip.ul.y;

             PgDrawIRect(tsExtent.ul.x + pnt.x, tsExtent.ul.y + pnt.y,
                         (tsExtent.lr.x - min(tsExtent.ul.x, 0) + 1) + pnt.x,
                         tsExtent.lr.y + pnt.y, Pg_DRAW_STROKE);
             PgDrawText(text, len, &pnt, 0);
             PgFlush();

             printf("EXTENT_NORMAL:  ul.x:  %d ul.y:  %d lr.x:  %d lr.y:  %d\n",
                    tsExtent.ul.x, tsExtent.ul.y, tsExtent.lr.x, tsExtent.lr.y);
             printf("POSITIONS:  ");

             if(PfExtentTextCharPositionsCx(ctx, &tsExtent, &tsPos, text, pucFont,
                   0L, 0L, piIndx, piPos, len, 0L, 0, 0, NULL) == 0)
             {  for(n = 0; n < max_chars; n++)
                  printf("%d ", piPos[n]);

                printf("\n");
                printf("EXTENT_POS:  ul.x:  %d ul.y:  %d lr.x:  %d lr.y:  %d\n",
                       tsExtent.ul.x, tsExtent.ul.y, tsExtent.lr.x, tsExtent.lr.y);
             }
             else
             {  fprintf(stderr, "NOTE : PfExtentTextCharPositions failed, errno %d.\n",
                        errno);
                fprintf(stderr, "FAIL : Pen.\n");
                exit(EXIT_FAILURE);
             }

             fprintf(stderr, "NOTE : end Draw text string.\n");

             //__SINGLE_CHAR_DRAW_
             for(n = 0; n < max_chars; n++)
               piIndx[n] = n + 1;

             fprintf(stderr,
                     "NOTE : start Draw the string, one character at a time.\n");

             if(PfExtentTextCharPositionsCx(ctx, &tsExtent, &tsPos, text, pucFont,
                   0L, 0L, piIndx, piPos, len, 0L, 0, 0, NULL) == -1)
             {  fprintf(stderr,
                        "NOTE : PfExtentTextCharPositions failed, errno %d.\n",
                        errno);
                fprintf(stderr, "FAIL : Pen.\n");
                exit(EXIT_FAILURE);
             }

             pnt.x = 10 + tsClip.ul.x;
             pnt.y = 50 + tsClip.ul.y;

             PgDrawIRect(tsExtent.ul.x + pnt.x, tsExtent.ul.y + pnt.y,
                         (tsExtent.lr.x - min(tsExtent.ul.x, 0) + 1) + pnt.x,
                         tsExtent.lr.y + pnt.y, Pg_DRAW_STROKE);

             for(n = 0; n < max_chars; n++)
             {  PgDrawText(text + n, 1, &pnt, 0);
                PgFlush();
                pnt.x = 10 + tsClip.ul.x + piPos[n];
                fprintf(stderr, "NOTE : Single[%d]:  %d\n", n, piPos[n]);
             }

             fprintf(stderr,
                     "NOTE : end Draw the string, one character at a time.\n");

             //__TWO_CHUNK_DRAW_
             fprintf(stderr, "NOTE : start Draw the string in two chunks.\n");
             pnt.x = 10 + tsClip.ul.x;
             pnt.y = 100 + tsClip.ul.y;

             PgDrawText(text, 2, &pnt, 0);
             PgFlush();
             sleep(1);
             pnt.x = 10 + tsClip.ul.x + piPos[1];
             PgDrawText(text + 2, len - 2, &pnt, 0);
             PgFlush();
             fprintf(stderr, "NOTE : end Draw the string in two chunks.\n");

             //__PRINT_POSITIONS_
             fprintf(stderr, "NOTE : start print positions.\n");

             for(n = max_chars - 1; n >= 0; n--)
             {  piIndx[0] = n + 1;

                if(PfExtentTextCharPositionsCx(ctx, &tsExtent, &tsPos, text, pucFont,
                      0L, 0L, piIndx, piPos, 1, 0L, 0, 0, NULL) == 0)
                {  for(m = 0; m < 1; m++)
                   fprintf(stderr, "NOTE : Position:  %d\n", piPos[m]);
                   fprintf(stderr,
                      "NOTE : EXTENT_POS ul.x:  %d ul.y:  %d lr.x:  %d lr.y:  %d\n",
                      tsExtent.ul.x, tsExtent.ul.y, tsExtent.lr.x, tsExtent.lr.y);
                }
                else
                {  fprintf(stderr,
                      "NOTE : PfExtentTextCharPositions failed, errno %d.\n",
                      errno);
                   fprintf(stderr, "FAIL : Pen.\n");
                   exit(EXIT_FAILURE);
                }
             }
             fprintf(stderr, "NOTE : end print positions.\n");

             //__DRAW_OVERLAY_
             fprintf(stderr,
                "NOTE : start Draw string, then overlay individual characters on \
 top from right to left.\n");

             if(PfExtentCx(ctx, &tsExtent, &tsPos, pucFont, 0L, 0L, text, len, 0,
                           NULL) == 0)
             {  pnt.x = 10 + tsClip.ul.x;
                pnt.y = 150 + tsClip.ul.y;

                PgDrawIRect(tsExtent.ul.x + pnt.x, tsExtent.ul.y + pnt.y,
                            (tsExtent.lr.x - min(tsExtent.ul.x, 0) + 1)
                            + pnt.x, tsExtent.lr.y + pnt.y, Pg_DRAW_STROKE);

                for(n = max_chars - 1; n >= 0; n--)
                {  switch(n)
                   {  case 0:  pnt.x = 10 + tsClip.ul.x;
                               PgDrawText(text + 0, len, &pnt, 0);
                               PgFlush();
                               break;

                      default: piIndx[0] = n;

                               if(PfExtentTextCharPositionsCx(
                                     ctx, &tsExtent, &tsPos, text,
                                     pucFont, 0L, 0L, piIndx, piPos,
                                     1, 0L, 0, 0, NULL) == -1)
                               {  fprintf(stderr,
                                     "NOTE : PfExtentTextCharPositions failed, \
 errno %d.\n", errno);
                                  fprintf(stderr, "FAIL : Pen.\n");
                                  exit(EXIT_FAILURE);
                               }
                               else
                               {  fprintf(stderr, "NOTE : Position:  %d\n", piPos[0]);
                                  pnt.x = 10 + tsClip.ul.x + piPos[0];
                                  PgDrawText(text + n, len - n, &pnt, 0);
                                  PgFlush();
                               }
                               break;
                   }
                }
             }
             else
             {  fprintf(stderr, "NOTE : PfExtentText failed, errno %d.\n", errno);
                fprintf(stderr, "FAIL : Pen.\n");
                exit(EXIT_FAILURE);
             }
             fprintf(stderr,
                "NOTE : end Draw string, then overlay individual characters on \
 top from right to left.\n");

             //__TEST_OUTORDER_
             fprintf(stderr, "NOTE : start Test indices which are non-sequential.\n");
             for(n = 0; n < 4; n++)
             {  struct element
                {  int first;
                   int second;
                };

                struct element times[4] = { { 1, 5 }, { 2, 4 }, { 3, 5 }, { 2, 5} };
                piIndx[0] = times[n].first;
                piIndx[1] = times[n].second;

                if(PfExtentTextCharPositionsCx(ctx, &tsExtent, &tsPos, text,
                      pucFont, 0L, 0L, piIndx, piPos, 2, 0L, 0, 0, NULL) == -1)
                {  fprintf(stderr,
                      "NOTE : PfExtentTextCharPositions failed, errno %d.\n",
                      errno);
                   fprintf(stderr, "FAIL : Pen.\n");
                   exit(EXIT_FAILURE);
                }
                else
                {  fprintf(stderr, "NOTE : Position[%d]:  %d\n", times[n].first,
                           piPos[0]);
                   fprintf(stderr, "NOTE : Position[%d]:  %d\n", times[n].second,
                           piPos[1]);
                }
             }
             fprintf(stderr, "NOTE : end Test indices which are non-sequential.\n");
          }
          else
          {  fprintf(stderr, "NOTE : PfExtentText failed, errno %d.\n", errno);
             fprintf(stderr, "FAIL : Pen.\n");
             exit(EXIT_FAILURE);
          }

          PgSetStrokeColor(old);
          free(piPos);
          free(piIndx);

          tsClip.ul.x *= -1;
          tsClip.ul.y *= -1;
          PgSetTranslation (&tsClip.ul, Pg_RELATIVE);
          PtClipRemove();
       }
       else
       {  fprintf(stderr, "NOTE : Unable to create raw canvas, errno %d.\n", errno);
          fprintf(stderr, "FAIL : Pen.\n");
          exit(EXIT_FAILURE);
       }
   }
   else
   {  fprintf(stderr, "NOTE : Unable to create raw canvas, errno %d.\n", errno);
      fprintf(stderr, "FAIL : Pen.\n");
      exit(EXIT_FAILURE);
   }

   fprintf(stderr, "PASS : Pen.\n");
   exit(EXIT_SUCCESS);
   return( Pt_CONTINUE );
}

PfExtentTextCharPositions():

#define MAX_INDICES 5
#define FALSE 0

int iaIndex[MAX_INDICES] = {0, 1, 2, 3, 4};
int iaPosition[MAX_INDICES];
PhRect_t tsExtent;
char caBuff[MAX_FONT_TAG];

PfGenerateFontName("Helvetica", 0, 24, caBuff);

if( PfExtentTextCharPositions( &tsExtent, NULL,
       "Lucy", caBuff, iaIndex, iaPositon,
        MAX_INDICES, 0L, 0, 0, NULL) != EOK)
  printf("Error in PfExtentTextCharPositions().\n");
else
  printf("Pixel penx positions after each character \
in string %s, are as follows: %d %d %d %d %d.\n",
         "Lucy", iaPosition[0], iaPosition[1],
         iaPosition[2], iaPosition[3],
         iaPositionArray[4]);

The pixel pen x positions for each character in the string Lucy are placed in the integer array iaPos, according to the indexes specified in iaIndex. Index 0 corresponds to the position before symbol L, index 1 corresponds to the position after L, index 2 corresponds to the position after u, and so on.

Classification:

Photon

PfExtentTextCharPositions()

Safety:
Interrupt handler No
Signal handler No
Thread No

PfExtentTextCharPositionsCx()

Safety:
Interrupt handler No
Signal handler No
Thread Yes

See also:

PfExtent(), PfExtentCx(), PfExtentText(), PfExtentTextCharPositionsCx(), PfExtentTextToRect(), PfExtentFractTextCharPositions(), PfFractionalExtentText(), PfGenerateFontName(), PfGenerateFontNameCx(), PhPoint_t, PhRect_t

Fonts chapter of the Photon Programmer's Guide