Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / win32ss / drivers / font / bmfd / glyph.c
diff --git a/win32ss/drivers/font/bmfd/glyph.c b/win32ss/drivers/font/bmfd/glyph.c
new file mode 100644 (file)
index 0000000..ebc5f06
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * PROJECT:         ReactOS win32 subsystem
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * PURPOSE:         GDI font driver for bitmap fonts
+ * PROGRAMMER:      Timo Kreuzer (timo.kreuzer@reactos.org)
+ */
+
+#include "bmfd.h"
+
+FORCEINLINE
+ULONG
+_ReadPixel(
+    CHAR* pjBits,
+    ULONG x,
+    ULONG y,
+    ULONG ulHeight)
+{
+    CHAR j;
+    j = pjBits[(x/8) * ulHeight + y];
+    return (j >> (~x & 0x7)) & 1;
+}
+
+
+FORCEINLINE
+VOID
+_WritePixel(
+    CHAR* pjBits,
+    ULONG x,
+    ULONG y,
+    ULONG cjRow,
+    ULONG color)
+{
+    pjBits += y * cjRow;
+    pjBits += x / 8;
+    *pjBits |= color << (~x & 0x7);
+}
+
+
+PBMFD_FONT
+BmfdGetFontInstance(
+    FONTOBJ *pfo,
+    PBMFD_FACE pface)
+{
+    PBMFD_FONT pfont = pfo->pvProducer;
+    XFORMOBJ *pxo;
+    FLOATOBJ_XFORM xfo;
+
+    if (!pfont)
+    {
+        /* Allocate realization info */
+        pfont = EngAllocMem(0, sizeof(BMFD_FONT), 0);
+        if (!pfont)
+        {
+            return NULL;
+        }
+
+        pxo = FONTOBJ_pxoGetXform(pfo);
+        XFORMOBJ_iGetFloatObjXform(pxo, &xfo);
+
+        pfont->pfo = pfo;
+        pfont->pface = pface;
+        pfont->xScale = FLOATOBJ_GetLong(&xfo.eM11);
+        pfont->yScale = FLOATOBJ_GetLong(&xfo.eM22);
+        pfont->ulAngle = 0;
+
+        /* Set the pvProducer member of the fontobj */
+        pfo->pvProducer = pfont;
+    }
+
+    return pfont;
+}
+
+
+ULONG
+BmfdQueryGlyphAndBitmap(
+    PBMFD_FONT pfont,
+    HGLYPH hg,
+    GLYPHDATA *pgd,
+    GLYPHBITS *pgb,
+    ULONG cjSize)
+{
+    PBMFD_FACE pface = pfont->pface;
+    PGLYPHENTRY pge;
+    ULONG xSrc, ySrc, cxSrc, cySrc;
+    ULONG xDst, yDst, cxDst, cyDst;
+    ULONG xScale, yScale;
+    ULONG ulGlyphOffset, cjDstRow, color;
+    PVOID pvSrc0, pvDst0;
+
+    /* The glyph handle is the byte offset to the glyph in the table */
+    pge = (PGLYPHENTRY)(pface->pCharTable + hg);
+
+    /* Get the bitmap offset depending on file version */
+    if (pface->ulVersion >= 0x300)
+    {
+        cxSrc = GETVAL(pge->ge20.geWidth);
+        ulGlyphOffset = GETVAL(pge->ge30.geOffset);
+    }
+    else
+    {
+        cxSrc = GETVAL(pge->ge30.geWidth);
+        ulGlyphOffset = GETVAL(pge->ge20.geOffset);
+    }
+    cySrc = pface->wPixHeight;
+
+    /* Pointer to the bitmap bits */
+    pvSrc0 = (PBYTE)pface->pFontInfo + ulGlyphOffset;
+    pvDst0 = pgb->aj;
+
+    xScale = pfont->xScale;
+    yScale = pfont->yScale;
+
+    /* Calculate extents of destination bitmap */
+    if (pfont->ulAngle == 90 || pfont->ulAngle == 270)
+    {
+        cxDst = cySrc * xScale;
+        cyDst = cxSrc * yScale;
+    }
+    else
+    {
+        cxDst = cxSrc * xScale;
+        cyDst = cySrc * yScale;
+    }
+    cjDstRow = (cxDst + 7) / 8;
+
+    if (pgd)
+    {
+        /* Fill GLYPHDATA structure */
+        pgd->gdf.pgb = pgb;
+        pgd->hg = hg;
+        pgd->fxD = xScale * (pface->wA + cxDst + pface->wC) << 4;
+        pgd->fxA = xScale * pface->wA << 4;
+        pgd->fxAB = xScale * (pface->wA + cxDst) << 4;
+        pgd->fxInkTop = yScale * pface->wAscent << 4;
+        pgd->fxInkBottom = - yScale * (pface->wDescent << 4);
+        pgd->rclInk.top = - yScale * pface->wAscent;
+        pgd->rclInk.bottom = yScale * pface->wDescent;
+        pgd->rclInk.left = xScale * pface->wA;
+        pgd->rclInk.right = pgd->rclInk.left + cxDst;
+        pgd->ptqD.x.LowPart = 0;
+        pgd->ptqD.x.HighPart = pgd->fxD;
+        pgd->ptqD.y.LowPart = 0;
+        pgd->ptqD.y.HighPart = 0;
+    }
+
+    if (pgb)
+    {
+        /* Verify that the buffer is big enough */
+        if (cjSize < FIELD_OFFSET(GLYPHBITS, aj) + cyDst * cjDstRow)
+        {
+            DbgPrint("Buffer too small (%ld), %ld,%ld\n",
+                     cjSize, cxSrc, cySrc);
+            return FD_ERROR;
+        }
+
+        /* Fill GLYPHBITS structure */
+        pgb->ptlOrigin.x = xScale * pface->wA;
+        pgb->ptlOrigin.y = - yScale * pface->wAscent;
+        pgb->sizlBitmap.cx = cxDst;
+        pgb->sizlBitmap.cy = cyDst;
+
+        /* Erase destination surface */
+        memset(pvDst0, 0, cyDst * cjDstRow);
+
+        switch (pfont->ulAngle)
+        {
+            case 90:
+                /* Copy pixels */
+                for (yDst = 0; yDst < cyDst ; yDst++)
+                {
+                    xSrc = yDst / yScale;
+                    for (xDst = 0; xDst < cxDst; xDst++)
+                    {
+                        ySrc = (cxDst - xDst) / xScale;
+                        color = _ReadPixel(pvSrc0, xSrc, ySrc, cySrc);
+                        _WritePixel(pvDst0, xDst, yDst, cjDstRow, color);
+                    }
+                }
+                break;
+
+            case 180:
+                for (yDst = 0; yDst < cyDst ; yDst++)
+                {
+                    ySrc = (cyDst - yDst) / yScale;
+                    for (xDst = 0; xDst < cxDst; xDst++)
+                    {
+                        xSrc = (cxDst - xDst) / xScale;
+                        color = _ReadPixel(pvSrc0, xSrc, ySrc, cySrc);
+                        _WritePixel(pvDst0, xDst, yDst, cjDstRow, color);
+                    }
+                }
+                break;
+
+            case 270:
+                for (yDst = 0; yDst < cyDst ; yDst++)
+                {
+                    xSrc = (cyDst - yDst) / yScale;
+                    for (xDst = 0; xDst < cxDst; xDst++)
+                    {
+                        ySrc = xDst / xScale;
+                        color = _ReadPixel(pvSrc0, xSrc, ySrc, cySrc);
+                        _WritePixel(pvDst0, xDst, yDst, cjDstRow, color);
+                    }
+                }
+                break;
+
+            case 0:
+            default:
+                for (yDst = 0; yDst < cyDst ; yDst++)
+                {
+                    ySrc = yDst / yScale;
+                    for (xDst = 0; xDst < cxDst; xDst++)
+                    {
+                        xSrc = xDst / xScale;
+                        color = _ReadPixel(pvSrc0, xSrc, ySrc, cySrc);
+                        _WritePixel(pvDst0, xDst, yDst, cjDstRow, color);
+                    }
+                }
+        }
+    }
+
+    /* Return the size of the GLYPHBITS structure */
+    return FIELD_OFFSET(GLYPHBITS, aj) + cyDst * cjDstRow;
+}
+
+ULONG
+BmfdQueryMaxExtents(
+    PBMFD_FONT pfont,
+    PFD_DEVICEMETRICS pfddm,
+    ULONG cjSize)
+{
+    ULONG cjMaxWidth, cjMaxBitmapSize;
+    PFONTINFO16 pFontInfo;
+    ULONG xScale, yScale;
+
+    if (pfddm)
+    {
+        if (cjSize < sizeof(FD_DEVICEMETRICS))
+        {
+            /* Not enough space, fail */
+            return FD_ERROR;
+        }
+
+        pFontInfo = pfont->pface->pFontInfo;
+
+        xScale = pfont->xScale;
+        yScale = pfont->yScale;
+
+        /* Fill FD_DEVICEMETRICS */
+        pfddm->flRealizedType = FDM_MASK;
+        pfddm->pteBase.x = FLOATL_1;
+        pfddm->pteBase.y = 0;
+        pfddm->pteSide.x = 0;
+        pfddm->pteSide.y = FLOATL_1;
+        pfddm->ptlUnderline1.x = 0;
+        pfddm->ptlUnderline1.y = 1;
+        pfddm->ptlStrikeout.x = 0;
+        pfddm->ptlStrikeout.y = -4;
+        pfddm->ptlULThickness.x = 0;
+        pfddm->ptlULThickness.y = 1;
+        pfddm->ptlSOThickness.x = 0;
+        pfddm->ptlSOThickness.y = 1;
+        pfddm->lMinA = 0;
+        pfddm->lMinC = 0;
+        pfddm->lMinD = 0;
+
+        if (pfont->ulAngle == 90 || pfont->ulAngle == 270)
+        {
+            pfddm->cxMax = xScale * GETVAL(pFontInfo->dfPixHeight);
+            pfddm->cyMax = yScale * GETVAL(pFontInfo->dfMaxWidth);
+            pfddm->fxMaxAscender = yScale * GETVAL(pFontInfo->dfAscent) << 4;
+            pfddm->fxMaxDescender = (pfddm->cyMax << 4) - pfddm->fxMaxAscender;
+        }
+        else
+        {
+            pfddm->cxMax = xScale * GETVAL(pFontInfo->dfMaxWidth);
+            pfddm->cyMax = yScale * GETVAL(pFontInfo->dfPixHeight);
+            pfddm->fxMaxAscender = yScale * GETVAL(pFontInfo->dfAscent) << 4;
+            pfddm->fxMaxDescender = (pfddm->cyMax << 4) - pfddm->fxMaxAscender;
+        }
+
+        pfddm->lD = pfddm->cxMax;
+
+        /* Calculate Width in bytes */
+        cjMaxWidth = ((pfddm->cxMax + 7) >> 3);
+
+        /* Calculate size of the bitmap, rounded to DWORDs */
+        cjMaxBitmapSize = ((cjMaxWidth * pfddm->cyMax) + 3) & ~3;
+
+        /* cjGlyphMax is the full size of the GLYPHBITS structure */
+        pfddm->cjGlyphMax = FIELD_OFFSET(GLYPHBITS, aj) + cjMaxBitmapSize;
+
+        /* NOTE: fdxQuantized and NonLinear... stay unchanged */
+    }
+
+    /* Return the size of the structure */
+    return sizeof(FD_DEVICEMETRICS);
+}
+
+
+/** Public Interface **********************************************************/
+
+PFD_GLYPHATTR
+APIENTRY
+BmfdQueryGlyphAttrs(
+    FONTOBJ *pfo,
+    ULONG iMode)
+{
+    DbgPrint("BmfdQueryGlyphAttrs()\n");
+    /* We don't support FO_ATTR_MODE_ROTATE */
+    return NULL;
+}
+
+LONG
+APIENTRY
+BmfdQueryFontData(
+    DHPDEV dhpdev,
+    FONTOBJ *pfo,
+    ULONG iMode,
+    HGLYPH hg,
+    OUT GLYPHDATA *pgd,
+    PVOID pv,
+    ULONG cjSize)
+{
+    PBMFD_FILE pfile = (PBMFD_FILE)pfo->iFile;
+    PBMFD_FACE pface = &pfile->aface[pfo->iFace - 1];
+    PBMFD_FONT pfont= BmfdGetFontInstance(pfo, pface);
+
+    DbgPrint("BmfdQueryFontData(pfo=%p, iMode=%ld, hg=%p, pgd=%p, pv=%p, cjSize=%ld)\n",
+             pfo, iMode, hg, pgd, pv, cjSize);
+//    __debugbreak();
+
+    switch (iMode)
+    {
+        case QFD_GLYPHANDBITMAP: /* 1 */
+            return BmfdQueryGlyphAndBitmap(pfont, hg, pgd, pv, cjSize);
+
+        case QFD_MAXEXTENTS: /* 3 */
+            return BmfdQueryMaxExtents(pfont, pv, cjSize);
+
+            /* we support nothing else */
+        default:
+            return FD_ERROR;
+
+    }
+
+    return FD_ERROR;
+}