monomer-1.5.0.0: cbits/fontmanager.c
// Based on code from memononen's https://github.com/memononen/nanovg
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include "fontstash.h"
#include "fontmanager.h"
static float fm__minf(float a, float b) {
return a < b ? a : b;
}
static float fm__maxf(float a, float b) {
return a > b ? a : b;
}
FMcontext* fmInit(float dpr)
{
FMcontext *ctx;
FONSparams fontParams;
ctx = (FMcontext*) malloc(sizeof(FMcontext));
memset(ctx, 0, sizeof(FMcontext));
memset(&fontParams, 0, sizeof(fontParams));
fontParams.width = INIT_FONTIMAGE_SIZE;
fontParams.height = INIT_FONTIMAGE_SIZE;
fontParams.flags = FONS_ZERO_TOPLEFT;
fontParams.renderCreate = NULL;
fontParams.renderUpdate = NULL;
fontParams.renderDraw = NULL;
fontParams.renderDelete = NULL;
fontParams.userPtr = NULL;
// Initialize font manager context
ctx->fs = fonsCreateInternal(&fontParams);
ctx->dpr = dpr;
ctx->scale = 1;
ctx->fontSize = 16.0f;
ctx->letterSpacing = 0.0f;
ctx->lineHeight = 1.0f;
ctx->fontBlur = 0.0f;
ctx->textAlign = ALIGN_LEFT | ALIGN_BASELINE;
ctx->fontId = 0;
return ctx;
}
int fmCreateFont(FMcontext* ctx, const char* name, const char* filename)
{
return fonsAddFont(ctx->fs, name, filename, 0);
}
int fmCreateFontMem(FMcontext* ctx, const char* name, unsigned char* data, int dataSize)
{
return fonsAddFontMem(ctx->fs, name, data, dataSize, 1, 0);
}
void fmSetScale(FMcontext* ctx, float scale) {
ctx->scale = scale;
}
void fmFontFace(FMcontext* ctx, const char* font)
{
ctx->fontId = fonsGetFontByName(ctx->fs, font);
}
void fmFontSize(FMcontext* ctx, float size)
{
ctx->fontSize = size;
}
void fmFontBlur(FMcontext* ctx, float blur)
{
ctx->fontBlur = blur;
}
void fmTextLetterSpacing(FMcontext* ctx, float spacing)
{
ctx->letterSpacing = spacing;
}
void fmTextLineHeight(FMcontext* ctx, float lineHeight)
{
ctx->lineHeight = lineHeight;
}
void fmTextMetrics(FMcontext* ctx, float* ascender, float* descender, float* lineh)
{
float scale = ctx->dpr * ctx->scale;
float invscale = 1.0f / scale;
if (ctx->fontId == FONS_INVALID) return;
fonsSetSize(ctx->fs, ctx->fontSize * scale);
fonsSetSpacing(ctx->fs, ctx->letterSpacing * scale);
fonsSetBlur(ctx->fs, ctx->fontBlur * scale);
fonsSetAlign(ctx->fs, ctx->textAlign);
fonsSetFont(ctx->fs, ctx->fontId);
fonsVertMetrics(ctx->fs, ascender, descender, lineh);
if (ascender != NULL)
*ascender *= invscale;
if (descender != NULL)
*descender *= invscale;
if (lineh != NULL)
*lineh *= invscale;
}
float fmTextBounds(FMcontext* ctx, float x, float y, const char* string, const char* end, float* bounds)
{
float scale = ctx->dpr * ctx->scale;
float invscale = 1.0f / scale;
float width;
if (ctx->fontId == FONS_INVALID) return 0;
fonsSetSize(ctx->fs, ctx->fontSize*scale);
fonsSetSpacing(ctx->fs, ctx->letterSpacing*scale);
fonsSetBlur(ctx->fs, ctx->fontBlur*scale);
fonsSetAlign(ctx->fs, ctx->textAlign);
fonsSetFont(ctx->fs, ctx->fontId);
width = fonsTextBounds(ctx->fs, x*scale, y*scale, string, end, bounds);
if (bounds != NULL) {
// Use line bounds for height.
fonsLineBounds(ctx->fs, y*scale, &bounds[1], &bounds[3]);
bounds[0] *= invscale;
bounds[1] *= invscale;
bounds[2] *= invscale;
bounds[3] *= invscale;
}
return width * invscale;
}
int fmTextGlyphPositions(FMcontext* ctx, float x, float y, const char* string, const char* end, FMGglyphPosition* positions, int maxPositions)
{
float scale = ctx->dpr * ctx->scale;
float invscale = 1.0f / scale;
FONStextIter iter, prevIter;
FONSquad q;
int npos = 0;
if (ctx->fontId == FONS_INVALID) return 0;
if (end == NULL)
end = string + strlen(string);
if (string == end)
return 0;
fonsSetSize(ctx->fs, ctx->fontSize*scale);
fonsSetSpacing(ctx->fs, ctx->letterSpacing*scale);
fonsSetBlur(ctx->fs, ctx->fontBlur*scale);
fonsSetAlign(ctx->fs, ctx->textAlign);
fonsSetFont(ctx->fs, ctx->fontId);
fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_OPTIONAL);
prevIter = iter;
while (fonsTextIterNext(ctx->fs, &iter, &q)) {
// can not retrieve glyph?
if (iter.prevGlyphIndex < 0 && fonsResetAtlas(ctx->fs, MAX_FONTIMAGE_SIZE, MAX_FONTIMAGE_SIZE)) {
iter = prevIter;
fonsTextIterNext(ctx->fs, &iter, &q); // try again
}
prevIter = iter;
positions[npos].str = iter.str;
positions[npos].x = iter.x * invscale;
positions[npos].minx = fm__minf(iter.x, q.x0) * invscale;
positions[npos].maxx = fm__maxf(iter.nextx, q.x1) * invscale;
positions[npos].miny = fm__minf(iter.y, q.y0) * invscale;
positions[npos].maxy = fm__maxf(iter.nexty, q.y1) * invscale;
npos++;
if (npos >= maxPositions)
break;
}
return npos;
}