libui/areatext/windows_drawtext.c

225 lines
5.0 KiB
C
Raw Normal View History

// 14 september 2015
#include "area.h"
struct uiDrawFont {
HFONT font;
};
uiDrawFont *uiDrawPrepareFont(uiDrawFontSpec *spec)
{
uiDrawFont *df;
LOGFONTW lf;
// TODO use uiNew
df = malloc(sizeof (uiDrawFont));
ZeroMemory(&lf, sizeof (LOGFONTW));
// TODO
df->font = xxxxxxxx(&lf);
if (df->font == NULL)
logLastError("error creating font in uiDrawPrepareFont()");
return df;
}
void uiDrawFreeFont(uiDrawFont *df)
{
if (DeleteObject(df->font) == 0)
logLastError("error deleting font in uiDrawFreeFont()");
// TODO use uiFree
free(df);
}
/* uniscribe notes:
- https://msdn.microsoft.com/en-us/library/windows/desktop/dd317792%28v=vs.85%29.aspx
- https://maxradi.us/documents/uniscribe/
- http://www.catch22.net/tuts/introduction-uniscribe
- http://www.catch22.net/tuts/uniscribe-mysteries
- http://www.catch22.net/tuts/more-uniscribe-mysteries
- http://www.catch22.net/tuts/drawing-styled-text-uniscribe
- http://www.microsoft.com/msj/1198/multilang/multilang.aspx
Even with all this we're on our own with actual paragraph layout; see the last link for example code (which we don't use here). */
struct uniitem {
SCRIPT_ITEM item;
int nGlyphs;
WORD *glyphs;
SCRIPT_VISATTR *visattrs;
int *advances;
GOFFSET *goffsets;
WCHAR *pwcChars;
int nChars;
WORD *clusters;
SCRIPT_LOGATTR *logattr;
ABC abc;
};
struct uniscribe {
WCHAR *text;
size_t len;
HDC dc;
SCRIPT_CONTROL control;
SCRIPT_STATE state;
struct uniitem *items;
int nItems;
SCRIPT_CACHE cache;
};
// the step numbers in this function are according to the "Lay Out Text Using Uniscribe" section of https://msdn.microsoft.com/en-us/library/windows/desktop/dd317792%28v=vs.85%29.aspx
// this does step 4
// steps 1 through 3 are irrelevent here
static void initUniscribe(struct uniscribe *s, WCHAR *text, HDC dc)
{
SCRIPT_ITEM *items;
int nAlloc;
int i;
HRESULT hr;
ZeroMemory(s, sizeof (struct uniscribe));
s->text = text;
s->len = wcslen(s->text);
s->dc = dc;
items = NULL;
nAlloc = 32;
for (;;) {
// TODO use uiRealloc
items = realloc(items, nAlloc * sizeof (SCRIPT_ITEM));
hr = ScriptItemize(s->text, s->len,
nAlloc,
&(s->control), &(s->state),
items, &(s->nItems));
if (hr == S_OK)
break;
if (hr == E_OUTOFMEMORY) {
nAlloc *= 2;
continue;
}
logHRESULT("error itemizing string in initUniscribe()", hr);
}
// this does part of step 6
s->items = malloc(s->nItems * sizeof (struct uniitem));
ZeroMemory(s->items, s->nItems * sizeof (struct uniitem));//TODO remove when switching to uiAlloc
for (i = 0; i < s->nItems; i++) {
s->items[i].pwcChars = s->text + items[i].iCharPos;
s->items[i].nChars = items[i + 1].iCharPos - items[i].iCharPos;
s->items[i].item = items[i];
}
free(items);
}
static void resetItem(struct uniitem *item)
{
if (item->nGlyphs == 0)
return;
item->nGlyphs = 0;
// TODO switch to uiFree
free(item->glyphs);
item->glyphs = NULL;
free(item->visattrs);
item->visattrs = NULL;
free(item->advances);
item->advances = NULL;
free(item->goffsets);
item->goffsets = NULL;
free(item->clusters);
item->clusters = NULL;
free(item->logattr);
item->logattr = NULL;
}
// step 5
// we're not using multiple fonts; we have no lists to merge
// step 6
static void shapeItem(struct uniscribe *s, int n)
{
struct uniitem *item;
int nAlloc;
HRESULT hr;
item = &(s->items[n]);
resetItem(item);
item->clusters = malloc(nChars * sizeof (WORD));
// TODO move to uiAlloc
nAlloc = 1.5 * item->nChars + 16;
for (;;) {
item->glyphs = realloc(item->glyphs, nAlloc * sizeof (WORD));
item->visattrs = realloc(item->visattrs, nAlloc * sizeof (SCRIPT_VISATTR));
hr = ScriptShape(s->dc, &(s->cache),
item->pwcChars, item->nChars,
nAlloc,
&(item->item.a),
item->glyphs, item->clusters,
item->visattrs, &(item->nGlyphs));
if (hr == S_OK)
break;
if (hr == E_OUTOFMEMORY) {
nAlloc *= 2;
continue;
}
logHRESULT("error shaping glyphs in shapeItem()", hr);
}
}
// step 7
// TODO
// step 8
static void placeItem(struct uniscribe *s, int n)
{
struct uniitem *item;
HRESULT hr;
item = &(s->items[n]);
item->advances = malloc(item->nGlyphs * sizeof (int));
item->goffsets = malloc(item->nGlyphs * sizeof (GOFFSET));
hr = ScriptPlace(s->dc, &(s->cache),
item->glyphs, item->nGlyphs, item->visattrs,
&(item->item.a),
item->advances, item->goffsets, &(item->abc));
if (hr != S_OK)
logHRESULT("error placing glyphs in placeItem()", hr);
}
static void breakItem(struct uniscribe *s, int n)
{
struct uniitem *item;
HRESULT hr;
item = &(s->items[n]);
// TODO uiAlloc
item->logattr = malloc(s->nChars * sizeof (SCRIPT_LOGATTR));
hr = ScriptBreak(item->pwcChars, item->nChars,
&(item->item.a),
item->logattr);
if (hr != S_OK)
logLastError("error breaking item in breakItem()");
}
static void uninitUniscribe(struct uniscribe *s)
{
HRESULT hr;
int i;
// TODO use uiFree
for (i = 0; i < s->nItems; i++)
resetItem(&(s->items[i]));
free(s->items);
hr = ScriptCacheFree(&(s->cache));
if (hr != S_OK)
logHRESULT("error freeing Uniscribe cache in uninitUniscribe()");
}