Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- dlls/gdi32/freetype.c | 698 +++++++++++++++++++++--------------------- 1 file changed, 351 insertions(+), 347 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index e5e3af2fe4..8e4d8e33ad 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -7002,7 +7002,7 @@ static void compute_gm_abc_metrics( GdiFont *incoming_font, GdiFont *font, TRACE( "abc: %d,%u,%d\n", abc->abcA, abc->abcB, abc->abcC ); }
-static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf) +static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, BYTE *buf) { TTPOLYGONHEADER *pph; TTPOLYCURVE *ppc; @@ -7075,7 +7075,7 @@ static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int b return needed; }
-static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf) +static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, BYTE *buf) { /* Convert the quadratic Beziers to cubic Beziers. The parametric eqn for a cubic Bezier is, from PLRM: @@ -7199,6 +7199,345 @@ static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int b return needed; }
+static DWORD get_ggo_glyph_from_outline( FT_GlyphSlot glyph, UINT format, FT_BBox bbox, + GLYPHMETRICS *gm, + BOOL needsTransform, FT_Matrix *transMatTategaki, + DWORD buflen, BYTE *buf ) +{ + DWORD width = (bbox.xMax - bbox.xMin) >> 6; + DWORD height = (bbox.yMax - bbox.yMin) >> 6; + FT_Outline *outline = &glyph->outline; + DWORD max_level, pitch, needed = 0; + FT_Bitmap ft_bitmap; + + switch (format) + { + case GGO_BITMAP: + pitch = ((width + 31) >> 5) << 2; + needed = pitch * height; + + if (!buf || !buflen) break; + if (!needed) return GDI_ERROR; /* empty glyph */ + if (needed > buflen) return GDI_ERROR; + + ft_bitmap.width = width; + ft_bitmap.rows = height; + ft_bitmap.pitch = pitch; + ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + ft_bitmap.buffer = buf; + + if (needsTransform) + pFT_Outline_Transform( outline, transMatTategaki ); + pFT_Outline_Translate( outline, -bbox.xMin, -bbox.yMin ); + + /* Note: FreeType will only set 'black' bits for us. */ + memset( buf, 0, needed ); + pFT_Outline_Get_Bitmap( library, outline, &ft_bitmap ); + break; + + case GGO_GRAY2_BITMAP: + case GGO_GRAY4_BITMAP: + case GGO_GRAY8_BITMAP: + case WINE_GGO_GRAY16_BITMAP: + pitch = (width + 3) / 4 * 4; + needed = pitch * height; + + if (!buf || !buflen) break; + if (!needed) return GDI_ERROR; /* empty glyph */ + if (needed > buflen) return GDI_ERROR; + + ft_bitmap.width = width; + ft_bitmap.rows = height; + ft_bitmap.pitch = pitch; + ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; + ft_bitmap.buffer = buf; + + if (needsTransform) + pFT_Outline_Transform( outline, transMatTategaki ); + pFT_Outline_Translate( outline, -bbox.xMin, -bbox.yMin ); + + memset( ft_bitmap.buffer, 0, buflen ); + pFT_Outline_Get_Bitmap( library, outline, &ft_bitmap ); + + max_level = get_max_level( format ); + if (max_level != 255) + { + BYTE *start, *ptr; + UINT row, col; + + for (row = 0, start = buf; row < height; row++) + { + for (col = 0, ptr = start; col < width; col++, ptr++) + *ptr = (((int)*ptr) * (max_level + 1)) / 256; + start += pitch; + } + } + break; + + case WINE_GGO_HRGB_BITMAP: + case WINE_GGO_HBGR_BITMAP: + case WINE_GGO_VRGB_BITMAP: + case WINE_GGO_VBGR_BITMAP: + { + BYTE *src; + unsigned int *dst; + INT x, rgb_interval, hmul, vmul; + INT src_pitch, src_width, src_height, x_shift, y_shift; + const INT *sub_order; + const INT rgb_order[3] = { 0, 1, 2 }; + const INT bgr_order[3] = { 2, 1, 0 }; + FT_Render_Mode render_mode = + (format == WINE_GGO_HRGB_BITMAP || + format == WINE_GGO_HBGR_BITMAP) ? FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V; + + if (!width || !height) /* empty glyph */ + { + if (!buf || !buflen) break; + return GDI_ERROR; + } + + if (render_mode == FT_RENDER_MODE_LCD) + { + gm->gmBlackBoxX += 2; + gm->gmptGlyphOrigin.x -= 1; + bbox.xMin -= (1 << 6); + } + else + { + gm->gmBlackBoxY += 2; + gm->gmptGlyphOrigin.y += 1; + bbox.yMax += (1 << 6); + } + + width = gm->gmBlackBoxX; + height = gm->gmBlackBoxY; + pitch = width * 4; + needed = pitch * height; + + if (!buf || !buflen) break; + if (needed > buflen) return GDI_ERROR; + + memset( buf, 0, buflen ); + dst = (unsigned int *)buf; + + if (needsTransform) + pFT_Outline_Transform( outline, transMatTategaki ); + +#ifdef FT_LCD_FILTER_H + if (pFT_Library_SetLcdFilter) + pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT ); +#endif + pFT_Render_Glyph( glyph, render_mode ); + + src = glyph->bitmap.buffer; + src_pitch = glyph->bitmap.pitch; + src_width = glyph->bitmap.width; + src_height = glyph->bitmap.rows; + + rgb_interval = render_mode == FT_RENDER_MODE_LCD ? 1 : src_pitch; + hmul = render_mode == FT_RENDER_MODE_LCD ? 3 : 1; + vmul = render_mode == FT_RENDER_MODE_LCD ? 1 : 3; + + x_shift = glyph->bitmap_left - (bbox.xMin >> 6); + if (x_shift < 0) + { + src += hmul * -x_shift; + src_width -= hmul * -x_shift; + } + else if (x_shift > 0) + { + dst += x_shift; + width -= x_shift; + } + + y_shift = (bbox.yMax >> 6) - glyph->bitmap_top; + if (y_shift < 0) + { + src += src_pitch * vmul * -y_shift; + src_height -= vmul * -y_shift; + } + else if (y_shift > 0) + { + dst += y_shift * (pitch / sizeof(*dst)); + height -= y_shift; + } + + width = min( width, src_width / hmul ); + height = min( height, src_height / vmul ); + + sub_order = (format == WINE_GGO_HRGB_BITMAP || + format == WINE_GGO_VRGB_BITMAP) ? rgb_order : bgr_order; + + while (height--) + { + for (x = 0; x < width; x++) + { + dst[x] = ((unsigned int)src[hmul * x + rgb_interval * sub_order[0]] << 16) | + ((unsigned int)src[hmul * x + rgb_interval * sub_order[1]] << 8) | + ((unsigned int)src[hmul * x + rgb_interval * sub_order[2]]); + } + src += src_pitch * vmul; + dst += pitch / sizeof(*dst); + } + break; + } + case GGO_NATIVE: + if (buflen == 0) buf = NULL; + + if (needsTransform && buf) + pFT_Outline_Transform( outline, transMatTategaki ); + + needed = get_native_glyph_outline( outline, buflen, NULL ); + + if (!buf || !buflen) break; + if (needed > buflen) return GDI_ERROR; + + get_native_glyph_outline( outline, buflen, buf ); + break; + + case GGO_BEZIER: + if (buflen == 0) buf = NULL; + + if (needsTransform && buf) + pFT_Outline_Transform( outline, transMatTategaki ); + + needed = get_bezier_glyph_outline( outline, buflen, NULL ); + + if (!buf || !buflen) break; + if (needed > buflen) return GDI_ERROR; + + get_bezier_glyph_outline( outline, buflen, buf ); + break; + + default: + FIXME("Unsupported format %d\n", format); + return GDI_ERROR; + } + + return needed; +} + +static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; + +static DWORD get_ggo_glyph_from_bitmap( FT_GlyphSlot glyph, UINT format, FT_BBox bbox, + GdiFont *font, + DWORD buflen, BYTE *buf ) +{ + DWORD width = (bbox.xMax - bbox.xMin) >> 6; + DWORD height = (bbox.yMax - bbox.yMin) >> 6; + DWORD max_level, pitch, needed = 0; + BYTE *src, *dst; + INT x, w, h; + + switch (format) + { + case GGO_BITMAP: + pitch = ((width + 31) >> 5) << 2; + needed = pitch * height; + + if (!buf || !buflen) break; + if (!needed) return GDI_ERROR; /* empty glyph */ + if (needed > buflen) return GDI_ERROR; + + src = glyph->bitmap.buffer; + dst = buf; + w = min( pitch, (glyph->bitmap.width + 7) >> 3 ); + h = min( height, glyph->bitmap.rows ); + while (h--) + { + if (!font->fake_bold) + memcpy( dst, src, w ); + else + { + dst[0] = 0; + for (x = 0; x < w; x++) + { + dst[x] = (dst[x] & 0x80) | (src[x] >> 1) | src[x]; + if (x + 1 < pitch) + dst[x + 1] = (src[x] & 0x01) << 7; + } + } + src += glyph->bitmap.pitch; + dst += pitch; + } + break; + + case GGO_GRAY2_BITMAP: + case GGO_GRAY4_BITMAP: + case GGO_GRAY8_BITMAP: + case WINE_GGO_GRAY16_BITMAP: + pitch = (width + 3) / 4 * 4; + needed = pitch * height; + + if(!buf || !buflen) break; + if (!needed) return GDI_ERROR; /* empty glyph */ + if (needed > buflen) return GDI_ERROR; + + src = glyph->bitmap.buffer; + dst = buf; + memset( buf, 0, buflen ); + max_level = get_max_level( format ); + h = min( height, glyph->bitmap.rows ); + while (h--) + { + for (x = 0; x < pitch && x < glyph->bitmap.width; x++) + { + if (src[x / 8] & masks[x % 8]) + { + dst[x] = max_level; + if (font->fake_bold && x + 1 < pitch) + dst[x+1] = max_level; + } + } + src += glyph->bitmap.pitch; + dst += pitch; + } + break; + + case WINE_GGO_HRGB_BITMAP: + case WINE_GGO_HBGR_BITMAP: + case WINE_GGO_VRGB_BITMAP: + case WINE_GGO_VBGR_BITMAP: + pitch = width * 4; + needed = pitch * height; + + if (!buf || !buflen) break; + if (!needed) return GDI_ERROR; /* empty glyph */ + if (needed > buflen) return GDI_ERROR; + + src = glyph->bitmap.buffer; + dst = buf; + memset(buf, 0, buflen); + h = min( height, glyph->bitmap.rows ); + while (h--) + { + for (x = 0; x < width && x < glyph->bitmap.width; x++) + { + if (src[x / 8] & masks[x % 8]) + { + ((unsigned int *)dst)[x] = ~0u; + if (font->fake_bold && x + 1 < width) + ((unsigned int *)dst)[x + 1] = ~0u; + } + } + src += glyph->bitmap.pitch; + dst += pitch; + } + break; + + case GGO_NATIVE: + case GGO_BEZIER: + TRACE("loaded a bitmap\n"); + return GDI_ERROR; + + default: + FIXME("Unsupported format %d\n", format); + return GDI_ERROR; + } + + return needed; +} + static FT_Int get_load_flags( UINT format ) { FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; @@ -7230,8 +7569,6 @@ static FT_Int get_load_flags( UINT format ) return load_flags; }
-static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; - static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf, const MAT2* lpmat) @@ -7242,8 +7579,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, GdiFont *font = incoming_font; FT_Glyph_Metrics metrics; FT_UInt glyph_index; - DWORD width, height, pitch, needed = 0; - FT_Bitmap ft_bitmap; + DWORD needed = 0; FT_Error err; FT_BBox bbox; FT_Int load_flags = get_load_flags(format); @@ -7334,9 +7670,6 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, &transMat, &transMatTategaki, &transMatUnrotated, &gm, abc );
- width = (bbox.xMax - bbox.xMin) >> 6; - height = (bbox.yMax - bbox.yMin) >> 6; - if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) && is_identity_MAT2(lpmat)) /* don't cache custom transforms */ cache_gm_abc_metrics( font, glyph_index, &gm, abc ); @@ -7347,352 +7680,23 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, return 1; /* FIXME */ }
- if(ft_face->glyph->format != ft_glyph_format_outline && - (format == GGO_NATIVE || format == GGO_BEZIER)) + switch (ft_face->glyph->format) { - TRACE("loaded a bitmap\n"); - return GDI_ERROR; - } - - switch(format) { - case GGO_BITMAP: - pitch = ((width + 31) >> 5) << 2; - needed = pitch * height; - - if(!buf || !buflen) break; - if (!needed) return GDI_ERROR; /* empty glyph */ - if (needed > buflen) - return GDI_ERROR; - - switch(ft_face->glyph->format) { - case ft_glyph_format_bitmap: - { - BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf; - INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 ); - INT h = min( height, ft_face->glyph->bitmap.rows ); - while(h--) { - if (!font->fake_bold) - memcpy(dst, src, w); - else { - INT x; - dst[0] = 0; - for (x = 0; x < w; x++) { - dst[x ] = (dst[x] & 0x80) | (src[x] >> 1) | src[x]; - if (x+1 < pitch) - dst[x+1] = (src[x] & 0x01) << 7; - } - } - src += ft_face->glyph->bitmap.pitch; - dst += pitch; - } - break; - } - - case ft_glyph_format_outline: - ft_bitmap.width = width; - ft_bitmap.rows = height; - ft_bitmap.pitch = pitch; - ft_bitmap.pixel_mode = ft_pixel_mode_mono; - ft_bitmap.buffer = buf; - - if(needsTransform) - pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki); - - pFT_Outline_Translate(&ft_face->glyph->outline, -bbox.xMin, -bbox.yMin ); - - /* Note: FreeType will only set 'black' bits for us. */ - memset(buf, 0, needed); - pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); - break; - - default: - FIXME("loaded glyph format %x\n", ft_face->glyph->format); - return GDI_ERROR; - } - break; - - case GGO_GRAY2_BITMAP: - case GGO_GRAY4_BITMAP: - case GGO_GRAY8_BITMAP: - case WINE_GGO_GRAY16_BITMAP: - { - unsigned int max_level, row, col; - BYTE *start, *ptr; - - pitch = (width + 3) / 4 * 4; - needed = pitch * height; - - if(!buf || !buflen) break; - if (!needed) return GDI_ERROR; /* empty glyph */ - if (needed > buflen) - return GDI_ERROR; - - max_level = get_max_level( format ); - - switch(ft_face->glyph->format) { - case ft_glyph_format_bitmap: - { - BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf; - INT h = min( height, ft_face->glyph->bitmap.rows ); - INT x; - memset( buf, 0, needed ); - while(h--) { - for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++) { - if (src[x / 8] & masks[x % 8]) { - dst[x] = max_level; - if (font->fake_bold && x+1 < pitch) dst[x+1] = max_level; - } - } - src += ft_face->glyph->bitmap.pitch; - dst += pitch; - } - break; - } - case ft_glyph_format_outline: - { - ft_bitmap.width = width; - ft_bitmap.rows = height; - ft_bitmap.pitch = pitch; - ft_bitmap.pixel_mode = ft_pixel_mode_grays; - ft_bitmap.buffer = buf; - - if(needsTransform) - pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki); - - pFT_Outline_Translate(&ft_face->glyph->outline, -bbox.xMin, -bbox.yMin ); - - memset(ft_bitmap.buffer, 0, buflen); - - pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); - - if (max_level != 255) - { - for (row = 0, start = buf; row < height; row++) - { - for (col = 0, ptr = start; col < width; col++, ptr++) - *ptr = (((int)*ptr) * (max_level + 1)) / 256; - start += pitch; - } - } - break; - } - - default: - FIXME("loaded glyph format %x\n", ft_face->glyph->format); - return GDI_ERROR; - } - break; - } - - case WINE_GGO_HRGB_BITMAP: - case WINE_GGO_HBGR_BITMAP: - case WINE_GGO_VRGB_BITMAP: - case WINE_GGO_VBGR_BITMAP: - { - switch (ft_face->glyph->format) - { case FT_GLYPH_FORMAT_BITMAP: - { - BYTE *src, *dst; - INT src_pitch, x; - - pitch = width * 4; - needed = pitch * height; - - if (!buf || !buflen) break; - if (!needed) return GDI_ERROR; /* empty glyph */ - if (needed > buflen) - return GDI_ERROR; - - memset(buf, 0, buflen); - dst = buf; - src = ft_face->glyph->bitmap.buffer; - src_pitch = ft_face->glyph->bitmap.pitch; - - height = min( height, ft_face->glyph->bitmap.rows ); - while ( height-- ) - { - for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++) - { - if ( src[x / 8] & masks[x % 8] ) - { - ((unsigned int *)dst)[x] = ~0u; - if (font->fake_bold && x+1 < width) ((unsigned int *)dst)[x+1] = ~0u; - } - } - src += src_pitch; - dst += pitch; - } - + needed = get_ggo_glyph_from_bitmap( ft_face->glyph, format, bbox, font, + buflen, buf ); break; - } - case FT_GLYPH_FORMAT_OUTLINE: - { - unsigned int *dst; - BYTE *src; - INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul; - INT x_shift, y_shift; - const INT *sub_order; - const INT rgb_order[3] = { 0, 1, 2 }; - const INT bgr_order[3] = { 2, 1, 0 }; - FT_Render_Mode render_mode = - (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)? - FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V; - - if (!width || !height) - { - if (!buf || !buflen) break; - return GDI_ERROR; - } - - if ( render_mode == FT_RENDER_MODE_LCD) - { - gm.gmBlackBoxX += 2; - gm.gmptGlyphOrigin.x -= 1; - bbox.xMin -= (1 << 6); - } - else - { - gm.gmBlackBoxY += 2; - gm.gmptGlyphOrigin.y += 1; - bbox.yMax += (1 << 6); - } - - width = gm.gmBlackBoxX; - height = gm.gmBlackBoxY; - pitch = width * 4; - needed = pitch * height; - - if (!buf || !buflen) break; - if (needed > buflen) - return GDI_ERROR; - - memset(buf, 0, buflen); - dst = buf; - - if ( needsTransform ) - pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki); - -#ifdef FT_LCD_FILTER_H - if ( pFT_Library_SetLcdFilter ) - pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT ); -#endif - pFT_Render_Glyph (ft_face->glyph, render_mode); - - src = ft_face->glyph->bitmap.buffer; - src_pitch = ft_face->glyph->bitmap.pitch; - src_width = ft_face->glyph->bitmap.width; - src_height = ft_face->glyph->bitmap.rows; - - if ( render_mode == FT_RENDER_MODE_LCD) - { - rgb_interval = 1; - hmul = 3; - vmul = 1; - } - else - { - rgb_interval = src_pitch; - hmul = 1; - vmul = 3; - } - - x_shift = ft_face->glyph->bitmap_left - (bbox.xMin >> 6); - if ( x_shift < 0 ) - { - src += hmul * -x_shift; - src_width -= hmul * -x_shift; - } - else if ( x_shift > 0 ) - { - dst += x_shift; - width -= x_shift; - } - - y_shift = (bbox.yMax >> 6) - ft_face->glyph->bitmap_top; - if ( y_shift < 0 ) - { - src += src_pitch * vmul * -y_shift; - src_height -= vmul * -y_shift; - } - else if ( y_shift > 0 ) - { - dst += y_shift * ( pitch / sizeof(*dst) ); - height -= y_shift; - } - - width = min( width, src_width / hmul ); - height = min( height, src_height / vmul ); - - sub_order = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP)? - rgb_order : bgr_order; - - while ( height-- ) - { - for ( x = 0; x < width; x++ ) - { - dst[x] = ((unsigned int)src[hmul * x + rgb_interval * sub_order[0]] << 16) | - ((unsigned int)src[hmul * x + rgb_interval * sub_order[1]] << 8) | - ((unsigned int)src[hmul * x + rgb_interval * sub_order[2]]); - } - src += src_pitch * vmul; - dst += pitch / sizeof(*dst); - } - + needed = get_ggo_glyph_from_outline( ft_face->glyph, format, bbox, &gm, + needsTransform, &transMatTategaki, + buflen, buf ); break; - } - default: - FIXME ("loaded glyph format %x\n", ft_face->glyph->format); - return GDI_ERROR; - } - - break; - } - - case GGO_NATIVE: - { - FT_Outline *outline = &ft_face->glyph->outline; - - if(buflen == 0) buf = NULL; - - if (needsTransform && buf) - pFT_Outline_Transform(outline, &transMatTategaki); - - needed = get_native_glyph_outline(outline, buflen, NULL); - - if (!buf || !buflen) - break; - if (needed > buflen) - return GDI_ERROR; - - get_native_glyph_outline(outline, buflen, buf); - break; - } - case GGO_BEZIER: - { - FT_Outline *outline = &ft_face->glyph->outline; - if(buflen == 0) buf = NULL; - - if (needsTransform && buf) - pFT_Outline_Transform(outline, &transMatTategaki); - - needed = get_bezier_glyph_outline(outline, buflen, NULL); - - if (!buf || !buflen) - break; - if (needed > buflen) + FIXME("loaded glyph format %x\n", ft_face->glyph->format); return GDI_ERROR; - - get_bezier_glyph_outline(outline, buflen, buf); - break; - } - - default: - FIXME("Unsupported format %d\n", format); - return GDI_ERROR; } + if (needed == GDI_ERROR) return GDI_ERROR; + *lpgm = gm; return needed; }