From: James Tabor Date: Sat, 11 Oct 2014 05:34:30 +0000 (+0000) Subject: [Win32k] X-Git-Tag: backups/0.3.17@66124~99 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=7564a04e4383d1ca3e85da5e9e953578be13d762 [Win32k] - Patch by Matteo Bruni : Don't overflow the buffer in GetGlyphOutline. svn path=/trunk/; revision=64657 --- diff --git a/reactos/win32ss/gdi/ntgdi/freetype.c b/reactos/win32ss/gdi/ntgdi/freetype.c index 3d40e57c5dc..bf5d0b9d4e4 100644 --- a/reactos/win32ss/gdi/ntgdi/freetype.c +++ b/reactos/win32ss/gdi/ntgdi/freetype.c @@ -1497,6 +1497,203 @@ static __inline FT_Fixed FT_FixedFromFIXED(FIXED f) return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract); } +static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf) +{ + TTPOLYGONHEADER *pph; + TTPOLYCURVE *ppc; + unsigned int needed = 0, point = 0, contour, first_pt; + unsigned int pph_start, cpfx; + DWORD type; + + for (contour = 0; contour < outline->n_contours; contour++) + { + /* Ignore contours containing one point */ + if (point == outline->contours[contour]) + { + point++; + continue; + } + + pph_start = needed; + pph = (TTPOLYGONHEADER *)(buf + needed); + first_pt = point; + if (buf) + { + pph->dwType = TT_POLYGON_TYPE; + FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart); + } + needed += sizeof(*pph); + point++; + while (point <= outline->contours[contour]) + { + ppc = (TTPOLYCURVE *)(buf + needed); + type = outline->tags[point] & FT_Curve_Tag_On ? + TT_PRIM_LINE : TT_PRIM_QSPLINE; + cpfx = 0; + do + { + if (buf) + FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); + cpfx++; + point++; + } while (point <= outline->contours[contour] && + (outline->tags[point] & FT_Curve_Tag_On) == + (outline->tags[point-1] & FT_Curve_Tag_On)); + /* At the end of a contour Windows adds the start point, but + only for Beziers */ + if (point > outline->contours[contour] && + !(outline->tags[point-1] & FT_Curve_Tag_On)) + { + if (buf) + FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]); + cpfx++; + } + else if (point <= outline->contours[contour] && + outline->tags[point] & FT_Curve_Tag_On) + { + /* add closing pt for bezier */ + if (buf) + FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); + cpfx++; + point++; + } + if (buf) + { + ppc->wType = type; + ppc->cpfx = cpfx; + } + needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX); + } + if (buf) + pph->cb = needed - pph_start; + } + return needed; +} + +static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf) +{ + /* Convert the quadratic Beziers to cubic Beziers. + The parametric eqn for a cubic Bezier is, from PLRM: + r(t) = at^3 + bt^2 + ct + r0 + with the control points: + r1 = r0 + c/3 + r2 = r1 + (c + b)/3 + r3 = r0 + c + b + a + + A quadratic Bezier has the form: + p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2 + + So equating powers of t leads to: + r1 = 2/3 p1 + 1/3 p0 + r2 = 2/3 p1 + 1/3 p2 + and of course r0 = p0, r3 = p2 + */ + int contour, point = 0, first_pt; + TTPOLYGONHEADER *pph; + TTPOLYCURVE *ppc; + DWORD pph_start, cpfx, type; + FT_Vector cubic_control[4]; + unsigned int needed = 0; + + for (contour = 0; contour < outline->n_contours; contour++) + { + pph_start = needed; + pph = (TTPOLYGONHEADER *)(buf + needed); + first_pt = point; + if (buf) + { + pph->dwType = TT_POLYGON_TYPE; + FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart); + } + needed += sizeof(*pph); + point++; + while (point <= outline->contours[contour]) + { + ppc = (TTPOLYCURVE *)(buf + needed); + type = outline->tags[point] & FT_Curve_Tag_On ? + TT_PRIM_LINE : TT_PRIM_CSPLINE; + cpfx = 0; + do + { + if (type == TT_PRIM_LINE) + { + if (buf) + FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); + cpfx++; + point++; + } + else + { + /* Unlike QSPLINEs, CSPLINEs always have their endpoint + so cpfx = 3n */ + + /* FIXME: Possible optimization in endpoint calculation + if there are two consecutive curves */ + cubic_control[0] = outline->points[point-1]; + if (!(outline->tags[point-1] & FT_Curve_Tag_On)) + { + cubic_control[0].x += outline->points[point].x + 1; + cubic_control[0].y += outline->points[point].y + 1; + cubic_control[0].x >>= 1; + cubic_control[0].y >>= 1; + } + if (point+1 > outline->contours[contour]) + cubic_control[3] = outline->points[first_pt]; + else + { + cubic_control[3] = outline->points[point+1]; + if (!(outline->tags[point+1] & FT_Curve_Tag_On)) + { + cubic_control[3].x += outline->points[point].x + 1; + cubic_control[3].y += outline->points[point].y + 1; + cubic_control[3].x >>= 1; + cubic_control[3].y >>= 1; + } + } + /* r1 = 1/3 p0 + 2/3 p1 + r2 = 1/3 p2 + 2/3 p1 */ + cubic_control[1].x = (2 * outline->points[point].x + 1) / 3; + cubic_control[1].y = (2 * outline->points[point].y + 1) / 3; + cubic_control[2] = cubic_control[1]; + cubic_control[1].x += (cubic_control[0].x + 1) / 3; + cubic_control[1].y += (cubic_control[0].y + 1) / 3; + cubic_control[2].x += (cubic_control[3].x + 1) / 3; + cubic_control[2].y += (cubic_control[3].y + 1) / 3; + if (buf) + { + FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]); + FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]); + FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]); + } + cpfx += 3; + point++; + } + } while (point <= outline->contours[contour] && + (outline->tags[point] & FT_Curve_Tag_On) == + (outline->tags[point-1] & FT_Curve_Tag_On)); + /* At the end of a contour Windows adds the start point, + but only for Beziers and we've already done that. + */ + if (point <= outline->contours[contour] && + outline->tags[point] & FT_Curve_Tag_On) + { + /* This is the closing pt of a bezier, but we've already + added it, so just inc point and carry on */ + point++; + } + if (buf) + { + ppc->wType = type; + ppc->cpfx = cpfx; + } + needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX); + } + if (buf) + pph->cb = needed - pph_start; + } + return needed; +} + /* * Based on WineEngGetGlyphOutline * @@ -1936,101 +2133,32 @@ ftGdiGetGlyphOutline( case GGO_NATIVE: { - int contour, point = 0, first_pt; FT_Outline *outline = &ft_face->glyph->outline; - TTPOLYGONHEADER *pph; - TTPOLYCURVE *ppc; - DWORD pph_start, cpfx, type; if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */ IntLockFreeType; if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat); - for (contour = 0; contour < outline->n_contours; contour++) + needed = get_native_glyph_outline(outline, cjBuf, NULL); + + if (!pvBuf || !cjBuf) { - pph_start = needed; - pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed); - first_pt = point; - if (pvBuf) - { - pph->dwType = TT_POLYGON_TYPE; - FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart); - } - needed += sizeof(*pph); - point++; - while (point <= outline->contours[contour]) - { - ppc = (TTPOLYCURVE *)((char *)pvBuf + needed); - type = (outline->tags[point] & FT_Curve_Tag_On) ? - TT_PRIM_LINE : TT_PRIM_QSPLINE; - cpfx = 0; - do - { - if (pvBuf) - FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); - cpfx++; - point++; - } - while (point <= outline->contours[contour] && - (outline->tags[point] & FT_Curve_Tag_On) == - (outline->tags[point-1] & FT_Curve_Tag_On)); - - /* At the end of a contour Windows adds the start point, but - only for Beziers */ - if (point > outline->contours[contour] && - !(outline->tags[point-1] & FT_Curve_Tag_On)) - { - if (pvBuf) - FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]); - cpfx++; - } - else if (point <= outline->contours[contour] && - outline->tags[point] & FT_Curve_Tag_On) - { - /* Add closing pt for bezier */ - if (pvBuf) - FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); - cpfx++; - point++; - } - if (pvBuf) - { - ppc->wType = type; - ppc->cpfx = cpfx; - } - needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX); - } - if (pvBuf) pph->cb = needed - pph_start; + IntUnLockFreeType; + break; } + if (needed > cjBuf) + { + IntUnLockFreeType; + return GDI_ERROR; + } + get_native_glyph_outline(outline, cjBuf, pvBuf); IntUnLockFreeType; break; } case GGO_BEZIER: { - /* Convert the quadratic Beziers to cubic Beziers. - The parametric eqn for a cubic Bezier is, from PLRM: - r(t) = at^3 + bt^2 + ct + r0 - with the control points: - r1 = r0 + c/3 - r2 = r1 + (c + b)/3 - r3 = r0 + c + b + a - - A quadratic Beizer has the form: - p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2 - - So equating powers of t leads to: - r1 = 2/3 p1 + 1/3 p0 - r2 = 2/3 p1 + 1/3 p2 - and of course r0 = p0, r3 = p2 - */ - - int contour, point = 0, first_pt; FT_Outline *outline = &ft_face->glyph->outline; - TTPOLYGONHEADER *pph; - TTPOLYCURVE *ppc; - DWORD pph_start, cpfx, type; - FT_Vector cubic_control[4]; if (cjBuf == 0) pvBuf = NULL; if (needsTransform && pvBuf) @@ -2039,102 +2167,14 @@ ftGdiGetGlyphOutline( FT_Outline_Transform(outline, &transMat); IntUnLockFreeType; } + needed = get_bezier_glyph_outline(outline, cjBuf, NULL); - for (contour = 0; contour < outline->n_contours; contour++) - { - pph_start = needed; - pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed); - first_pt = point; - if (pvBuf) - { - pph->dwType = TT_POLYGON_TYPE; - FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart); - } - needed += sizeof(*pph); - point++; - while (point <= outline->contours[contour]) - { - ppc = (TTPOLYCURVE *)((char *)pvBuf + needed); - type = (outline->tags[point] & FT_Curve_Tag_On) ? - TT_PRIM_LINE : TT_PRIM_CSPLINE; - cpfx = 0; - do - { - if (type == TT_PRIM_LINE) - { - if (pvBuf) - FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); - cpfx++; - point++; - } - else - { - /* Unlike QSPLINEs, CSPLINEs always have their endpoint - so cpfx = 3n */ - - /* FIXME: Possible optimization in endpoint calculation - if there are two consecutive curves */ - cubic_control[0] = outline->points[point-1]; - if (!(outline->tags[point-1] & FT_Curve_Tag_On)) - { - cubic_control[0].x += outline->points[point].x + 1; - cubic_control[0].y += outline->points[point].y + 1; - cubic_control[0].x >>= 1; - cubic_control[0].y >>= 1; - } - if (point+1 > outline->contours[contour]) - cubic_control[3] = outline->points[first_pt]; - else - { - cubic_control[3] = outline->points[point+1]; - if (!(outline->tags[point+1] & FT_Curve_Tag_On)) - { - cubic_control[3].x += outline->points[point].x + 1; - cubic_control[3].y += outline->points[point].y + 1; - cubic_control[3].x >>= 1; - cubic_control[3].y >>= 1; - } - } - /* r1 = 1/3 p0 + 2/3 p1 - r2 = 1/3 p2 + 2/3 p1 */ - cubic_control[1].x = (2 * outline->points[point].x + 1) / 3; - cubic_control[1].y = (2 * outline->points[point].y + 1) / 3; - cubic_control[2] = cubic_control[1]; - cubic_control[1].x += (cubic_control[0].x + 1) / 3; - cubic_control[1].y += (cubic_control[0].y + 1) / 3; - cubic_control[2].x += (cubic_control[3].x + 1) / 3; - cubic_control[2].y += (cubic_control[3].y + 1) / 3; - if (pvBuf) - { - FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]); - FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]); - FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]); - } - cpfx += 3; - point++; - } - } - while (point <= outline->contours[contour] && - (outline->tags[point] & FT_Curve_Tag_On) == - (outline->tags[point-1] & FT_Curve_Tag_On)); - /* At the end of a contour Windows adds the start point, - but only for Beziers and we've already done that. */ - if (point <= outline->contours[contour] && - outline->tags[point] & FT_Curve_Tag_On) - { - /* This is the closing pt of a bezier, but we've already - added it, so just inc point and carry on */ - point++; - } - if (pvBuf) - { - ppc->wType = type; - ppc->cpfx = cpfx; - } - needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX); - } - if (pvBuf) pph->cb = needed - pph_start; - } + if (!pvBuf || !cjBuf) + break; + if (needed > cjBuf) + return GDI_ERROR; + + get_bezier_glyph_outline(outline, cjBuf, pvBuf); break; }