xref: /reactos/win32ss/drivers/font/bmfd/glyph.c (revision 4d3df0da)
1 /*
2  * PROJECT:         ReactOS win32 subsystem
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * PURPOSE:         GDI font driver for bitmap fonts
5  * PROGRAMMER:      Timo Kreuzer (timo.kreuzer@reactos.org)
6  */
7 
8 #include "bmfd.h"
9 
10 FORCEINLINE
11 ULONG
12 _ReadPixel(
13     CHAR* pjBits,
14     ULONG x,
15     ULONG y,
16     ULONG ulHeight)
17 {
18     CHAR j;
19     j = pjBits[(x/8) * ulHeight + y];
20     return (j >> (~x & 0x7)) & 1;
21 }
22 
23 
24 FORCEINLINE
25 VOID
26 _WritePixel(
27     CHAR* pjBits,
28     ULONG x,
29     ULONG y,
30     ULONG cjRow,
31     ULONG color)
32 {
33     pjBits += y * cjRow;
34     pjBits += x / 8;
35     *pjBits |= color << (~x & 0x7);
36 }
37 
38 
39 PBMFD_FONT
40 BmfdGetFontInstance(
41     FONTOBJ *pfo,
42     PBMFD_FACE pface)
43 {
44     PBMFD_FONT pfont = pfo->pvProducer;
45     XFORMOBJ *pxo;
46     FLOATOBJ_XFORM xfo;
47 
48     if (!pfont)
49     {
50         /* Allocate realization info */
51         pfont = EngAllocMem(0, sizeof(BMFD_FONT), 0);
52         if (!pfont)
53         {
54             return NULL;
55         }
56 
57         pxo = FONTOBJ_pxoGetXform(pfo);
58         XFORMOBJ_iGetFloatObjXform(pxo, &xfo);
59 
60         pfont->pfo = pfo;
61         pfont->pface = pface;
62         pfont->xScale = FLOATOBJ_GetLong(&xfo.eM11);
63         pfont->yScale = FLOATOBJ_GetLong(&xfo.eM22);
64         pfont->ulAngle = 0;
65 
66         /* Set the pvProducer member of the fontobj */
67         pfo->pvProducer = pfont;
68     }
69 
70     return pfont;
71 }
72 
73 
74 ULONG
75 BmfdQueryGlyphAndBitmap(
76     PBMFD_FONT pfont,
77     HGLYPH hg,
78     GLYPHDATA *pgd,
79     GLYPHBITS *pgb,
80     ULONG cjSize)
81 {
82     PBMFD_FACE pface = pfont->pface;
83     PGLYPHENTRY pge;
84     ULONG xSrc, ySrc, cxSrc, cySrc;
85     ULONG xDst, yDst, cxDst, cyDst;
86     LONG xScale, yScale;
87     ULONG ulGlyphOffset, cjDstRow, color;
88     PVOID pvSrc0, pvDst0;
89 
90     /* The glyph handle is the byte offset to the glyph in the table */
91     pge = (PGLYPHENTRY)(pface->pCharTable + hg);
92 
93     /* Get the bitmap offset depending on file version */
94     if (pface->ulVersion >= 0x300)
95     {
96         cxSrc = GETVAL(pge->ge20.geWidth);
97         ulGlyphOffset = GETVAL(pge->ge30.geOffset);
98     }
99     else
100     {
101         cxSrc = GETVAL(pge->ge30.geWidth);
102         ulGlyphOffset = GETVAL(pge->ge20.geOffset);
103     }
104     cySrc = pface->wPixHeight;
105 
106     /* Pointer to the bitmap bits */
107     pvSrc0 = (PBYTE)pface->pFontInfo + ulGlyphOffset;
108     pvDst0 = pgb->aj;
109 
110     xScale = pfont->xScale;
111     yScale = pfont->yScale;
112 
113     /* Calculate extents of destination bitmap */
114     if (pfont->ulAngle == 90 || pfont->ulAngle == 270)
115     {
116         cxDst = cySrc * xScale;
117         cyDst = cxSrc * yScale;
118     }
119     else
120     {
121         cxDst = cxSrc * xScale;
122         cyDst = cySrc * yScale;
123     }
124     cjDstRow = (cxDst + 7) / 8;
125 
126     if (pgd)
127     {
128         /* Fill GLYPHDATA structure */
129         pgd->gdf.pgb = pgb;
130         pgd->hg = hg;
131         pgd->fxD = xScale * (pface->wA + cxDst + pface->wC) << 4;
132         pgd->fxA = xScale * pface->wA << 4;
133         pgd->fxAB = xScale * (pface->wA + cxDst) << 4;
134         pgd->fxInkTop = yScale * pface->wAscent << 4;
135         pgd->fxInkBottom = - yScale * (pface->wDescent << 4);
136         pgd->rclInk.top = - yScale * pface->wAscent;
137         pgd->rclInk.bottom = yScale * pface->wDescent;
138         pgd->rclInk.left = xScale * pface->wA;
139         pgd->rclInk.right = pgd->rclInk.left + cxDst;
140         pgd->ptqD.x.LowPart = 0;
141         pgd->ptqD.x.HighPart = pgd->fxD;
142         pgd->ptqD.y.LowPart = 0;
143         pgd->ptqD.y.HighPart = 0;
144     }
145 
146     if (pgb)
147     {
148         /* Verify that the buffer is big enough */
149         if (cjSize < FIELD_OFFSET(GLYPHBITS, aj) + cyDst * cjDstRow)
150         {
151             DbgPrint("Buffer too small (%ld), %ld,%ld\n",
152                      cjSize, cxSrc, cySrc);
153             return FD_ERROR;
154         }
155 
156         /* Fill GLYPHBITS structure */
157         pgb->ptlOrigin.x = xScale * pface->wA;
158         pgb->ptlOrigin.y = - yScale * pface->wAscent;
159         pgb->sizlBitmap.cx = cxDst;
160         pgb->sizlBitmap.cy = cyDst;
161 
162         /* Erase destination surface */
163         memset(pvDst0, 0, cyDst * cjDstRow);
164 
165         switch (pfont->ulAngle)
166         {
167             case 90:
168                 /* Copy pixels */
169                 for (yDst = 0; yDst < cyDst ; yDst++)
170                 {
171                     xSrc = yDst / yScale;
172                     for (xDst = 0; xDst < cxDst; xDst++)
173                     {
174                         ySrc = (cxDst - xDst) / xScale;
175                         color = _ReadPixel(pvSrc0, xSrc, ySrc, cySrc);
176                         _WritePixel(pvDst0, xDst, yDst, cjDstRow, color);
177                     }
178                 }
179                 break;
180 
181             case 180:
182                 for (yDst = 0; yDst < cyDst ; yDst++)
183                 {
184                     ySrc = (cyDst - yDst) / yScale;
185                     for (xDst = 0; xDst < cxDst; xDst++)
186                     {
187                         xSrc = (cxDst - xDst) / xScale;
188                         color = _ReadPixel(pvSrc0, xSrc, ySrc, cySrc);
189                         _WritePixel(pvDst0, xDst, yDst, cjDstRow, color);
190                     }
191                 }
192                 break;
193 
194             case 270:
195                 for (yDst = 0; yDst < cyDst ; yDst++)
196                 {
197                     xSrc = (cyDst - yDst) / yScale;
198                     for (xDst = 0; xDst < cxDst; xDst++)
199                     {
200                         ySrc = xDst / xScale;
201                         color = _ReadPixel(pvSrc0, xSrc, ySrc, cySrc);
202                         _WritePixel(pvDst0, xDst, yDst, cjDstRow, color);
203                     }
204                 }
205                 break;
206 
207             case 0:
208             default:
209                 for (yDst = 0; yDst < cyDst ; yDst++)
210                 {
211                     ySrc = yDst / yScale;
212                     for (xDst = 0; xDst < cxDst; xDst++)
213                     {
214                         xSrc = xDst / xScale;
215                         color = _ReadPixel(pvSrc0, xSrc, ySrc, cySrc);
216                         _WritePixel(pvDst0, xDst, yDst, cjDstRow, color);
217                     }
218                 }
219         }
220     }
221 
222     /* Return the size of the GLYPHBITS structure */
223     return FIELD_OFFSET(GLYPHBITS, aj) + cyDst * cjDstRow;
224 }
225 
226 ULONG
227 BmfdQueryMaxExtents(
228     PBMFD_FONT pfont,
229     PFD_DEVICEMETRICS pfddm,
230     ULONG cjSize)
231 {
232     ULONG cjMaxWidth, cjMaxBitmapSize;
233     PFONTINFO16 pFontInfo;
234     ULONG xScale, yScale;
235 
236     if (pfddm)
237     {
238         if (cjSize < sizeof(FD_DEVICEMETRICS))
239         {
240             /* Not enough space, fail */
241             return FD_ERROR;
242         }
243 
244         pFontInfo = pfont->pface->pFontInfo;
245 
246         xScale = pfont->xScale;
247         yScale = pfont->yScale;
248 
249         /* Fill FD_DEVICEMETRICS */
250         pfddm->flRealizedType = FDM_MASK;
251         pfddm->pteBase.x = FLOATL_1;
252         pfddm->pteBase.y = 0;
253         pfddm->pteSide.x = 0;
254         pfddm->pteSide.y = FLOATL_1;
255         pfddm->ptlUnderline1.x = 0;
256         pfddm->ptlUnderline1.y = 1;
257         pfddm->ptlStrikeout.x = 0;
258         pfddm->ptlStrikeout.y = -4;
259         pfddm->ptlULThickness.x = 0;
260         pfddm->ptlULThickness.y = 1;
261         pfddm->ptlSOThickness.x = 0;
262         pfddm->ptlSOThickness.y = 1;
263         pfddm->lMinA = 0;
264         pfddm->lMinC = 0;
265         pfddm->lMinD = 0;
266 
267         if (pfont->ulAngle == 90 || pfont->ulAngle == 270)
268         {
269             pfddm->cxMax = xScale * GETVAL(pFontInfo->dfPixHeight);
270             pfddm->cyMax = yScale * GETVAL(pFontInfo->dfMaxWidth);
271             pfddm->fxMaxAscender = yScale * GETVAL(pFontInfo->dfAscent) << 4;
272             pfddm->fxMaxDescender = (pfddm->cyMax << 4) - pfddm->fxMaxAscender;
273         }
274         else
275         {
276             pfddm->cxMax = xScale * GETVAL(pFontInfo->dfMaxWidth);
277             pfddm->cyMax = yScale * GETVAL(pFontInfo->dfPixHeight);
278             pfddm->fxMaxAscender = yScale * GETVAL(pFontInfo->dfAscent) << 4;
279             pfddm->fxMaxDescender = (pfddm->cyMax << 4) - pfddm->fxMaxAscender;
280         }
281 
282         pfddm->lD = pfddm->cxMax;
283 
284         /* Calculate Width in bytes */
285         cjMaxWidth = ((pfddm->cxMax + 7) >> 3);
286 
287         /* Calculate size of the bitmap, rounded to DWORDs */
288         cjMaxBitmapSize = ((cjMaxWidth * pfddm->cyMax) + 3) & ~3;
289 
290         /* cjGlyphMax is the full size of the GLYPHBITS structure */
291         pfddm->cjGlyphMax = FIELD_OFFSET(GLYPHBITS, aj) + cjMaxBitmapSize;
292 
293         /* NOTE: fdxQuantized and NonLinear... stay unchanged */
294     }
295 
296     /* Return the size of the structure */
297     return sizeof(FD_DEVICEMETRICS);
298 }
299 
300 
301 /** Public Interface **********************************************************/
302 
303 PFD_GLYPHATTR
304 APIENTRY
305 BmfdQueryGlyphAttrs(
306     FONTOBJ *pfo,
307     ULONG iMode)
308 {
309     DbgPrint("BmfdQueryGlyphAttrs()\n");
310     /* We don't support FO_ATTR_MODE_ROTATE */
311     return NULL;
312 }
313 
314 LONG
315 APIENTRY
316 BmfdQueryFontData(
317     DHPDEV dhpdev,
318     FONTOBJ *pfo,
319     ULONG iMode,
320     HGLYPH hg,
321     OUT GLYPHDATA *pgd,
322     PVOID pv,
323     ULONG cjSize)
324 {
325     PBMFD_FILE pfile = (PBMFD_FILE)pfo->iFile;
326     PBMFD_FACE pface = &pfile->aface[pfo->iFace - 1];
327     PBMFD_FONT pfont= BmfdGetFontInstance(pfo, pface);
328 
329     DbgPrint("BmfdQueryFontData(pfo=%p, iMode=%ld, hg=%p, pgd=%p, pv=%p, cjSize=%ld)\n",
330              pfo, iMode, hg, pgd, pv, cjSize);
331 //    __debugbreak();
332 
333     switch (iMode)
334     {
335         case QFD_GLYPHANDBITMAP: /* 1 */
336             return BmfdQueryGlyphAndBitmap(pfont, hg, pgd, pv, cjSize);
337 
338         case QFD_MAXEXTENTS: /* 3 */
339             return BmfdQueryMaxExtents(pfont, pv, cjSize);
340 
341             /* we support nothing else */
342         default:
343             return FD_ERROR;
344 
345     }
346 
347     return FD_ERROR;
348 }
349