Chapter 9
Position-Based Decoration

   9.1 Background
   9.2 Compute Character Position
   9.3 Compute Ruler Position
   9.4 Boundary Conditions
   9.5 Scan Coefficients

9.1 Background

We assume a rectangualar canvase for which we can provide the measurements, as well as the location of each character and ruler in it.

A region starts and ends with a ‘\special{t4ht"}’. The entry point gets coordinates (0,0). It is configured wuth

\special{t4ht"% 
    * before-all 
    * after-all     %right  %left %height %depth 
    ............. 
    ** before-char   %x %y 
    * after-char 
    * line          %x %y %thickness %length 
    * x-coefficients: A-magnification, B-displacement %A(x) + %B 
    * y-coefficients: C-magnification, D-displacement, E/F-origin 
                           %C(y + (%E(up) | %F(height+depth))  ) + %D 
 } 

The ‘*’ is a seperator character, and it can be replaced by other characters.

We assume C-type templates, where values are assumed to be in float decimals (e.g., ‘%.2f’; replacing 2 by 0, implies an integer).

The ‘* after-all’ can be repeated arbitrary many times (must appear at least once). The last one is found when ‘**’ is encountered.

The first character in each ‘after-all’ is treated as a code: x-min x, X-max x, y-min , Y-max y, w-dx, h-dy, otherwise-string with no value. We need the codes to enable arbitrary combinations of values.

The ‘before-char’ must be non-empty for ‘%x %y’ to be printed. The case is similar for the ruler. If both are empty, we just measure the dvi dimensions–can be used for applets.

9.2 Compute Character Position

<..pos dvi ch..>
 if( pos_dvi ){       long int d;
   if( *pos_text ){
     <.open output file.>
     (IGNORED) fprintf(cur_o_file, pos_text,
          pos_x_A * (x_val - base_pos_x) + pos_x_B,
          pos_y_C * (y_val - base_pos_y) + pos_y_D);
   }
   if( x_val < min_pos_x )                       min_pos_x = x_val;
   if( (d = x_val + <.ch width.>)  > max_pos_x ) max_pos_x = d;
   if( (d = y_val - <.ch height.>) < min_pos_y ) min_pos_y = d;
   if( (d = y_val + <.ch depth.>)  > max_pos_y ) max_pos_y = d;
 }
 -_-_-

<..end pos dvi ch..>
 if( pos_dvi ){
    print_f(end_pos_text);
 }
 -_-_-

[more]).

[?]

9.3 Compute Ruler Position

<..pos dvi x rule..>
          long int d;
 if( (up > 0) && (right > 0) ){
    if(  *pos_line ){
                       double from_x, from_y;
      <.open output file.>
      from_x = pos_x_A * (x_val - base_pos_x) + pos_x_B;
      from_y = pos_y_C * (y_val - pos_y_E * up - base_pos_y) + pos_y_D;
      switch (rect_pos){
        case 1: {
               (IGNORED) fprintf(cur_o_file, pos_line,
                    from_x, from_y,
                    pos_x_A * right + pos_x_B  + from_x,
                    pos_y_C * up + pos_y_D  + from_y );
                break; }
        case 2: {
               (IGNORED) fprintf(cur_o_file, pos_line,
                    from_x, from_y,
                    pos_x_A * right + pos_x_B + from_x,
                    from_y,
                    pos_y_C * up + pos_y_D  );
                break; }
        default: {
               (IGNORED) fprintf(cur_o_file, pos_line,
                    from_x, from_y,
                    pos_x_A * right,
                    pos_y_C * up);
                }
       }
    }
    if( x_val < min_pos_x )           min_pos_x = x_val;
    if( (d = x_val + right) > max_pos_x ) max_pos_x = d;
    if( (d = y_val - up) < min_pos_y ) min_pos_y = d;
    if( y_val > max_pos_y )           max_pos_y = y_val;
 }
 -_-_-

9.4 Boundary Conditions

<..positioned content..>
 if( special_n ){
    <.read pos instructions.>
 } else if( (pos_dvi = !pos_dvi) == TRUE ){
    print_f(pos_body);
    min_pos_x = max_pos_x = base_pos_x = x_val;
    min_pos_y = max_pos_y = base_pos_y = y_val ;
 } else {                     U_CHAR   *p;
                              double dim=0.0;
                              BOOL   dim_on;
   <.open output file.>
   p = end_pos_body;
   while( *p ){
     dim_on = TRUE;
     switch( *p ){
        <.dim = pos value.>
         default: { dim_on = FALSE; }
     }
     p++;
     if( dim_on ){    (IGNORED) fprintf(cur_o_file, p, dim);  }
     else        {    (IGNORED) fprintf(cur_o_file, "%s", p); }
     while( * (p++) );
   }
 }
 -_-_-

The pattern of of ‘end_pos_body’ has a ‘\0’ at the end of each segment, and the last segment is empty. Hence, it ends with a ‘\0\0’.

<..dim = pos value..>
 case ’X’: {  dim = pos_x_A * (max_pos_x - base_pos_x) + pos_x_B;
              break; }
 case ’x’: {  dim = pos_x_A * (base_pos_x - min_pos_x) + pos_x_B;
              break; }
 case ’d’: {  dim = pos_x_A * (max_pos_x - min_pos_x) + pos_x_B;
              break; }
 case ’y’: {  dim = pos_y_C * (base_pos_y - min_pos_y - 1) + pos_y_D;
              break; }
 case ’Y’: {  dim = pos_y_C * (max_pos_y - base_pos_y) + pos_y_D;
              break; }
 case ’D’: {  dim = pos_y_C * (max_pos_y - min_pos_y) + pos_y_D;
              break; }
 -_-_-

<..vars..>+
 static BOOL pos_dvi = FALSE;
 static U_CHAR   *pos_body,     * pos_text,     * pos_line,
        *end_pos_body, * end_pos_text;
 static double   pos_x_A, pos_x_B, pos_y_C, pos_y_D, pos_y_E;
 static long int base_pos_x, base_pos_y, min_pos_x,
          max_pos_x, min_pos_y, max_pos_y;
 static short rect_pos;
 -_-_-

9.5 Scan Coefficients

Note that ‘pos_body’ points to the left-most byte in the template.

<..main’s init..>+
 pos_text = pos_line = end_pos_body = end_pos_text = pos_body =
                       m_alloc(char, (int) 1);
 (IGNORED) strcpy((char *) pos_text, "" );
 -_-_-

<..read pos instructions..>
 {                       U_CHAR * p, ch, i;
   ch = get_char();
   p = pos_text = pos_line = end_pos_text
     = end_pos_body = pos_body
     = (char *)  r_alloc((void *) pos_body,(size_t) special_n + 1);
   i = 0;  <.scan templates for pos.>
   <.scan constants for pos.>
   if( (i != 10) || special_n ){
     warn_i_str(39,pos_text);
     *(pos_text = end_pos_body = pos_line =
       end_pos_text = pos_body) = ’\0’;
   }
 }
 -_-_-

<..scan templates for pos..>
 {                               BOOL after_star=0;
    while(  special_n-- > 0 ){
       if( (*p = get_char()) == ch ){
          *p = ’\0’; i++;
               if( i==1 ){ end_pos_body = p + 1;   after_star = FALSE; }
          else if( i==2 ){ pos_text     = p + 1;
                           if( !after_star ){  i--;  after_star = TRUE; }
                         }
          else if( i==3 ){ end_pos_text = p + 1; }
          else if( i==4 ){ pos_line     = p + 1; }
          else           { p++; break; }
       } else { after_star = FALSE; }
       p++;
    }
 }
 -_-_-

<..scan constants for pos..>
 {                     long int v=0;
                       double w[5];
                       int j;
                       U_CHAR ch, sign;
                       BOOL done;
   for(j=0;j<5;j++){
     <.v = int part; sign = ....>
     if( done ){
       i++;
       w[j] = sign * ((double) v + pos_dbl( &special_n ));
     }
   }
   pos_x_A = w[0];  pos_x_B = w[1];
   pos_y_C = w[2];  pos_y_D = w[3]; pos_y_E = w[4];
 }
 rect_pos = (special_n == 2);
 if( rect_pos ){  special_n -= 2;  rect_pos = get_char() - ’0’;}
 -_-_-

<..v = int part; sign = .....>
 done = FALSE;  sign = 1;
 if( --special_n > 0 ){
   if( (ch = get_char()) == ’-’ ){ sign = -1; v=0; }
   else v = ch - ’0’;
   if( (v<0) || (v>9) ) done = TRUE;
 }
 if( !done )
    while(  --special_n > 0 ){
      ch = get_char();
      if( (’0’ <= ch ) && (ch <= ’9’ ) ){
         v =  v * 10 + ch - ’0’; }
      else{  done = TRUE;  break; }
    }
 -_-_-

<..header functions..>+
 static double pos_dbl( ARG_I(long int *) );
 -_-_-

<..functions..>+
 
 static double pos_dbl( special_n )       long  int *  special_n
 ;{
                 U_CHAR ch;
                 double v;
                 int d;
   v = 0.0; d = 10;
   while(  --(*special_n) > 0 ){
     ch = get_char();
     if( (’0’ <= ch ) && (ch <= ’9’ ) ){
        v += (double) (ch -’0’) / d;  d *= 10; }
     else break;
   }
   return v;
 }
 -_-_-

<..err int pos..>
 123454321
 -_-_-