xref: /reactos/dll/opengl/opengl32/wgl_font.c (revision 0c2cdcae)
1 /* Window-specific OpenGL functions implementation.
2  *
3  * Copyright (c) 1999 Lionel Ulmer
4  * Copyright (c) 2005 Raphael Junqueira
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "opengl32.h"
22 
23 #include <math.h>
24 
25 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
26 
27 /***********************************************************************
28  *		wglUseFontBitmaps_common
29  */
wglUseFontBitmaps_common(HDC hdc,DWORD first,DWORD count,DWORD listBase,BOOL unicode)30 static BOOL wglUseFontBitmaps_common( HDC hdc, DWORD first, DWORD count, DWORD listBase, BOOL unicode )
31 {
32     const GLDISPATCHTABLE * funcs = IntGetCurrentDispatchTable();
33     GLYPHMETRICS gm;
34     unsigned int glyph, size = 0;
35     void *bitmap = NULL, *gl_bitmap = NULL;
36     int org_alignment;
37     BOOL ret = TRUE;
38 
39     funcs->GetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
40     funcs->PixelStorei(GL_UNPACK_ALIGNMENT, 4);
41 
42     for (glyph = first; glyph < first + count; glyph++) {
43         static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
44         unsigned int needed_size, height, width, width_int;
45 
46         if (unicode)
47             needed_size = GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
48         else
49             needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &identity);
50 
51         TRACE("Glyph: %3d / List: %d size %d\n", glyph, listBase, needed_size);
52         if (needed_size == GDI_ERROR) {
53             ret = FALSE;
54             break;
55         }
56 
57         if (needed_size > size) {
58             size = needed_size;
59             HeapFree(GetProcessHeap(), 0, bitmap);
60             HeapFree(GetProcessHeap(), 0, gl_bitmap);
61             bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
62             gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
63         }
64         if (unicode)
65             ret = (GetGlyphOutlineW(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR);
66         else
67             ret = (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &identity) != GDI_ERROR);
68         if (!ret) break;
69 
70         if (TRACE_ON(wgl)) {
71             unsigned int bitmask;
72             unsigned char *bitmap_ = bitmap;
73 
74             TRACE("  - bbox: %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
75             TRACE("  - origin: (%d, %d)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
76             TRACE("  - increment: %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
77             if (needed_size != 0) {
78                 TRACE("  - bitmap:\n");
79                 for (height = 0; height < gm.gmBlackBoxY; height++) {
80                     TRACE("      ");
81                     for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
82                         if (bitmask == 0) {
83                             bitmap_ += 1;
84                             bitmask = 0x80;
85                         }
86                         if (*bitmap_ & bitmask)
87                             TRACE("*");
88                         else
89                             TRACE(" ");
90                     }
91                     bitmap_ += (4 - ((UINT_PTR)bitmap_ & 0x03));
92                     TRACE("\n");
93                 }
94             }
95         }
96 
97          /* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
98          * glyph for it to be drawn properly.
99          */
100         if (needed_size != 0) {
101             width_int = (gm.gmBlackBoxX + 31) / 32;
102             for (height = 0; height < gm.gmBlackBoxY; height++) {
103                 for (width = 0; width < width_int; width++) {
104                     ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
105                     ((int *) bitmap)[height * width_int + width];
106                 }
107             }
108         }
109 
110         funcs->NewList(listBase++, GL_COMPILE);
111         if (needed_size != 0) {
112             funcs->Bitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
113                     0 - gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - gm.gmptGlyphOrigin.y,
114                     gm.gmCellIncX, gm.gmCellIncY,
115                     gl_bitmap);
116         } else {
117             /* This is the case of 'empty' glyphs like the space character */
118             funcs->Bitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
119         }
120         funcs->EndList();
121     }
122 
123     funcs->PixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
124     HeapFree(GetProcessHeap(), 0, bitmap);
125     HeapFree(GetProcessHeap(), 0, gl_bitmap);
126     return ret;
127 }
128 
129 /***********************************************************************
130  *		wglUseFontBitmapsA (OPENGL32.@)
131  */
wglUseFontBitmapsA(HDC hdc,DWORD first,DWORD count,DWORD listBase)132 BOOL WINAPI wglUseFontBitmapsA(HDC hdc, DWORD first, DWORD count, DWORD listBase)
133 {
134     return wglUseFontBitmaps_common( hdc, first, count, listBase, FALSE );
135 }
136 
137 /***********************************************************************
138  *		wglUseFontBitmapsW (OPENGL32.@)
139  */
wglUseFontBitmapsW(HDC hdc,DWORD first,DWORD count,DWORD listBase)140 BOOL WINAPI wglUseFontBitmapsW(HDC hdc, DWORD first, DWORD count, DWORD listBase)
141 {
142     return wglUseFontBitmaps_common( hdc, first, count, listBase, TRUE );
143 }
144 
145 /* FIXME: should probably have a glu.h header */
146 
147 typedef struct GLUtesselator GLUtesselator;
148 typedef void (WINAPI *_GLUfuncptr)(void);
149 
150 #define GLU_TESS_BEGIN  100100
151 #define GLU_TESS_VERTEX 100101
152 #define GLU_TESS_END    100102
153 
154 static GLUtesselator * (WINAPI *pgluNewTess)(void);
155 static void (WINAPI *pgluDeleteTess)(GLUtesselator *tess);
156 static void (WINAPI *pgluTessNormal)(GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z);
157 static void (WINAPI *pgluTessBeginPolygon)(GLUtesselator *tess, void *polygon_data);
158 static void (WINAPI *pgluTessEndPolygon)(GLUtesselator *tess);
159 static void (WINAPI *pgluTessCallback)(GLUtesselator *tess, GLenum which, _GLUfuncptr fn);
160 static void (WINAPI *pgluTessBeginContour)(GLUtesselator *tess);
161 static void (WINAPI *pgluTessEndContour)(GLUtesselator *tess);
162 static void (WINAPI *pgluTessVertex)(GLUtesselator *tess, GLdouble *location, GLvoid* data);
163 
load_libglu(void)164 static HMODULE load_libglu(void)
165 {
166     static const WCHAR glu32W[] = {'g','l','u','3','2','.','d','l','l',0};
167     static int already_loaded;
168     static HMODULE module;
169 
170     if (already_loaded) return module;
171     already_loaded = 1;
172 
173     TRACE("Trying to load GLU library\n");
174     module = LoadLibraryW( glu32W );
175     if (!module)
176     {
177         WARN("Failed to load glu32\n");
178         return NULL;
179     }
180 #define LOAD_FUNCPTR(f) p##f = (void *)GetProcAddress( module, #f )
181     LOAD_FUNCPTR(gluNewTess);
182     LOAD_FUNCPTR(gluDeleteTess);
183     LOAD_FUNCPTR(gluTessBeginContour);
184     LOAD_FUNCPTR(gluTessNormal);
185     LOAD_FUNCPTR(gluTessBeginPolygon);
186     LOAD_FUNCPTR(gluTessCallback);
187     LOAD_FUNCPTR(gluTessEndContour);
188     LOAD_FUNCPTR(gluTessEndPolygon);
189     LOAD_FUNCPTR(gluTessVertex);
190 #undef LOAD_FUNCPTR
191     return module;
192 }
193 
fixed_to_double(POINTFX fixed,UINT em_size,GLdouble vertex[3])194 static void fixed_to_double(POINTFX fixed, UINT em_size, GLdouble vertex[3])
195 {
196     vertex[0] = (fixed.x.value + (GLdouble)fixed.x.fract / (1 << 16)) / em_size;
197     vertex[1] = (fixed.y.value + (GLdouble)fixed.y.fract / (1 << 16)) / em_size;
198     vertex[2] = 0.0;
199 }
200 
tess_callback_vertex(GLvoid * vertex)201 static void WINAPI tess_callback_vertex(GLvoid *vertex)
202 {
203     const GLDISPATCHTABLE * funcs = IntGetCurrentDispatchTable();
204     GLdouble *dbl = vertex;
205     TRACE("%f, %f, %f\n", dbl[0], dbl[1], dbl[2]);
206     funcs->Vertex3dv(vertex);
207 }
208 
tess_callback_begin(GLenum which)209 static void WINAPI tess_callback_begin(GLenum which)
210 {
211     const GLDISPATCHTABLE * funcs = IntGetCurrentDispatchTable();
212     TRACE("%d\n", which);
213     funcs->Begin(which);
214 }
215 
tess_callback_end(void)216 static void WINAPI tess_callback_end(void)
217 {
218     const GLDISPATCHTABLE * funcs = IntGetCurrentDispatchTable();
219     TRACE("\n");
220     funcs->End();
221 }
222 
223 typedef struct _bezier_vector {
224     GLdouble x;
225     GLdouble y;
226 } bezier_vector;
227 
bezier_deviation_squared(const bezier_vector * p)228 static double bezier_deviation_squared(const bezier_vector *p)
229 {
230     bezier_vector deviation;
231     bezier_vector vertex;
232     bezier_vector base;
233     double base_length;
234     double dot;
235 
236     vertex.x = (p[0].x + p[1].x*2 + p[2].x)/4 - p[0].x;
237     vertex.y = (p[0].y + p[1].y*2 + p[2].y)/4 - p[0].y;
238 
239     base.x = p[2].x - p[0].x;
240     base.y = p[2].y - p[0].y;
241 
242     base_length = sqrt(base.x*base.x + base.y*base.y);
243     base.x /= base_length;
244     base.y /= base_length;
245 
246     dot = base.x*vertex.x + base.y*vertex.y;
247     dot = min(max(dot, 0.0), base_length);
248     base.x *= dot;
249     base.y *= dot;
250 
251     deviation.x = vertex.x-base.x;
252     deviation.y = vertex.y-base.y;
253 
254     return deviation.x*deviation.x + deviation.y*deviation.y;
255 }
256 
bezier_approximate(const bezier_vector * p,bezier_vector * points,FLOAT deviation)257 static int bezier_approximate(const bezier_vector *p, bezier_vector *points, FLOAT deviation)
258 {
259     bezier_vector first_curve[3];
260     bezier_vector second_curve[3];
261     bezier_vector vertex;
262     int total_vertices;
263 
264     if(bezier_deviation_squared(p) <= deviation*deviation)
265     {
266         if(points)
267             *points = p[2];
268         return 1;
269     }
270 
271     vertex.x = (p[0].x + p[1].x*2 + p[2].x)/4;
272     vertex.y = (p[0].y + p[1].y*2 + p[2].y)/4;
273 
274     first_curve[0] = p[0];
275     first_curve[1].x = (p[0].x + p[1].x)/2;
276     first_curve[1].y = (p[0].y + p[1].y)/2;
277     first_curve[2] = vertex;
278 
279     second_curve[0] = vertex;
280     second_curve[1].x = (p[2].x + p[1].x)/2;
281     second_curve[1].y = (p[2].y + p[1].y)/2;
282     second_curve[2] = p[2];
283 
284     total_vertices = bezier_approximate(first_curve, points, deviation);
285     if(points)
286         points += total_vertices;
287     total_vertices += bezier_approximate(second_curve, points, deviation);
288     return total_vertices;
289 }
290 
291 /***********************************************************************
292  *		wglUseFontOutlines_common
293  */
wglUseFontOutlines_common(HDC hdc,DWORD first,DWORD count,DWORD listBase,FLOAT deviation,FLOAT extrusion,int format,LPGLYPHMETRICSFLOAT lpgmf,BOOL unicode)294 static BOOL wglUseFontOutlines_common(HDC hdc,
295                                       DWORD first,
296                                       DWORD count,
297                                       DWORD listBase,
298                                       FLOAT deviation,
299                                       FLOAT extrusion,
300                                       int format,
301                                       LPGLYPHMETRICSFLOAT lpgmf,
302                                       BOOL unicode)
303 {
304     const GLDISPATCHTABLE * funcs = IntGetCurrentDispatchTable();
305     UINT glyph;
306     const MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
307     GLUtesselator *tess = NULL;
308     LOGFONTW lf;
309     HFONT old_font, unscaled_font;
310     UINT em_size = 1024;
311     RECT rc;
312 
313     TRACE("(%p, %d, %d, %d, %f, %f, %d, %p, %s)\n", hdc, first, count,
314           listBase, deviation, extrusion, format, lpgmf, unicode ? "W" : "A");
315 
316     if(deviation <= 0.0)
317         deviation = 1.0/em_size;
318 
319     if(format == WGL_FONT_POLYGONS)
320     {
321         if (!load_libglu())
322         {
323             ERR("glu32 is required for this function but isn't available\n");
324             return FALSE;
325         }
326 
327         tess = pgluNewTess();
328         if(!tess) return FALSE;
329         pgluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)tess_callback_vertex);
330         pgluTessCallback(tess, GLU_TESS_BEGIN, (_GLUfuncptr)tess_callback_begin);
331         pgluTessCallback(tess, GLU_TESS_END, tess_callback_end);
332     }
333 
334     GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
335     rc.left = rc.right = rc.bottom = 0;
336     rc.top = em_size;
337     DPtoLP(hdc, (POINT*)&rc, 2);
338     lf.lfHeight = -abs(rc.top - rc.bottom);
339     lf.lfOrientation = lf.lfEscapement = 0;
340     unscaled_font = CreateFontIndirectW(&lf);
341     old_font = SelectObject(hdc, unscaled_font);
342 
343     for (glyph = first; glyph < first + count; glyph++)
344     {
345         DWORD needed;
346         GLYPHMETRICS gm;
347         BYTE *buf;
348         TTPOLYGONHEADER *pph;
349         TTPOLYCURVE *ppc;
350         GLdouble *vertices = NULL, *vertices_temp = NULL;
351         int vertex_total = -1;
352 
353         if(unicode)
354             needed = GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
355         else
356             needed = GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, 0, NULL, &identity);
357 
358         if(needed == GDI_ERROR)
359             goto error;
360 
361         buf = HeapAlloc(GetProcessHeap(), 0, needed);
362 
363         if(!buf)
364             goto error;
365 
366         if(unicode)
367             GetGlyphOutlineW(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
368         else
369             GetGlyphOutlineA(hdc, glyph, GGO_NATIVE, &gm, needed, buf, &identity);
370 
371         TRACE("glyph %d\n", glyph);
372 
373         if(lpgmf)
374         {
375             lpgmf->gmfBlackBoxX = (float)gm.gmBlackBoxX / em_size;
376             lpgmf->gmfBlackBoxY = (float)gm.gmBlackBoxY / em_size;
377             lpgmf->gmfptGlyphOrigin.x = (float)gm.gmptGlyphOrigin.x / em_size;
378             lpgmf->gmfptGlyphOrigin.y = (float)gm.gmptGlyphOrigin.y / em_size;
379             lpgmf->gmfCellIncX = (float)gm.gmCellIncX / em_size;
380             lpgmf->gmfCellIncY = (float)gm.gmCellIncY / em_size;
381 
382             TRACE("%fx%f at %f,%f inc %f,%f\n", lpgmf->gmfBlackBoxX, lpgmf->gmfBlackBoxY,
383                   lpgmf->gmfptGlyphOrigin.x, lpgmf->gmfptGlyphOrigin.y, lpgmf->gmfCellIncX, lpgmf->gmfCellIncY);
384             lpgmf++;
385         }
386 
387         funcs->NewList(listBase++, GL_COMPILE);
388         funcs->FrontFace(GL_CCW);
389         if(format == WGL_FONT_POLYGONS)
390         {
391             funcs->Normal3d(0.0, 0.0, 1.0);
392             pgluTessNormal(tess, 0, 0, 1);
393             pgluTessBeginPolygon(tess, NULL);
394         }
395 
396         while(!vertices)
397         {
398             if(vertex_total != -1)
399                 vertices_temp = vertices = HeapAlloc(GetProcessHeap(), 0, vertex_total * 3 * sizeof(GLdouble));
400             vertex_total = 0;
401 
402             pph = (TTPOLYGONHEADER*)buf;
403             while((BYTE*)pph < buf + needed)
404             {
405                 GLdouble previous[3];
406                 fixed_to_double(pph->pfxStart, em_size, previous);
407 
408                 if(vertices)
409                     TRACE("\tstart %d, %d\n", pph->pfxStart.x.value, pph->pfxStart.y.value);
410 
411                 if(format == WGL_FONT_POLYGONS)
412                     pgluTessBeginContour(tess);
413                 else
414                     funcs->Begin(GL_LINE_LOOP);
415 
416                 if(vertices)
417                 {
418                     fixed_to_double(pph->pfxStart, em_size, vertices);
419                     if(format == WGL_FONT_POLYGONS)
420                         pgluTessVertex(tess, vertices, vertices);
421                     else
422                         funcs->Vertex3d(vertices[0], vertices[1], vertices[2]);
423                     vertices += 3;
424                 }
425                 vertex_total++;
426 
427                 ppc = (TTPOLYCURVE*)((char*)pph + sizeof(*pph));
428                 while((char*)ppc < (char*)pph + pph->cb)
429                 {
430                     int i, j;
431                     int num;
432 
433                     switch(ppc->wType) {
434                     case TT_PRIM_LINE:
435                         for(i = 0; i < ppc->cpfx; i++)
436                         {
437                             if(vertices)
438                             {
439                                 TRACE("\t\tline to %d, %d\n",
440                                       ppc->apfx[i].x.value, ppc->apfx[i].y.value);
441                                 fixed_to_double(ppc->apfx[i], em_size, vertices);
442                                 if(format == WGL_FONT_POLYGONS)
443                                     pgluTessVertex(tess, vertices, vertices);
444                                 else
445                                     funcs->Vertex3d(vertices[0], vertices[1], vertices[2]);
446                                 vertices += 3;
447                             }
448                             fixed_to_double(ppc->apfx[i], em_size, previous);
449                             vertex_total++;
450                         }
451                         break;
452 
453                     case TT_PRIM_QSPLINE:
454                         for(i = 0; i < ppc->cpfx-1; i++)
455                         {
456                             bezier_vector curve[3];
457                             bezier_vector *points;
458                             GLdouble curve_vertex[3];
459 
460                             if(vertices)
461                                 TRACE("\t\tcurve  %d,%d %d,%d\n",
462                                       ppc->apfx[i].x.value,     ppc->apfx[i].y.value,
463                                       ppc->apfx[i + 1].x.value, ppc->apfx[i + 1].y.value);
464 
465                             curve[0].x = previous[0];
466                             curve[0].y = previous[1];
467                             fixed_to_double(ppc->apfx[i], em_size, curve_vertex);
468                             curve[1].x = curve_vertex[0];
469                             curve[1].y = curve_vertex[1];
470                             fixed_to_double(ppc->apfx[i + 1], em_size, curve_vertex);
471                             curve[2].x = curve_vertex[0];
472                             curve[2].y = curve_vertex[1];
473                             if(i < ppc->cpfx-2)
474                             {
475                                 curve[2].x = (curve[1].x + curve[2].x)/2;
476                                 curve[2].y = (curve[1].y + curve[2].y)/2;
477                             }
478                             num = bezier_approximate(curve, NULL, deviation);
479                             points = HeapAlloc(GetProcessHeap(), 0, num*sizeof(bezier_vector));
480                             num = bezier_approximate(curve, points, deviation);
481                             vertex_total += num;
482                             if(vertices)
483                             {
484                                 for(j=0; j<num; j++)
485                                 {
486                                     TRACE("\t\t\tvertex at %f,%f\n", points[j].x, points[j].y);
487                                     vertices[0] = points[j].x;
488                                     vertices[1] = points[j].y;
489                                     vertices[2] = 0.0;
490                                     if(format == WGL_FONT_POLYGONS)
491                                         pgluTessVertex(tess, vertices, vertices);
492                                     else
493                                         funcs->Vertex3d(vertices[0], vertices[1], vertices[2]);
494                                     vertices += 3;
495                                 }
496                             }
497                             HeapFree(GetProcessHeap(), 0, points);
498                             previous[0] = curve[2].x;
499                             previous[1] = curve[2].y;
500                         }
501                         break;
502                     default:
503                         ERR("\t\tcurve type = %d\n", ppc->wType);
504                         if(format == WGL_FONT_POLYGONS)
505                             pgluTessEndContour(tess);
506                         else
507                             funcs->End();
508                         goto error_in_list;
509                     }
510 
511                     ppc = (TTPOLYCURVE*)((char*)ppc + sizeof(*ppc) +
512                                          (ppc->cpfx - 1) * sizeof(POINTFX));
513                 }
514                 if(format == WGL_FONT_POLYGONS)
515                     pgluTessEndContour(tess);
516                 else
517                     funcs->End();
518                 pph = (TTPOLYGONHEADER*)((char*)pph + pph->cb);
519             }
520         }
521 
522 error_in_list:
523         if(format == WGL_FONT_POLYGONS)
524             pgluTessEndPolygon(tess);
525         funcs->Translated((GLdouble)gm.gmCellIncX / em_size, (GLdouble)gm.gmCellIncY / em_size, 0.0);
526         funcs->EndList();
527 
528         HeapFree(GetProcessHeap(), 0, buf);
529 
530         if(vertices_temp)
531             HeapFree(GetProcessHeap(), 0, vertices_temp);
532     }
533 
534  error:
535     DeleteObject(SelectObject(hdc, old_font));
536     if(format == WGL_FONT_POLYGONS)
537         pgluDeleteTess(tess);
538     return TRUE;
539 
540 }
541 
542 /***********************************************************************
543  *		wglUseFontOutlinesA (OPENGL32.@)
544  */
wglUseFontOutlinesA(HDC hdc,DWORD first,DWORD count,DWORD listBase,FLOAT deviation,FLOAT extrusion,int format,LPGLYPHMETRICSFLOAT lpgmf)545 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
546 				DWORD first,
547 				DWORD count,
548 				DWORD listBase,
549 				FLOAT deviation,
550 				FLOAT extrusion,
551 				int format,
552 				LPGLYPHMETRICSFLOAT lpgmf)
553 {
554     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, FALSE);
555 }
556 
557 /***********************************************************************
558  *		wglUseFontOutlinesW (OPENGL32.@)
559  */
wglUseFontOutlinesW(HDC hdc,DWORD first,DWORD count,DWORD listBase,FLOAT deviation,FLOAT extrusion,int format,LPGLYPHMETRICSFLOAT lpgmf)560 BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
561 				DWORD first,
562 				DWORD count,
563 				DWORD listBase,
564 				FLOAT deviation,
565 				FLOAT extrusion,
566 				int format,
567 				LPGLYPHMETRICSFLOAT lpgmf)
568 {
569     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
570 }
571