diff --git a/winarea/drawtext.c b/winarea/drawtext.c new file mode 100644 index 00000000..59efbe81 --- /dev/null +++ b/winarea/drawtext.c @@ -0,0 +1,188 @@ +// 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 uniscribe { + WCHAR *text; + size_t len; + HDC dc; + + SCRIPT_CONTROL control; + SCRIPT_STATE state; + + SCRIPT_ITEM *items; + int nItems; + + SCRIPT_CACHE cache; + WORD **glyphs; + WORD **clusters; + SCRIPT_VISATTR **visattrs; + int *nGlyphs; + + int **advances; + GOFFSET **gOffsets; + ABC *abcs; +}; + +// 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 +void initUniscribe(struct uniscribe *s, WCHAR *text, HDC dc) +{ + HRESULT hr; + int nAlloc; + int i; + + ZeroMemory(s, sizeof (struct uniscribe)); + + s->text = text; + s->len = wcslen(s->text); + s->dc = dc; + + // steps 1 through 3 are irrelevent here + + // step 4 + nAlloc = 32; + for (;;) { + // TODO use uiRealloc + s->items = realloc(s->items, nAlloc * sizeof (SCRIPT_ITEM)); + hr = ScriptItemize(s->text, s->len, + nAlloc, + &(s->control), &(s->state), + s->items, &(s->nItems)); + if (hr == S_OK) + break; + if (hr == E_OUTOFMEMORY) { + nAlloc *= 2; + continue; + } + logHRESULT("error itemizing string in initUniscribe()", hr); + } + + // step 5 + // we're not using multiple fonts; we have no lists to merge + + // step 6 + s->glyphs = malloc(s->nItems * sizeof (WORD *)); + s->clusters = malloc(s->nItems * sizeof (WORD *)); + s->visattrs = malloc(s->nItems * sizeof (SCRIPT_VISATTR *)); + s->nGlyphs = malloc(s->nItems * sizeof (int)); + for (i = 0; i < s->nItems; i++) { + WCHAR *pwcChars; + int nChars; + + pwcChars = s->text + s->items[i].iCharPos; + nChars = s->items[i + 1].iCharPos - s->items[i].iCharPos; + nAlloc = 1.5 * nChars + 16; +s->glyphs[i] = NULL;//TODO remove when switched to uiAlloc +s->visattrs[i] = NULL; + s->clusters[i] = malloc(nChars * sizeof (WORD)); + for (;;) { + s->glyphs[i] = realloc(s->glyphs[i], nAlloc * sizeof (WORD)); + s->visattrs[i] = realloc(s->visattrs[i], nAlloc * sizeof (SCRIPT_VISATTR)); + hr = ScriptShape(s->dc, &(s->cache), + pwcChars, nChars, + nAlloc, + &(s->items[i].a), + s->glyphs[i], s->clusters[i], + s->visattrs[i], &(s->nGlyphs[i])); + if (hr == S_OK) + break; + if (hr == E_OUTOFMEMORY) { + nAlloc *= 2; + continue; + } + logHRESULT("error shaping glyphs in initUniscribe()", hr); + } + } + + // step 7 + // TODO + + // step 8 + s->advances = malloc(s->nItems * sizeof (int *)); + s->goffsets = malloc(s->nItems * sizeof (GOFFSET *)); + s->abcs = malloc(s->nItems * sizeof (ABC)); + for (i = 0; i < s->nItems; i++) { + s->advances[i] = malloc(s->nGlyphs[i] * sizeof (int)); + s->goffsets[i] = malloc(s->nGlyphs[i] * sizeof (GOFFSET)); + hr = ScriptPlace(s->dc, &(s->cache), + s->glyphs[i], s->nGlyphs[i], s->visattrs[i], + &(s->items[i].a), + s->advances[i], s->goffsets[i], &(s->abcs[i])); + if (hr != S_OK) + logHRESULT("error placing glyphs in initUniscribe()", hr); + } +} + +void uninitUniscribe(struct uniscribe *s) +{ + HRESULT hr; + int i; + + // TODO use uiFree + + free(s->abcs); + + for (i = 0; i < s->goffsets; i++) + free(s->goffsets[i]); + free(s->goffsets); + + for (i = 0; i < s->nItems; i++) + free(s->advances[i]); + free(s->advances); + + free(s->nGlyphs); + + for (i = 0; i < s->nItems; i++) + free(s->visattrs[i]); + free(s->visattrs); + + for (i = 0; i < s->nItems; i++) + free(s->clusters[i]); + free(s->clusters); + + for (i = 0; i < s->nItems; i++) + free(s->glyphs[i]); + free(s->glyphs); + + hr = ScriptCacheFree(&(s->cache)); + if (hr != S_OK) + logHRESULT("error freeing Uniscribe cache in uninitUniscribe()"); + + free(s->items); +} diff --git a/windows/winapi.h b/windows/winapi.h index bfd8e8ab..11abfb96 100644 --- a/windows/winapi.h +++ b/windows/winapi.h @@ -28,3 +28,4 @@ #include #include #include +#include