/* $VER: lib.c 2.0 (6.4.2002) by Grzegorz Kraszewski */ /****** ttrender.library/background ***************************************** * * * PURPOSE * * The library is fast, AmigaOS friendly TrueType render engine. It has * nothing to do with Amiga outline font system. This system has a lot of * limitations which make it useless for high speed and quality text output. * If someone wants an integration of TrueType with AmigaOS bullet.library * like outline font system, should consider using ttf.library. This library * opens TrueType font by itself and renders high quality glyphs directly * into any RastPort. * * FREETYPE2 BASED * * The render engine of the library is based on FreeType2 project * (http://www.freetype.org). This version of ttrender.library uses 2.0.9 * FreeType build. * * REQUIREMENTS * * The library requires at least CyberGraphX 3.x or Picasso96 2.x system. It * is possible that non-antialiased output will be possible on AGA machines * in the future. * * FEATURES * * The library expands FreeType functionality making usage of TrueType fonts * easy and comfortable. Below you can find key features: * * - renders whole strings (not single glyphs) with kerning. * - antialiasing to any (not neccesarily uniform color) background. * - system compatible output to any (including planar) RastPort. * - supports JAM1. JAM2, INVERSVID, COMPLEMENT RastPort modes. * - supports 8-bit to Unicode mapping with "ENV:ttfcodepage" table * compatible with ttf.library. * - allows for direct 16-bit Unicode string rendering. * - easy to use, taglist based API. * - efficient system-wide glyph cache system. * * CACHE SYSTEM * * The library uses my own (not that experimental FreeType one) cache system * speeding up strings rendering alot. The cache is system-wide, it means it * is common to every application using ttrender.library. Only used glyphs of * given font face are cached. If the library encounters cache miss, missing * glyph is loaded and rasterized on the fly. Cache system is totally * transparent to the library user, so there are no cache functions in the * library API. Cache uses one single Exec memory pool avoiding memory * fragmentation. * * FONT DIRECTORIES * * The library searches for a font in three directories: * 1. Process current directory. * 2. "PROGDIR:" of the calling application. * 3. "FONTS:_TrueType_Outlines" as a common location for TrueType fonts. * ***************************************************************************** * */ #define __NOLIBBASE__ #include #include FT_FREETYPE_H #include #include #include #include #include #include #include #include #include #include #include #include #define reg(a) __asm(#a) #define USELIB(a) struct Library *##a = ttb->ttb_##a #define MAX_PATH_LENGHT 1024 /* maximum length of file path including ending zero */ #include "lib.h" struct TTRenderBase *Ttb; struct Library *__UtilityBase; /* required for libnix 64-bit arithmetic */ /*--- Functions prototypes -------------------------------------------------*/ struct TTRenderBase *LibInit(void *seglist reg(a0), struct Library *sysb reg(a6)); struct TTRenderBase *LibOpen(struct TTRenderBase *ttb reg(a6)); LONG LibClose(struct TTRenderBase *ttb reg(a6)); APTR LibExpunge(struct TTRenderBase *ttb reg(a6)); LONG LibReserved(void); BOOL TT_SetFont(struct TTRenderBase *ttb reg(a6), STRPTR name reg(a0), UWORD size reg(d0)); BOOL TT_PutStr(struct TTRenderBase *ttb reg(a6), UBYTE *str reg(a0)); BOOL TT_PutUStr(struct TTRenderBase *ttb reg(a6), UWORD *str reg(a0)); BOOL TT_PutStrTagList(struct TTRenderBase *ttb reg(a6), UBYTE *str reg(a0), struct TagItem *taglist reg(a1)); BOOL TT_PutUStrTagList(struct TTRenderBase *ttb reg(a6), UWORD *str reg(a0), struct TagItem *taglist reg(a1)); ULONG TT_SetModesTagList(struct TTRenderBase *ttb reg(a6), struct TagItem *taglist reg(a0)); ULONG TT_GetFontAttrsTagList(struct TTRenderBase *ttb reg(a6), struct TagItem *taglist reg(a0)); ULONG TT_StrWidth(struct TTRenderBase *ttb reg(a6), UBYTE *string reg(a0)); ULONG TT_UStrWidth(struct TTRenderBase *ttb reg(a6), UWORD *string reg(a0)); extern struct Resident romtag; /* cached one glyph bitmap */ struct CachedBitmap { struct MinNode cb_Node; LONG cb_AdvanceX; LONG cb_AdvanceY; WORD cb_OffsetX; WORD cb_OffsetY; FT_Bitmap cb_Bitmap; ULONG cb_Index; }; /* cached typeface of given size */ struct CachedSize { struct MinNode cs_Node; UWORD cs_PixelSize; struct MinList cs_Bitmaps; /* list of CachedBitmap structures */ }; /* cached multiple sizes of one face */ struct CachedFont { struct MinNode cf_Node; char *cf_Name; struct MinList cf_Sizes; /* list of CachedSize structures */ }; /* memory cache functions declarations */ struct CachedBitmap *cache_add_bitmap(struct TTRenderBase *ttb, struct CachedSize *cs, FT_GlyphSlot glyph, ULONG index); struct CachedBitmap *cache_find_bitmap(struct TTRenderBase *ttb, struct CachedSize *cs, ULONG index, char mode); void cache_flush_bitmap(struct TTRenderBase *ttb, struct CachedBitmap *cb); struct CachedSize *cache_add_size(struct TTRenderBase *ttb, struct CachedFont *cf, UWORD size); struct CachedSize *cache_find_size(struct TTRenderBase *ttb, struct CachedFont *cf, UWORD size); void cache_flush_size(struct TTRenderBase *ttb, struct CachedSize *cs); struct CachedFont *cache_add_font(struct TTRenderBase *ttb, char *name); struct CachedFont *cache_find_font(struct TTRenderBase *ttb, char *name); void cache_flush_font(struct TTRenderBase *ttb, struct CachedFont *cf); void cache_flush_all(struct TTRenderBase *ttb); /* codepage handling functions prototypes */ static void load_codepage(struct TTRenderBase *ttb); static void free_codepage(struct TTRenderBase *ttb); /* === CODE STARTS HERE === */ /*--------------------------------------------------------------------------*/ static const void *FuncTable[] = { LibOpen, LibClose, LibExpunge, LibReserved, TT_PutStr, TT_PutUStr, TT_SetFont, TT_PutStrTagList, TT_PutUStrTagList, TT_SetModesTagList, TT_GetFontAttrsTagList, TT_StrWidth, TT_UStrWidth, (APTR)-1 }; /*----------------------------------------------------------------------------------------------------*/ static void get_rp_fgcolor(struct TTRenderBase *ttb, struct RastPort *rp, struct ColorMap *cm, UBYTE *dest) { USELIB(GfxBase); ULONG tcolor[3]; WORD i; GetRGB32(cm, GetAPen(rp), 1, tcolor); for (i = 0; i < 3; i++) dest[i] = tcolor[i] >> 24; } /*----------------------------------------------------------------------------------------------------*/ /*static void get_rp_bgcolor(struct TTRenderBase *ttb, struct RastPort *rp, struct ColorMap *cm, UBYTE *dest) { USELIB(GfxBase); ULONG tcolor[3]; WORD i; GetRGB32(cm, GetBPen(rp), 1, tcolor); for (i = 0; i < 3; i++) dest[i] = tcolor[i] >> 24; }*/ /*----------------------------------------------------------------------------------------------------*/ static void blt_gray_bitmap(struct TTRenderBase *ttb, FT_Bitmap *bm, struct RastPort *rp, struct ColorMap *cm, WORD dstx, WORD dsty) { USELIB(GfxBase); USELIB(CyberGfxBase); USELIB(SysBase); ULONG bufsize, drawmode; UBYTE *buf; UBYTE fgcolor[3], bgcolor[3]; drawmode = GetDrMd(rp); get_rp_fgcolor(ttb, rp, cm, fgcolor); bufsize = bm->width * bm->rows * sizeof(ULONG); if (buf = AllocPooled(ttb->ttb_MemPool, bufsize)) { WORD xi, yi; UBYTE *ptr = buf, *src = bm->buffer; ReadPixelArray(buf, 0, 0, bm->width * sizeof(ULONG), rp, dstx, dsty, bm->width, bm->rows, RECTFMT_ARGB); for (yi = 0; yi < bm->rows; yi++) { for (xi = 0; xi < bm->width; xi++) { UBYTE alpha; *ptr++ = 0; alpha = (drawmode & INVERSVID) ? ~src[xi] : src[xi]; *ptr += ((WORD)(fgcolor[0] - *ptr++) * (WORD)(alpha)) >> 8; *ptr += ((WORD)(fgcolor[1] - *ptr++) * (WORD)(alpha)) >> 8; *ptr += ((WORD)(fgcolor[2] - *ptr++) * (WORD)(alpha)) >> 8; } src += bm->pitch; } WritePixelArray(buf, 0, 0, bm->width * sizeof(ULONG), rp, dstx, dsty, bm->width, bm->rows, RECTFMT_ARGB); FreePooled(ttb->ttb_MemPool, buf, bufsize); } } /*----------------------------------------------------------------------------------------------------*/ static void blt_mono_bitmap(struct TTRenderBase *ttb, FT_Bitmap *bm, struct RastPort *rp, struct ColorMap *cm, WORD dstx, WORD dsty) { USELIB(GfxBase); USELIB(CyberGfxBase); USELIB(SysBase); ULONG bufsize, drawmode; UBYTE *buf; UBYTE fgcolor[3], bgcolor[3]; drawmode = GetDrMd(rp); get_rp_fgcolor(ttb, rp, cm, fgcolor); bufsize = bm->width * bm->rows * sizeof(ULONG); if (buf = AllocPooled(ttb->ttb_MemPool, bufsize)) { WORD xi, yi; UBYTE *ptr = buf, *src = bm->buffer; ReadPixelArray(buf, 0, 0, bm->width * sizeof(ULONG), rp, dstx, dsty, bm->width, bm->rows, RECTFMT_ARGB); for (yi = 0; yi < bm->rows; yi++) { for (xi = 0; xi < bm->width; xi++) { UBYTE b, mask; if (!(xi & 7)) { mask = 0x80; b = src[xi >> 3]; } else mask >>= 1; *ptr++ = 0; if (b & mask) { *ptr++ = fgcolor[0]; *ptr++ = fgcolor[1]; *ptr++ = fgcolor[2]; } else ptr += 3; } src += bm->pitch; } WritePixelArray(buf, 0, 0, bm->width * sizeof(ULONG), rp, dstx, dsty, bm->width, bm->rows, RECTFMT_ARGB); FreePooled(ttb->ttb_MemPool, buf, bufsize); } } /*----------------------------------------------------------------------------------------------------*/ ULONG tt_strwidth(struct TTRenderBase *ttb, struct RenderEnv *re, APTR str, BOOL unicode) { USELIB(DOSBase); ULONG chindex = 0, previous; ULONG xpos = 0, ypos = 0; int error; UBYTE *nstr = str; UWORD *ustr = str; UWORD chcode; struct CachedBitmap *cb; FT_Face face = ttb->ttb_Face; BOOL use_kerning = FT_HAS_KERNING(face); struct RastPort *rp = re->re_TargetRPort; struct ColorMap *cm = re->re_TargetCMap; char render_mode = re->re_Antialias ? 0 : ft_render_mode_mono; char bitmap_mode = re->re_Antialias ? ft_pixel_mode_grays : ft_pixel_mode_mono; while (chcode = unicode ? *ustr++ : *nstr++) { previous = chindex; if (!unicode && ttb->ttb_CodePage) chcode = ttb->ttb_CodePage[chcode]; chindex = FT_Get_Char_Index(face, chcode); if (previous && use_kerning) { FT_Vector delta; FT_Get_Kerning(face, previous, chindex, ft_kerning_unfitted, &delta); xpos += delta.x; } if (cb = cache_find_bitmap(ttb->ttb_RealTTRenderBase, ttb->ttb_CurrentCache, chindex, bitmap_mode)) { DBG("MemCache HIT"); xpos += cb->cb_AdvanceX; ypos += cb->cb_AdvanceY; } else { DBG("MemCache MISS"); if (!FT_Load_Glyph(face, chindex, 0)) { if (!(error = FT_Render_Glyph(face->glyph, render_mode))) { FT_Bitmap *bm = &(face->glyph->bitmap); cache_add_bitmap(ttb->ttb_RealTTRenderBase, ttb->ttb_CurrentCache, face->glyph, chindex); } } xpos += face->glyph->advance.x; ypos += face->glyph->advance.y; } } return ((xpos + 32) >> 6); } void tt_putstr(struct TTRenderBase *ttb, struct RenderEnv *re, WORD x, WORD y, APTR str, BOOL unicode) { USELIB_DBG(DOSBase) // USELIB(DOSBase); USELIB(GfxBase); ULONG chindex = 0, previous; ULONG xpos = x << 6, ypos = y << 6; int error; UBYTE *nstr = str; UWORD *ustr = str; UWORD chcode; struct CachedBitmap *cb; FT_Face face = ttb->ttb_Face; BOOL use_kerning = FT_HAS_KERNING(face); UWORD pixlen; struct RastPort *rp = re->re_TargetRPort; struct ColorMap *cm = re->re_TargetCMap; char render_mode = re->re_Antialias ? 0 : ft_render_mode_mono; char bitmap_mode = re->re_Antialias ? ft_pixel_mode_grays : ft_pixel_mode_mono; pixlen = tt_strwidth(ttb, re, str, unicode); /* draw backgorund in JAM2 mode */ if (GetDrMd(rp) & JAM2) { ULONG old_fg_pen = GetAPen(rp); SetAPen(rp, GetBPen(rp)); RectFill(rp, rp->cp_x, rp->cp_y - ttb->ttb_Ascender, rp->cp_x + pixlen, rp->cp_y + ttb->ttb_Descender); SetAPen(rp, old_fg_pen); } while (chcode = unicode ? *ustr++ : *nstr++) { previous = chindex; if (!unicode && ttb->ttb_CodePage) chcode = ttb->ttb_CodePage[chcode]; chindex = FT_Get_Char_Index(face, chcode); if (previous && use_kerning) { FT_Vector delta; FT_Get_Kerning(face, previous, chindex, ft_kerning_unfitted, &delta); xpos += delta.x; } /* glyph already cached with tt_strwidth() */ cb = cache_find_bitmap(ttb->ttb_RealTTRenderBase, ttb->ttb_CurrentCache, chindex, bitmap_mode); switch (cb->cb_Bitmap.pixel_mode) { case ft_pixel_mode_grays: blt_gray_bitmap(ttb, &cb->cb_Bitmap, rp, cm, (xpos >> 6) + cb->cb_OffsetX, (ypos >> 6) - cb->cb_OffsetY); break; case ft_pixel_mode_mono: blt_mono_bitmap(ttb, &cb->cb_Bitmap, rp, cm, (xpos >> 6) + cb->cb_OffsetX, (ypos >> 6) - cb->cb_OffsetY); break; } xpos += cb->cb_AdvanceX; ypos += cb->cb_AdvanceY; } } /*----------------------------------------------------------------------------------------------------*/ /* always gets "real" TTRenderBase */ struct CachedBitmap *cache_add_bitmap(struct TTRenderBase *ttb, struct CachedSize *cs, FT_GlyphSlot glyph, ULONG index) { USELIB(SysBase); USELIB_DBG(DOSBase) struct CachedBitmap *cb; ULONG bmsize; if (cb = AllocPooled(ttb->ttb_MemPool, sizeof(struct CachedBitmap))) { cb->cb_Index = index; cb->cb_AdvanceX = glyph->advance.x; cb->cb_AdvanceY = glyph->advance.y; cb->cb_OffsetX = glyph->bitmap_left; cb->cb_OffsetY = glyph->bitmap_top; CopyMem(&glyph->bitmap, &cb->cb_Bitmap, sizeof(FT_Bitmap)); bmsize = cb->cb_Bitmap.rows * cb->cb_Bitmap.pitch; if (bmsize) { if (cb->cb_Bitmap.buffer = AllocPooled(ttb->ttb_MemPool, bmsize)) { CopyMem(glyph->bitmap.buffer, cb->cb_Bitmap.buffer, bmsize); } } else cb->cb_Bitmap.buffer = NULL; if (cb->cb_Bitmap.buffer || !bmsize) { ttb->ttb_MemCacheSize += sizeof(struct CachedBitmap) + bmsize; AddTail((struct List*)&cs->cs_Bitmaps, (struct Node*)cb); DBG2("\tMemCache: %ld glyph added, cache size %ld bytes.", cb->cb_Index, ttb->ttb_MemCacheSize); return cb; } FreePooled(ttb->ttb_MemPool, cb, sizeof(struct CachedBitmap)); } return NULL; } /*----------------------------------------------------------------------------------------------------*/ /* always gets "real" TTRenderBase */ struct CachedBitmap *cache_find_bitmap(struct TTRenderBase *ttb, struct CachedSize *cs, ULONG index, char mode) { struct MinNode *n; for(n = cs->cs_Bitmaps.mlh_Head; n->mln_Succ; n = n->mln_Succ) { if (((struct CachedBitmap*)n)->cb_Index == index && ((struct CachedBitmap*)n)->cb_Bitmap.pixel_mode == mode) return (struct CachedBitmap*)n; } return NULL; } /*----------------------------------------------------------------------------------------------------*/ /* always gets "real" TTRenderBase */ void cache_flush_bitmap(struct TTRenderBase *ttb, struct CachedBitmap *cb) { USELIB(SysBase); USELIB_DBG(DOSBase) ULONG bsize; DBG1("\t\tMemCache: '%ld' bitmap flushed.", cb->cb_Index); bsize = cb->cb_Bitmap.rows * cb->cb_Bitmap.pitch; Remove((struct Node*)cb); if (cb->cb_Bitmap.buffer) FreePooled(ttb->ttb_MemPool, cb->cb_Bitmap.buffer, bsize); FreePooled(ttb->ttb_MemPool, cb, sizeof(struct CachedBitmap)); ttb->ttb_MemCacheSize -= sizeof(struct CachedBitmap) + bsize; DBG1("\t\tCache size %ld bytes.", ttb->ttb_MemCacheSize); } /*----------------------------------------------------------------------------------------------------*/ /* always gets "real" TTRenderBase */ struct CachedSize *cache_add_size(struct TTRenderBase *ttb, struct CachedFont *cf, UWORD size) { USELIB(SysBase); USELIB_DBG(DOSBase) struct CachedSize *cs; if (cs = AllocPooled(ttb->ttb_MemPool, sizeof(struct CachedSize))) { cs->cs_PixelSize = size; cs->cs_Bitmaps.mlh_Head = (struct MinNode*)&cs->cs_Bitmaps.mlh_Tail; cs->cs_Bitmaps.mlh_Tail = NULL; cs->cs_Bitmaps.mlh_TailPred = (struct MinNode*)&cs->cs_Bitmaps.mlh_Head; ttb->ttb_MemCacheSize += sizeof(struct CachedSize); AddTail((struct List*)&cf->cf_Sizes, (struct Node*)cs); DBG2("\tMemCache: %ld size added, cache size %ld bytes.", cs->cs_PixelSize, ttb->ttb_MemCacheSize); return cs; } return NULL; } /*----------------------------------------------------------------------------------------------------*/ /* always gets "real" TTRenderBase */ struct CachedSize *cache_find_size(struct TTRenderBase *ttb, struct CachedFont *cf, UWORD size) { struct MinNode *n; for(n = cf->cf_Sizes.mlh_Head; n->mln_Succ; n = n->mln_Succ) { if (((struct CachedSize*)n)->cs_PixelSize == size) return (struct CachedSize*)n; } return NULL; } /*----------------------------------------------------------------------------------------------------*/ /* always gets "real" TTRenderBase */ void cache_flush_size(struct TTRenderBase *ttb, struct CachedSize *cs) { USELIB(SysBase); USELIB_DBG(DOSBase) struct MinNode *n, *n2; DBG1("\tMemCache: '%ld' size flushed.", cs->cs_PixelSize); Remove((struct Node*)cs); n = cs->cs_Bitmaps.mlh_Head; while(n2 = n->mln_Succ) { cache_flush_bitmap(ttb, (struct CachedBitmap*)n); n = n2; } FreePooled(ttb->ttb_MemPool, cs, sizeof(struct CachedSize)); ttb->ttb_MemCacheSize -= sizeof(struct CachedSize); DBG1("\tCache size %ld bytes.", ttb->ttb_MemCacheSize); } /*----------------------------------------------------------------------------------------------------*/ /* always gets "real" TTRenderBase */ struct CachedFont *cache_add_font(struct TTRenderBase *ttb, char *name) { USELIB(SysBase); USELIB_DBG(DOSBase) struct CachedFont *cf; ULONG namelen; namelen = strlen(name) + 1; if (cf = AllocPooled(ttb->ttb_MemPool, sizeof(struct CachedFont))) { if (cf->cf_Name = AllocPooled(ttb->ttb_MemPool, namelen)) { strcpy(cf->cf_Name, name); cf->cf_Sizes.mlh_Head = (struct MinNode*)&cf->cf_Sizes.mlh_Tail; cf->cf_Sizes.mlh_Tail = NULL; cf->cf_Sizes.mlh_TailPred = (struct MinNode*)&cf->cf_Sizes.mlh_Head; ttb->ttb_MemCacheSize += sizeof(struct CachedFont) + namelen; AddTail((struct List*)&ttb->ttb_MemoryCache, (struct Node*)cf); DBG2("\tMemCache: '%s' font added, cache size %ld bytes.", (LONG)cf->cf_Name, ttb->ttb_MemCacheSize); return cf; } FreePooled(ttb->ttb_MemPool, cf, sizeof(struct CachedFont)); } return NULL; } /*----------------------------------------------------------------------------------------------------*/ /* always gets "real" TTRenderBase */ void cache_flush_font(struct TTRenderBase *ttb, struct CachedFont *cf) { USELIB(SysBase); USELIB_DBG(DOSBase) struct MinNode *n, *n2; ULONG namelen; namelen = strlen(cf->cf_Name) + 1; DBG1("\tMemCache: '%s' font flushed.", (LONG)cf->cf_Name); Remove((struct Node*)cf); n = cf->cf_Sizes.mlh_Head; while(n2 = n->mln_Succ) { cache_flush_size(ttb, (struct CachedSize*)n); n = n2; } FreePooled(ttb->ttb_MemPool, cf->cf_Name, namelen); FreePooled(ttb->ttb_MemPool, cf, sizeof(struct CachedFont)); ttb->ttb_MemCacheSize -= namelen + sizeof(struct CachedFont); DBG1("\tCache size %ld bytes.", ttb->ttb_MemCacheSize); } /*----------------------------------------------------------------------------------------------------*/ /* always gets "real" TTRenderBase */ struct CachedFont *cache_find_font(struct TTRenderBase *ttb, char *name) { struct MinNode *n; for(n = ttb->ttb_MemoryCache.mlh_Head; n->mln_Succ; n = n->mln_Succ) { if (strcmp(((struct CachedFont*)n)->cf_Name, name) == 0) return (struct CachedFont*)n; } return NULL; } /*----------------------------------------------------------------------------------------------------*/ /* always gets "real" TTRenderBase */ void cache_flush_all(struct TTRenderBase *ttb) { struct MinNode *n, *n2; n = ttb->ttb_MemoryCache.mlh_Head; while(n2 = n->mln_Succ) { cache_flush_font(ttb, (struct CachedFont*)n); n = n2; } } /*----------------------------------------------------------------------------------------------------*/ static void load_codepage(struct TTRenderBase *ttb) { struct Library *SysBase = ttb->ttb_SysBase; struct Library *DOSBase = ttb->ttb_DOSBase; BPTR codepage; int d; /* load codepage */ ttb->ttb_CodePage = NULL; if (codepage = Open("ENV:ttfcodepage", MODE_OLDFILE)) { if (ttb->ttb_CodePage = AllocPooled(ttb->ttb_MemPool, 512)) { if (Read(codepage, ttb->ttb_CodePage, 512) != 512) { FreePooled(ttb->ttb_MemPool, ttb->ttb_CodePage, 512); ttb->ttb_CodePage = NULL; } } Close(codepage); } } /*----------------------------------------------------------------------------------------------------*/ static void free_codepage(struct TTRenderBase *ttb) { USELIB(SysBase); if (ttb->ttb_CodePage) FreePooled(ttb->ttb_MemPool, ttb->ttb_CodePage, 512); } /*-------------------------------------------------------------------------*/ /* INIT */ /*-------------------------------------------------------------------------*/ __saveds struct TTRenderBase *LibInit (APTR seglist reg(a0), struct Library *sysb reg(a6)) { struct TTRenderBase *ttb, *rval = NULL; struct Library *SysBase = sysb; if (ttb = (struct TTRenderBase*)MakeLibrary (FuncTable, NULL, NULL, sizeof (struct TTRenderBase), 0)) { ttb->ttb_Lib.lib_Node.ln_Type = NT_LIBRARY; ttb->ttb_Lib.lib_Node.ln_Name = romtag.rt_Name; ttb->ttb_Lib.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED; ttb->ttb_Lib.lib_Version = 2; ttb->ttb_Lib.lib_Revision = 0; ttb->ttb_Lib.lib_IdString = romtag.rt_IdString; ttb->ttb_Lib.lib_OpenCnt = 0; ttb->ttb_SegList = seglist; ttb->ttb_SysBase = SysBase; ttb->ttb_MemPool = NULL; ttb->ttb_RealTTRenderBase = NULL; ttb->ttb_RenderEnv.re_TargetRPort = NULL; ttb->ttb_RenderEnv.re_TargetCMap = NULL; ttb->ttb_RenderEnv.re_Antialias = FALSE; ttb->ttb_GfxBase = NULL; ttb->ttb_DOSBase = NULL; ttb->ttb_CyberGfxBase = NULL; ttb->ttb_UtilityBase = NULL; ttb->ttb_FTLib = NULL; ttb->ttb_Face = NULL; ttb->ttb_MemoryCache.mlh_Head = (struct MinNode*)&ttb->ttb_MemoryCache.mlh_Tail; ttb->ttb_MemoryCache.mlh_Tail = NULL; ttb->ttb_MemoryCache.mlh_TailPred = (struct MinNode*)&ttb->ttb_MemoryCache.mlh_Head; ttb->ttb_MemCacheSize = 0; ttb->ttb_Ascender = 0; ttb->ttb_Descender = 0; AddLibrary ((struct Library*)ttb); rval = ttb; } return rval; } /*-------------------------------------------------------------------------*/ /* OPEN */ /*-------------------------------------------------------------------------*/ static struct TTRenderBase *init_resources(struct TTRenderBase *ttb) { USELIB(SysBase); USELIB_DBG(DOSBase) LONG ft_error; if (!(__UtilityBase = OpenLibrary("utility.library", 39))) return NULL; ttb->ttb_UtilityBase = __UtilityBase; if (!(ttb->ttb_GfxBase = OpenLibrary("graphics.library", 39))) return NULL; if (!(ttb->ttb_DOSBase = OpenLibrary("dos.library", 38))) return NULL; if (!(ttb->ttb_CyberGfxBase = OpenLibrary("cybergraphics.library", 41))) return NULL; if (!(ttb->ttb_MemPool = CreatePool(MEMF_ANY | MEMF_CLEAR, 1024, 512))) return NULL; #ifdef TTR_DEBUG DOSBase = ttb->ttb_DOSBase; ttb->debug = Open("KCON:0/17/640/150/ttrender.library/AUTO/CLOSE", MODE_NEWFILE); #endif load_codepage(ttb); Ttb = ttb; if (ft_error = FT_Init_FreeType(&ttb->ttb_FTLib) != 0) { DBG1("FT_Init_FreeType() failed, error %ld.", ft_error); ttb->ttb_FTLib = NULL; return NULL; } DBG("Library initialization successfull."); return ttb; } /* always gets "real" TTRenderBase */ static void free_resources(struct TTRenderBase *ttb) { USELIB(SysBase); if (ttb->ttb_FTLib) FT_Done_FreeType(ttb->ttb_FTLib); if (ttb->ttb_CyberGfxBase) CloseLibrary(ttb->ttb_CyberGfxBase); if (ttb->ttb_DOSBase) CloseLibrary(ttb->ttb_DOSBase); if (ttb->ttb_GfxBase) CloseLibrary(ttb->ttb_GfxBase); if (__UtilityBase) CloseLibrary(__UtilityBase); cache_flush_all(ttb); free_codepage(ttb); if (ttb->ttb_MemPool) DeletePool(ttb->ttb_MemPool); return; } __saveds struct TTRenderBase *LibOpen (struct TTRenderBase *ttb_real reg(a6)) { struct TTRenderBase *ttb_fake = NULL; struct Library *SysBase = ttb_real->ttb_SysBase; if (ttb_fake = (struct TTRenderBase*)MakeLibrary (FuncTable, NULL, NULL, sizeof (struct TTRenderBase), 0)) { if (!ttb_real->ttb_MemPool) { if (!init_resources(ttb_real)) { free_resources(ttb_real); FreeMem ((APTR)ttb_fake - ttb_fake->ttb_Lib.lib_NegSize, (LONG)ttb_fake->ttb_Lib.lib_PosSize + (LONG)ttb_fake->ttb_Lib.lib_NegSize); return NULL; } } CopyMem((APTR)ttb_real, (APTR)ttb_fake, sizeof(struct TTRenderBase)); ttb_fake->ttb_RealTTRenderBase = ttb_real; { #ifdef TTR_DEBUG struct Library *DOSBase = ttb_fake->ttb_DOSBase; #endif DBG2("Library opened, real base $%08lx, priv base $%08lx.", (LONG)ttb_real, (LONG)ttb_fake); } ttb_real->ttb_Lib.lib_OpenCnt++; ttb_real->ttb_Lib.lib_Flags &= ~LIBF_DELEXP; return ttb_fake; } } /*-------------------------------------------------------------------------*/ /* CLOSE */ /*-------------------------------------------------------------------------*/ __saveds long LibClose(struct TTRenderBase *ttb_fake reg(a6)) { struct Library *SysBase = ttb_fake->ttb_SysBase; struct TTRenderBase *ttb_real = ttb_fake->ttb_RealTTRenderBase; #ifdef TTR_DEBUG struct Library *DOSBase = ttb_fake->ttb_DOSBase; #endif if (ttb_fake->ttb_Face) FT_Done_Face(ttb_fake->ttb_Face); FreeMem ((APTR)ttb_fake - ttb_fake->ttb_Lib.lib_NegSize, (LONG)ttb_fake->ttb_Lib.lib_PosSize + (LONG)ttb_fake->ttb_Lib.lib_NegSize); DBG("Library closed"); if (!(--ttb_real->ttb_Lib.lib_OpenCnt)) { if (ttb_real->ttb_Lib.lib_Flags & LIBF_DELEXP) return ((long)LibExpunge(ttb_real)); } return 0; } /*-------------------------------------------------------------------------*/ /* EXPUNGE */ /*-------------------------------------------------------------------------*/ __saveds APTR LibExpunge (struct TTRenderBase *ttb reg(a6)) { USELIB(SysBase); APTR seglist; if (ttb->ttb_Lib.lib_OpenCnt) { ttb->ttb_Lib.lib_Flags |= LIBF_DELEXP; return 0; } Remove ((struct Node*)ttb); free_resources(ttb); seglist = ttb->ttb_SegList; FreeMem ((APTR)ttb - ttb->ttb_Lib.lib_NegSize, (LONG)ttb->ttb_Lib.lib_PosSize + (LONG)ttb->ttb_Lib.lib_NegSize); return seglist; } /*-------------------------------------------------------------------------*/ /* RESERVED */ /*-------------------------------------------------------------------------*/ long LibReserved (void) { return 0; } /****** ttrender.library/TT_SetFont ***************************************** * * NAME * TT_SetFont -- Opens TrueType font with given name and size. * * SYNOPSIS * success = TT_SetFont (name, size) * A0 D0:16 * * BOOL TT_SetFont (STRPTR, UWORD); * * FUNCTION * Opens TrueType font file and sets current font size in pixels. Every * following call to TT_PutStr[Tags/TagList]() or * TT_PutUStr[Tags/TagList]() will use this font and size. * * INPUTS * name - pointer to a NULL terminated string containing font name. * ".ttf" suffix will be added automatically. Search order is * defined as follows: * 1. current directory * ".ttf" * 2. PROGDIR: * "PROGDIR:.ttf" * 3. "FONTS:_TrueType_Outlines" (by analogy to _Bullet_Outlines) * "FONTS:_TrueType_Outlines/.ttf" * size - screen size of the font in pixels (to be exact - it is the * distance between baselines of two following lines of text * expressed in pixels). * * RESULT * success - TRUE if the font has been opened successfully, FALSE * otherwise. This function can fail for three reasons: * 1. File not found or malformed. * 2. Zero font size. * 3. No memory for requested (too big?) size. * * NOTES * * BUGS * * SEE ALSO * TT_PutStr(), TT_PutUStr() * ***************************************************************************** * */ __saveds BOOL TT_SetFont(struct TTRenderBase *ttb reg(a6), STRPTR name reg(a0), UWORD size reg(d0)) { USELIB(SysBase); USELIB(DOSBase); STRPTR filepath; BOOL result = FALSE; BPTR testlock = 0; LONG error; struct CachedSize *cs; struct CachedFont *cf; struct RenderEnv *re = &ttb->ttb_RenderEnv; DBG2("TT_SetFont(\"%s\", %ld):", name, size); if (ttb->ttb_Face) { FT_Done_Face(ttb->ttb_Face); ttb->ttb_Face = NULL; } DBG("\tOld typeface cleared."); /* add .ttf suffix */ if (filepath = AllocPooled(ttb->ttb_MemPool, MAX_PATH_LENGHT)) { STRPTR p, q; strncpy(filepath, name, MAX_PATH_LENGHT - 8); strcat(filepath, ".ttf"); /* OK, we have a full name, let's try current directory */ DBG1("\tFont search: searching for \"%s\" file...", filepath); if (!(testlock = Lock(filepath, ACCESS_READ))) { /* Try "PROGDIR:" now */ strcpy(filepath, "PROGDIR:"); AddPart(filepath, name, MAX_PATH_LENGHT - 16); strcat(filepath, ".ttf"); DBG1("\tFont search: searching for \"%s\" file...", filepath); if (!(testlock = Lock(filepath, ACCESS_READ))) { /* Still not found, try "FONTS:_TrueType_Outlines/" */ strcpy(filepath, "FONTS:_TrueType_Outlines/"); AddPart(filepath, name, MAX_PATH_LENGHT - 32); strcat(filepath, ".ttf"); DBG1("\tFont search: searching for \"%s\" file...", filepath); if (!(testlock = Lock(filepath, ACCESS_READ))) { DBG("\tFont search: file not found."); result = FALSE; } } } if (testlock) { /* font file found, Tank, load us up :-) */ DBG("\tFont file found, loading..."); DBG1("\tFTLib = $%08lx.", ttb->ttb_FTLib); if (!(error = FT_New_Face(ttb->ttb_FTLib, filepath, 0, &ttb->ttb_Face))) { ULONG px_size, asc, desc; DBG1("\tFont face \"%s\" loaded succesfully.", name); /* compute correct pixel size for given height */ px_size = ((size << 17) + (ttb->ttb_Face->height >> 1)) / ttb->ttb_Face->height; FT_Set_Char_Size(ttb->ttb_Face, 0, px_size,72, 72); DBG1("\tRescaled to %ld pixels height.", px_size); if (!(cf = cache_find_font(ttb->ttb_RealTTRenderBase, name))) cf = cache_add_font(ttb->ttb_RealTTRenderBase, name); if (cf) { if (!(cs = cache_find_size(ttb->ttb_RealTTRenderBase, cf, size))) cs = cache_add_size(ttb->ttb_RealTTRenderBase, cf, size); if (cs) ttb->ttb_CurrentCache = cs; } /* global metrics calculation */ asc = (ttb->ttb_Face->size->metrics.ascender + 0x1F) >> 6; desc = (0x1F - ttb->ttb_Face->size->metrics.descender) >> 6; ttb->ttb_Ascender = asc + ((size - (asc + desc)) >> 1); ttb->ttb_Descender = size - ttb->ttb_Ascender; result = TRUE; } UnLock(testlock); } FreePooled(ttb->ttb_MemPool, filepath, MAX_PATH_LENGHT); } return result; } /****** ttrender.library/TT_PutStr ****************************************** * * NAME * TT_PutStr -- Renders string into RastPort. * * SYNOPSIS * success = TT_PutStr (string) * A0 * * BOOL TT_PutStr (UBYTE*); * * FUNCTION * Renders the string using current ttrender.library settings, and * current RastPort settings (pen, drawmode). String is rendered at * current RastPort (x, y) position, where 'y' means position of font * baseline. String is converted to Unicode according to * "ENV:ttfcodepage" mapping table. If there is no mapping table, * ISO-8859-1 mapping is used which is equal to ECMA Latin1 Amiga * standard. * * INPUTS * string - NULL-terminated string to render to. * * RESULT * TRUE if the string has been rendered. * * EXAMPLE * \* write a text with pen 1 and transp. background at (100, 100) *\ * \* rendering is done to a system window *\ * * SetAPen(win->RPort, 1); * SetDrMd(win->RPort, JAM1); * Move(win->RPort, 100, 100); * TT_SetModesTags(TTA_Window, win); * TT_PutStr("some text"); * * NOTES * * BUGS * * SEE ALSO * TT_PutStrTagList(), TT_SetModesTagList(), TT_PutUStr() * ***************************************************************************** * */ __saveds BOOL TT_PutStr(struct TTRenderBase *ttb reg(a6), UBYTE *str reg(a0)) { struct RenderEnv *re = &ttb->ttb_RenderEnv; if (re->re_TargetRPort && re->re_TargetCMap) { tt_putstr(ttb, re, re->re_TargetRPort->cp_x, re->re_TargetRPort->cp_y, str, FALSE); return TRUE; } return FALSE; } /****** ttrender.library/TT_PutUStr ***************************************** * * NAME * TT_PutUStr -- Renders Unicode string into RastPort. * * SYNOPSIS * success = TT_PutUStr (string) * A0 * * BOOL TT_PutUStr (UWORD*); * * FUNCTION * Renders the string using current ttrender.library (RastPort, ColorMap, * render mode), and RastPort settings (pen, drawmode). String is * rendered at current RastPort (x, y) position, where 'y' means position * of font baseline. String is an 16-bit Unicode one and should be * terminated with 16-bit zero. * * INPUTS * string - 16-bit Unicode NULL-terminated string to render to. * * RESULT * TRUE if the string has been rendered. * * BUGS * * SEE ALSO * TT_PutUStrTagList(), TT_SetModesTagList(), TT_PutStr() * ***************************************************************************** * */ __saveds BOOL TT_PutUStr(struct TTRenderBase *ttb reg(a6), UWORD *ustr reg(a0)) { struct RenderEnv *re = &ttb->ttb_RenderEnv; if (re->re_TargetRPort && re->re_TargetCMap) { tt_putstr(ttb, re, re->re_TargetRPort->cp_x, re->re_TargetRPort->cp_y, ustr, TRUE); return TRUE; } return FALSE; } static ULONG parse_taglist(struct TTRenderBase *ttb, struct TagItem *taglist, struct RenderEnv *renv) { USELIB(UtilityBase); USELIB_DBG(DOSBase) struct TagItem *current_tag, *tag_pointer = taglist; BOOL rpset = FALSE, cmset = FALSE; ULONG tag_counter = 0; while (current_tag = NextTagItem(&tag_pointer)) { switch (current_tag->ti_Tag) { case TTA_Antialias: renv->re_Antialias = current_tag->ti_Data; DBG1("\tAntialias %s", renv->re_Antialias ? (ULONG)"on" : (ULONG)"off"); tag_counter++; break; case TTA_RastPort: renv->re_TargetRPort = (struct RastPort*)current_tag->ti_Data; DBG1("\tRastPort $%08lx", renv->re_TargetRPort); rpset = TRUE; tag_counter++; break; case TTA_ColorMap: renv->re_TargetCMap = (struct ColorMap*)current_tag->ti_Data; DBG1("\tColorMap $%08lx", renv->re_TargetCMap); cmset = TRUE; tag_counter++; break; case TTA_Screen: if (!rpset) renv->re_TargetRPort = &((struct Screen*)current_tag->ti_Data)->RastPort; if (!cmset) renv->re_TargetCMap = ((struct Screen*)current_tag->ti_Data)->ViewPort.ColorMap; DBG1("\tScreen $%08lx", current_tag->ti_Data); DBG2("\t[RPort $%08lx, CMap $%08lx]", renv->re_TargetRPort, renv->re_TargetCMap); tag_counter++; break; case TTA_Window: if (!rpset)renv->re_TargetRPort = ((struct Window*)current_tag->ti_Data)->RPort; if (!cmset)renv->re_TargetCMap = ((struct Window*)current_tag->ti_Data)->WScreen->ViewPort.ColorMap; DBG1("\tWindow $%08lx", current_tag->ti_Data); DBG2("\t[RPort $%08lx, CMap $%08lx]", renv->re_TargetRPort, renv->re_TargetCMap); tag_counter++; break; } } } /****** ttrender.library/TT_PutStrTagList *********************************** * * NAME * TT_PutStrTagList -- Renders string into RastPort with local settings. * * SYNOPSIS * success = TT_PutStrTagList (string, taglist) * A0 A1 * * BOOL TT_PutStrTagList (UBYTE*, struct TagItem*); * * success = TT_PutStrTags (string, Tag1, ...) * * BOOL TT_PutStrTags (UBYTE*, Tag, ...); * * FUNCTION * Renders the string allowing temporary override of current * ttrender.library settings, and current RastPort settings. Attributes * given in the taglist have local precedence over global * ttrender.library settings set by TT_SetModesTagList() call. Check * TT_SetModesTagList() docs for a list of tags. * * INPUTS * string - NULL-terminated string to render to. * * taglist - local attributes valid only in this function call. * * RESULT * TRUE if the string has been rendered. * * EXAMPLE * * \* Turn antialias mode on globally *\ * * TT_SetModesTags(TTA_Antialias, TRUE); * * TT_PutStr("some text"); \* this text will be antialiased *\ * TT_PutStrTags("another text", * TTA_Antialias, FALSE, \* this text won't (locally *\ * TAG_END); \* switched off) *\ * TT_PutStr("third text"); \* this text will be antialiased *\ * * NOTES * * BUGS * * SEE ALSO * TT_PutStr(), TT_SetModesTagList() * ***************************************************************************** * */ __saveds BOOL TT_PutStrTagList(struct TTRenderBase *ttb reg(a6), UBYTE *str reg(a0), struct TagItem *taglist reg(a1)) { USELIB(SysBase); USELIB_DBG(DOSBase) struct RenderEnv local; DBG("Local TT_PutStrTagList() settings change:"); CopyMem(&ttb->ttb_RenderEnv, &local, sizeof(struct RenderEnv)); parse_taglist(ttb, taglist, &local); if (local.re_TargetRPort && local.re_TargetCMap) { tt_putstr(ttb, &local, local.re_TargetRPort->cp_x, local.re_TargetRPort->cp_y, str, FALSE); return TRUE; } return FALSE; } /****** ttrender.library/TT_PutUStrTagList ********************************** * * NAME * TT_PutUStrTagList -- Renders 16-bit Unicode string into RastPort with * local settings. * * SYNOPSIS * success = TT_PutUStrTagList (string, taglist) * A0 A1 * * BOOL TT_PutUStrTagList (UWORD*, struct TagItem*); * * success = TT_PutUStrTags (string, Tag1, ...) * * BOOL TT_PutUStrTags (UWORD*, Tag, ...); * * FUNCTION * Renders the 16-bit Unicode string allowing temporary override of * current ttrender.library settings, and current RastPort settings. * Attributes given in the taglist have local precedence over global * ttrender.library settings set by TT_SetModesTagList() call. Check * TT_SetModesTagList() docs for a list of tags. * * INPUTS * string - NULL-terminated 16-bit Unicode string to render to. * * taglist - local attributes valid only in this function call. * * RESULT * TRUE if the string has been rendered. * * NOTES * * BUGS * * SEE ALSO * TT_PutUStr(), TT_SetModesTagList() * ***************************************************************************** * */ __saveds BOOL TT_PutUStrTagList(struct TTRenderBase *ttb reg(a6), UWORD *str reg(a0), struct TagItem *taglist reg(a1)) { USELIB(SysBase); USELIB_DBG(DOSBase) struct RenderEnv local; DBG("Local TT_PutUStrTagList() settings change:"); CopyMem(&ttb->ttb_RenderEnv, &local, sizeof(struct RenderEnv)); parse_taglist(ttb, taglist, &local); if (local.re_TargetRPort && local.re_TargetCMap) { tt_putstr(ttb, &local, local.re_TargetRPort->cp_x, local.re_TargetRPort->cp_y, str, TRUE); return TRUE; } return FALSE; } /****** ttrender.library/TT_SetModesTagList ********************************* * * NAME * TT_SetModesTagList -- Sets global rendering settings. * * SYNOPSIS * count = TT_SetModesTagList (taglist) * A0 * * ULONG TT_SetModesTagList (struct TagItem*); * * count = TT_SetModesTags (Tag1, ...) * * ULONG TT_SetModesTags (Tag, ...); * * FUNCTION * Sets global (per library opening) render engine settings. Every * following TT_PutStr() / TT_PutUStr() call will use these settings. * They can by overriden temporarily however, with TT_PutStrTagList() / * TT_PutUStrTagList() calls. Here is a list of attributes: * * TTA_RastPort - (struct RastPort*) - Destination RastPort for * rendering. The library will adhere to this RastPort settings like * draw mode, pens, current pen position. * * TTA_ColorMap - (struct ColorMap*) - ColorMap used to convert pen * number to RGB color value. * * TTA_Screen - (struct Screen*) - useful shortcut for TTA_RastPort and * TTA_ColorMap, automatically sets screen ColorMap and screen * RastPort. * * TTA_Window - (struct Window*) - useful shortcut for TTA_RastPort and * TTA_ColorMap, automatically sets window ColorMap and window * RastPort. * * TTA_Antialias - (BOOL) - controls antialiasing (on or off). * * INPUTS * taglist - the list of global attributes. * * RESULT * counter - the count of recognized tags. * * NOTES * TTA_RastPort and TTA_ColorMap attributes have precedence over * TTA_Screen and TTA_Window ones. It can be useful if one wants to use * window/screen ColorMap but separate RastPort. An example: * * TT_SetModesTags(TTA_Window, win, TTA_RastPort, my_rport, TAG_END); * * It will set window colormap and 'my_rport' as targets. Note that the * precedence is based on tag values, not on tags order. So ordering of * the tags is meaningless for the function. * * BUGS * * SEE ALSO * TT_PutStr(), TT_SetModesTagList() * ***************************************************************************** * */ __saveds ULONG TT_SetModesTagList(struct TTRenderBase *ttb reg(a6), struct TagItem *taglist reg(a0)) { USELIB_DBG(DOSBase) DBG("Global settings change:"); return (parse_taglist(ttb, taglist, &ttb->ttb_RenderEnv)); } /****** ttrender.library/TT_GetFontAttrsTagList ***************************** * * NAME * TT_GetFontAttrsTagList -- Gets current font attributes (V2). * * SYNOPSIS * count = TT_GetFontAttrsTagList (taglist) * A0 * * ULONG TT_GetFontAttrsTagList (struct TagItem*); * * count = TT_GetFontAttrsTags (Tag1, ...) * * ULONG TT_GetFontAttrsTags (Tag, ...); * * FUNCTION * Gets current (set by last SetFont() call) font attributes (global * metrics mainly). The value of every attribute is written to an ULONG * pointed by ti_Data field of the TagItem. Here is a list of attributes: * * TTFA_Ascender - This is a distance (in pixels) between the baseline * and top elements of the font (typically these elements are accents * of capital letters). NOTE: many shareware TT fonts have wrong ascen- * der value. * * TTFA_Descender - This is a distance (in pixels) between the baseline * and bottom elements of the font (typically in letters 'p', 'q', 'g' * etc.). NOTE: many shareware TT fonts have wrong descender value. * Descender value is typically negative (as bottom elements usually * are placed below the baseline). * * NOTE: TTFA_Ascender and TTFA_Descender are guarranted to fulfill * following formula: ascender - descender = font height. * * INPUTS * taglist - the list of attributes. * * RESULT * counter - the count of recognized tags. * * NOTES * * BUGS * * SEE ALSO * TT_SetFont() * ***************************************************************************** * */ __saveds ULONG TT_GetFontAttrsTagList(struct TTRenderBase *ttb reg(a6), struct TagItem *taglist reg(a0)) { USELIB(UtilityBase); USELIB_DBG(DOSBase) struct TagItem *current_tag, *tag_pointer = taglist; ULONG tag_counter = 0; DBG("TT_GetFontAttrsTagList()"); while (current_tag = NextTagItem(&tag_pointer)) { switch (current_tag->ti_Tag) { case TTFA_Ascender: *(ULONG*)current_tag->ti_Data = ttb->ttb_Ascender; DBG2("\tTTFA_Ascender (%ld) written at %08lx", ttb->ttb_Ascender, current_tag->ti_Data); tag_counter++; break; case TTFA_Descender: *(ULONG*)current_tag->ti_Data = ttb->ttb_Descender; DBG2("\tTTFA_Descender (%ld) written at %08lx", ttb->ttb_Descender, current_tag->ti_Data); tag_counter++; break; } } return tag_counter; } /****** ttrender.library/TT_StrWidth **************************************** * * NAME * TT_StrWidth -- Gets string width in pixels (V2). * * SYNOPSIS * width = TT_StrWidth(string) * A0 * * ULONG TT_StrWidth (UBYTE*); * * FUNCTION * Calculates the pixel width of given string written with current font. * Takes kerning into account. String will be mapped to Unicode using * "ENV:ttfcodepage" table (see TT_PutStr() docs). * * INPUTS * string - the width of this string will be calculated. * * RESULT * width - the width of the string in pixels. * * NOTES * * BUGS * * SEE ALSO * TT_PutStr(), TT_SetFont() * ***************************************************************************** * */ __saveds ULONG TT_StrWidth(struct TTRenderBase *ttb reg(a6), UBYTE *string reg(a0)) { return (tt_strwidth(ttb, &ttb->ttb_RenderEnv, string, FALSE)); } /****** ttrender.library/TT_UStrWidth *************************************** * * NAME * TT_UStrWidth -- Gets Unicode 16-bit string width in pixels (V2). * * SYNOPSIS * width = TT_UStrWidth(string) * A0 * * ULONG TT_UStrWidth (UWORD*); * * FUNCTION * Calculates the pixel width of given 16-bit Unicode string written * with current font. Takes kerning into account. * * INPUTS * string - the width of this 16-bit Unicode string will be calculated. * * RESULT * width - the width of the string in pixels. * * NOTES * * BUGS * * SEE ALSO * TT_PutUStr(), TT_SetFont() * ***************************************************************************** * */ __saveds ULONG TT_UStrWidth(struct TTRenderBase *ttb reg(a6), UWORD *string reg(a0)) { return (tt_strwidth(ttb, &ttb->ttb_RenderEnv, string, TRUE)); }