/* Copyright 1996 Acorn Computers Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/************************************************************************/
/* � Acorn Computers Ltd, 1992.                                         */
/*                                                                      */
/* This file forms part of an unsupported source release of RISC_OSLib. */
/*                                                                      */
/* It may be freely used to create executable images for saleable       */
/* products but cannot be sold in source form or as an object library   */
/* without the prior written consent of Acorn Computers Ltd.            */
/*                                                                      */
/* If this file is re-distributed (even if modified) it should retain   */
/* this copyright notice.                                               */
/*                                                                      */
/************************************************************************/

/*
 * Title  : c.font
 * Purpose: access to RISC OS font facilities
 * History: IDJ: 06-Feb-92: prepared for source release
 */
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "os.h"
#include "trace.h"
#include "msgs.h"
#include "wimp.h"
#include "font.h"
#include "VerIntern/messages.h"

/*                          F O N T    S W I 's                          */
#define CacheAddr            0x40080
#define FindFont             0x40081
#define LoseFont             0x40082
#define ReadDefn             0x40083
#define ReadInfo             0x40084
#define StringWidth          0x40085
#define Paint                0x40086
#define Caret                0x40087
#define ConverttoOS          0x40088
#define Converttopoints      0x40089
#define SetFont              0x4008A
#define CurrentFont          0x4008B
#define FutureFont           0x4008C
#define FindCaret            0x4008D
#define CharBBox             0x4008E
#define ReadScaleFactor      0x4008F
#define SetScaleFactor       0x40090
#define ListFonts            0x40091
#define SetFontColours       0x40092
#define SetPalette           0x40093
#define ReadThresholds       0x40094
#define SetThresholds        0x40095
#define FindCaretJ           0x40096
#define StringBBox           0x40097
#define ReadColourTable      0x40098
#define MakeBitmap           0x40099
#define UnCacheFile          0x4009A
#define SetFontMax           0x4009B
#define ReadFontMax          0x4009C
#define ReadFontPrefix       0x4009D
#define SwitchOutputToBuffer 0x4009E
#define ReadFontMetrics      0x4009F
#define DecodeMenu           0x400A0
#define ScanString           0x400A1
#define SetColourTable       0x400A2

#pragma -s1

#ifndef UROM
os_error *font_cacheaddress(int *version, int *cacheused,
                            int *cachesize)

{
    os_regset r;
    os_error *e;

    r.r[0] = 0;
    e = os_swix(CacheAddr, &r);

    if (!e)
    {
      *version = r.r[0];
      *cacheused = r.r[1];
      *cachesize = r.r[2];
    }

    return e;
}
#endif

os_error *font_find(char *name, int xsize, int ysize, int xres,
                    int yres, font *fontadd)
{
    os_regset r;
    os_error *e;

    r.r[1] = (int)name;
    r.r[2] = xsize;
    r.r[3] = ysize;
    r.r[4] = xres;
    r.r[5] = yres;

    e = os_swix(FindFont, &r);

    *fontadd = (font) r.r[0];

    return e;
}


os_error *font_lose(font f)
{
    os_regset r;
    os_error *e;

    r.r[0] = f;
    e = os_swix(LoseFont, &r);
    return e;
}


#ifndef UROM
os_error * font_readdef(font f, font_def *d)

{
    os_regset r;
    os_error *e;

    r.r[0] = (int)f;
    r.r[1] = (int)&d->name;

    e = os_swix(ReadDefn, &r);

    d->xsize = r.r[2];
    d->ysize = r.r[3];
    d->xres = r.r[4];
    d->yres = r.r[5];
    d->usage = r.r[6];
    d->age = r.r[7];

    return(e);
}
#endif

os_error *font_readinfo(font f, font_info *i)
{
    os_regset r;
    os_error *e;

    r.r[0] = f;

    e = os_swix(ReadInfo, &r);

    i->minx = r.r[1];
    i->miny = r.r[2];
    i->maxx = r.r[3];
    i->maxy = r.r[4];

    return e;
}


os_error *font_strwidth(font_string *fs)
{
    os_regset r;
    os_error *e;

    r.r[1] = (int)fs->s;
    r.r[2] = fs->x;
    r.r[3] = fs->y;
    r.r[4] = fs->split;
    r.r[5] = fs->term;

    e = os_swix(StringWidth, &r);

    fs->x = r.r[2];
    fs->y = r.r[3];
    fs->split = r.r[4];
    fs->term = r.r[5];

    return e;
}


os_error *font_paint(char *s, int options, int x, int y)
{
    os_regset r;
    os_error *e;

    r.r[1] = (int)s;
    r.r[2] = options;
    r.r[3] = x;
    r.r[4] = y;

    e = os_swix(Paint, &r);

    return e;
}


#ifndef UROM
os_error *font_caret(int colour, int height, int flags, int x, int y)
{
    os_regset r;
    os_error *e;

    r.r[0] = colour;
    r.r[1] = height;
    r.r[2] = flags;
    r.r[3] = x;
    r.r[4] = y;

    e = os_swix(Caret, &r);

    return e;
}
#endif


os_error *font_converttoos(int x_inch, int y_inch, int *x_os,
                           int *y_os)
{
    os_regset r;
    os_error *e;

    r.r[1] = x_inch;
    r.r[2] = y_inch;

    e = os_swix(ConverttoOS, &r);

    *x_os = r.r[1];
    *y_os = r.r[2];

    return e;
}

#ifndef UROM
os_error *font_converttopoints(int x_os, int y_os, int *x_inch,
                               int *y_inch)
{
    os_regset r;
    os_error *e;

    r.r[1] = x_os;
    r.r[2] = y_os;

    e = os_swix(Converttopoints, &r);

    *x_inch = r.r[1];
    *y_inch = r.r[2];

    return e;
}
#endif

os_error *font_setfont(font f)
{
    os_regset r;
    os_error *e;

    r.r[0] = f;

    e = os_swix(SetFont, &r);

    return(e);
}

#ifndef UROM
os_error *font_current(font_state *f)
{
    os_regset r;
    os_error *e;

    e = os_swix(CurrentFont, &r);

    f->f = r.r[0];
    f->back_colour = r.r[1];
    f->fore_colour = r.r[2];
    f->offset = r.r[3];

    return(e);
}
#endif

#ifndef UROM
os_error *font_future(font_state *f)
{
    os_regset r;
    os_error *e;

    e = os_swix(FutureFont, &r);

    f->f = r.r[0];
    f->back_colour = r.r[1];
    f->fore_colour = r.r[2];
    f->offset = r.r[3];

    return(e);
}
#endif


os_error *font_findcaret(font_string *fs)
{
    os_regset r;
    os_error *e;

    r.r[1] = (int)fs->s;
    r.r[2] = fs->x;
    r.r[3] = fs->y;

    e = os_swix(FindCaret, &r);

    fs->x = r.r[2];
    fs->y = r.r[3];
    fs->split = r.r[4];
    fs->term = r.r[5];

    return e;
}


os_error *font_charbbox(font f, char ch, int options, font_info *i)
{
    os_regset r;
    os_error *e;

    r.r[0] = f;
    r.r[1] = ch;
    r.r[2] = options;

    e = os_swix(CharBBox, &r);

    i->minx = r.r[1];
    i->miny = r.r[2];
    i->maxx = r.r[3];
    i->maxy = r.r[4];

    return e;
}

#ifndef UROM
os_error *font_readscalefactor(int *x, int *y)
{
    os_regset r;
    os_error *e;

    e = os_swix(ReadScaleFactor, &r);

    *x = r.r[1];
    *y = r.r[2];

    return e;
}
#endif

#ifndef UROM
os_error *font_setscalefactor(int x, int y)
{
    os_regset r;
    os_error *e;

    r.r[1] = x;
    r.r[2] = y;

    e = os_swix(SetScaleFactor, &r);

    return e;
}
#endif

#ifndef UROM
os_error *font_list(char *a, int *count)
{
    os_regset r;
    os_error *e;
    int i;

    r.r[1] = (int)a;
    r.r[2] = *count;
    r.r[3] = -1;

    e = os_swix(ListFonts, &r);

    if (!e)

      {

      *count = r.r[2];
      i = 0;

      while (a[i] >= 32 && i <= 99)

           ++i;

      a[i] = 0;

      }

    else /* error return: probably some filing system error */

      *count = -1; /* signal end of list */

    return e;
}
#endif


os_error *font_setcolour(font f, int background, int foreground,
                         int offset)
{
    os_regset r;
    os_error *e;

    r.r[0] = f;
    r.r[1] = background;
    r.r[2] = foreground;
    r.r[3] = offset;

    e = os_swix(SetFontColours, &r);

    return e;
}

#ifndef UROM
os_error *font_setpalette(int background, int foreground, int offset,
                          int physical_back, int physical_fore)

{
    os_regset r;
    os_error *e;

    r.r[1] = background;
    r.r[2] = foreground;
    r.r[3] = offset;
    r.r[4] = physical_back;
    r.r[5] = physical_fore;

    e = os_swix(SetPalette, &r);

    return e;
}
#endif

#ifndef UROM
os_error *font_readthresholds(font_threshold *th)
{
    os_regset r;
    os_error *e;

    r.r[1] = (int)th;

    e = os_swix(ReadThresholds, &r);

    return e;
}
#endif

#ifndef UROM
os_error *font_setthresholds(font_threshold *th)
{
    os_regset r;
    os_error *e;

    r.r[1] = (int)th;

    e = os_swix(SetThresholds, &r);

    return e;
}
#endif

#ifndef UROM
os_error *font_findcaretj(font_string *fs, int offset_x, int offset_y)
{
    os_regset r;
    os_error *e;

    r.r[1] = (int)fs->s;
    r.r[2] = fs->x;
    r.r[3] = fs->y;
    r.r[4] = offset_x;
    r.r[5] = offset_y;

    e = os_swix(FindCaretJ, &r);

    fs->x = r.r[2];
    fs->y = r.r[3];
    fs->split = r.r[4];
    fs->term = r.r[5];

    return e;
}
#endif

os_error *font_stringbbox(char *s, font_info *fi)
{
    os_regset r;
    os_error *e;

    r.r[1] = (int)s;

    e = os_swix(StringBBox, &r);

    fi->minx = r.r[1];
    fi->miny = r.r[2];
    fi->maxx = r.r[3];
    fi->maxy = r.r[4];

    return e;
}

/*-----------------------------------------------------------------*/
/*Routines for conversion of fonts to Draw module path objects. See
   the documentation of SWI Font_SwitchOutputToBuffer.*/

os_error
   *font_output_to_null
   (  BOOL add_hints,
      BOOL output_skeleton,
      font_action_on_bitmap action_on_bitmap
   )

/*Redirects the output from font_paint to nowhere, in preparation for
   font_output_size.*/

{  os_regset reg_set;
   os_error *error;

   tracef0 ("font_output_to_null\n");

   reg_set.r [0] =
      1 /*no output*/ +
      (add_hints? 1 << 1: 0) +
      (output_skeleton? 1 << 2: 0) +
      (  action_on_bitmap == font_ERROR?
            1 << 4:
         action_on_bitmap == font_CONVERT?
            1 << 3:
            0
      );
   reg_set.r [1] = 8;

   if ((error = os_swix (SwitchOutputToBuffer, &reg_set)) != NULL)
      return error;

   return NULL;
}
/*-----------------------------------------------------------------*/
os_error *font_output_size (size_t *size_ptr)

/*Counts the size of the buffer that would have been written if the
   output had been to a buffer.*/

{  os_regset reg_set;
   os_error *error;

   tracef0 ("font_output_size\n");

   reg_set.r [0] =  0;
   reg_set.r [1] = -1;

   if ((error = os_swix (SwitchOutputToBuffer, &reg_set)) != NULL)
      return error;

   *size_ptr = reg_set.r [1];
   tracef1 ("font_output_size: made %d bytes of path\n", *size_ptr);
   return NULL;
}
/*-----------------------------------------------------------------*/

os_error
   *font_output_to_buffer
   (  drawmod_buffer *buff_ptr,
      BOOL add_hints,
      BOOL output_skeleton,
      font_action_on_bitmap action_on_bitmap
   )

/*Redirects the output to a buffer. A series of draw paths or groups
   is written.*/

{  os_regset reg_set;
   os_error *error;

   tracef0 ("font_output_to_buffer\n");

   reg_set.r [0] =
      (add_hints? 1 << 1: 0) +
      (output_skeleton? 1 << 2: 0) +
      (  action_on_bitmap == font_ERROR?
            1 << 4:
         action_on_bitmap == font_CONVERT?
            1 << 3:
            0
      );
   reg_set.r [1] = (int) buff_ptr;

   tracef1 ("font_output_to_buffer: path going to 0x%p\n", buff_ptr);
   if ((error = os_swix (SwitchOutputToBuffer, &reg_set)) != NULL)
      return error;

   return NULL;
}

/*-----------------------------------------------------------------*/

os_error *font_output_to_screen (void)

/*Redirects the output to the screen.*/

{  os_regset reg_set;
   os_error *error;

   tracef0 ("font_output_to_screen\n");

   reg_set.r [0] = 0;
   reg_set.r [1] = 0;

   if ((error = os_swix (SwitchOutputToBuffer, &reg_set)) != NULL)
      return error;

   return NULL;
}

#pragma -s0

/*-----------------------------------------------------------------*/

static os_error errbuff={0};

os_error *font_makemenu(wimp_menustr ** menup, char * tickitem, fontmenu_flags flags)
{
   os_regset r;
   os_error *error;

   tracef3 ("font_makemenu: *menup=0x%p, tickitem=0x%p, flags=%d\n", *menup, tickitem, flags);

   switch(flags) {

     case fontmenu_WithoutSystemFont:
          r.r[2] = (1<<19) + (1<<21);
          break;

     case fontmenu_WithSystemFont:
          r.r[2] = (1<<19) + (1<<20) + (1<<21);
          break;

     case fontmenu_Delete:
          if (*menup) { free(*menup); *menup = NULL; }
          return NULL;

     default:
          errbuff.errnum = 1;
          strcpy(errbuff.errmess,msgs_lookup(MSGS_fontmenu1));
          return(&errbuff);
   }

   r.r[1] = 0;        /* return size of buffer in R3 */
   r.r[4] = 0;        /* return size of buffer in R5 */
   r.r[6] = (int) tickitem;

   if ((error = os_swix (ListFonts, &r)) != NULL) return error;

   r.r[1] = (int) realloc(*menup,r.r[3] + r.r[5]);
   if (r.r[1]) {
     *menup = (wimp_menustr *)r.r[1];
   } else {
     errbuff.errnum = 1;
     strcpy(errbuff.errmess,msgs_lookup(MSGS_fontmenu2));
     return(&errbuff);
   }
   r.r[4] = r.r[1] + r.r[3];

   error = os_swix (ListFonts, &r);

   if (r.r[3] && !error) {
      *menup = (void *)r.r[1];
   } else {
      free(*menup);
      *menup = NULL;
   }

   return(error);
}

/*-----------------------------------------------------------------*/

extern os_error *font_decodemenu(wimp_menustr * menu, int * selections, char **resultp)
{
   os_regset r;
   os_error *error;

   tracef3 ("font_decodemenu: menu=0x%p, selection[0]=%d, old buffer=0x%p\n", menu, selections[0], *resultp);

   r.r[0] = 0;
   r.r[1] = (int) menu;
   r.r[2] = (int) selections;
   r.r[3] = 0;
   if ((error = os_swix(DecodeMenu,&r)) != NULL) return error;

   r.r[0] = 0;
   r.r[1] = (int) menu;
   r.r[2] = (int) selections;
   r.r[3] = (int) realloc(*resultp, r.r[4]);

   if (r.r [4] == 0)
   {  /*No selection made.*/
      *resultp = NULL;
      return NULL;
   }

   if (r.r[3]) {
     *resultp = (char *)r.r[3];
   } else {
     errbuff.errnum = 1;
     strcpy(errbuff.errmess,msgs_lookup(MSGS_fontmenu3));
     return(&errbuff);
   }

   return(os_swix(DecodeMenu,&r));
}