diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 414a85e..7d41034 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -166,6 +166,7 @@ MAKE_FUNCPTR(FT_Matrix_Multiply); MAKE_FUNCPTR(FT_MulFix); MAKE_FUNCPTR(FT_New_Face); MAKE_FUNCPTR(FT_New_Memory_Face); +MAKE_FUNCPTR(FT_Outline_Embolden); MAKE_FUNCPTR(FT_Outline_Get_Bitmap); MAKE_FUNCPTR(FT_Outline_Transform); MAKE_FUNCPTR(FT_Outline_Translate); @@ -2338,6 +2339,7 @@ static BOOL init_freetype(void) LOAD_FUNCPTR(FT_MulFix) LOAD_FUNCPTR(FT_New_Face) LOAD_FUNCPTR(FT_New_Memory_Face) + LOAD_FUNCPTR(FT_Outline_Embolden) LOAD_FUNCPTR(FT_Outline_Get_Bitmap) LOAD_FUNCPTR(FT_Outline_Transform) LOAD_FUNCPTR(FT_Outline_Translate) @@ -4147,6 +4149,102 @@ DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count, return count; } +static void wine_ft_outline_embolden( FT_Outline *outline, FT_Pos hstrength, FT_Pos vstrength ) +{ + if ( !outline ) + return; + + FIXME("%p %d %d\n", outline, (INT)hstrength, (INT)vstrength); + + if ( pFT_Outline_Embolden ) + pFT_Outline_Embolden( outline, hstrength ); +} + +static void wine_ft_bitmap_embolden( FT_Bitmap *bitmap, FT_Int hstr, FT_Int vstr ) +{ + if ( !bitmap || !bitmap->buffer ) + return; + + TRACE("%p %d %d\n", bitmap, hstr, vstr); + + switch ( bitmap->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + { + int x, y, i; + unsigned char *p; + + if ( hstr > 8 ) hstr = 8; + + for ( y = 0; y < bitmap->rows; y++ ) + { + p = bitmap->buffer + y * bitmap->pitch; + for ( x = bitmap->pitch - 1; x >= 0; x-- ) + { + unsigned char tmp = p[x]; + for ( i = 1; i <= hstr; i++ ) + { + p[x] |= tmp >> i; + if ( x > 0 ) + p[x] |= p[x - 1] << ( 8 - i); + } + } + } + for ( y = bitmap->rows - 1; y > 0; y-- ) + { + p = bitmap->buffer + y * bitmap->pitch; + for ( i = 1; i <= vstr; i++ ) + { + if ( y - i >= 0 ) + { + unsigned char *q = p - i * bitmap->pitch; + for ( x = 0; x < bitmap->pitch; x++ ) + p[x] |= q[x]; + } + } + } + } + break; + case FT_PIXEL_MODE_GRAY: + { + int x, y, i; + unsigned char *p; + + for ( y = 0; y < bitmap->rows; y++ ) + { + p = bitmap->buffer + y * bitmap->pitch; + for ( x = bitmap->pitch - 1; x > 0; x--) + { + for ( i = 1; i <= hstr; i++) + { + if ( x - i >= 0) + p[x] = (p[x] > p[x - i])? p[x] : p[x - i]; + } + } + } + for ( y = bitmap->rows - 1; y > 0; y-- ) + { + p = bitmap->buffer + y * bitmap->pitch; + for ( i = 1; i <= vstr; i++ ) + { + if ( y - i >= 0 ) + { + unsigned char *q = p - i * bitmap->pitch; + for ( x = 0; x < bitmap->pitch; x++ ) + p[x] = (p[x] > q[x])? p[x] : q[x];; + } + } + } + } + break; + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + default: + FIXME("Unimplemented pixel mode %d\n", bitmap->pixel_mode ); + break; + } +} + /************************************************************* * WineEngGetGlyphOutline * @@ -4170,6 +4268,9 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, FT_Angle angle = 0; FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; float widthRatio = 1.0; + FT_Pos hstrength = 0, vstrength = 0; + FT_Int hstr = 0, vstr = 0; + FT_Glyph_Metrics glyph_metrics; FT_Matrix transMat = identityMat; BOOL needsTransform = FALSE; BOOL tategaki = (font->GSUB_Table != NULL); @@ -4210,17 +4311,6 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, if (!font->gm[original_index / GM_BLOCK_SIZE]) font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE); - if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat) - load_flags |= FT_LOAD_NO_BITMAP; - - err = pFT_Load_Glyph(ft_face, glyph_index, load_flags); - - if(err) { - WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err); - LeaveCriticalSection( &freetype_cs ); - return GDI_ERROR; - } - /* Scaling factor */ if (font->aveWidth && font->potm) { @@ -4230,13 +4320,6 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, else widthRatio = font->scale_y; - left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64; - right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64; - - adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6; - lsb = left >> 6; - bbx = (right - left) >> 6; - /* Scaling transform */ if(font->aveWidth) { FT_Matrix scaleMat; @@ -4287,10 +4370,48 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, needsTransform = TRUE; } + if ( needsTransform || + !(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) ) + load_flags |= FT_LOAD_NO_BITMAP; + + err = pFT_Load_Glyph( ft_face, glyph_index, load_flags ); + if(err) + { + WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err); + LeaveCriticalSection( &freetype_cs ); + return GDI_ERROR; + } + + glyph_metrics = ft_face->glyph->metrics; + + if ( font->fake_bold ) + { + hstrength = ( pFT_MulFix( ft_face->units_per_EM, ft_face->size->metrics.y_scale ) / 48 + 63 ) & -64; + vstrength = ( pFT_MulFix( ft_face->units_per_EM, ft_face->size->metrics.y_scale ) / 96 ) & -64; + hstr = hstrength >> 6; + vstr = vstrength >> 6; + TRACE("fake_bold: hstrength=%d vstrength=%d\n", (INT)hstrength, (INT)vstrength); + + glyph_metrics.width += hstrength; + glyph_metrics.height += vstrength; +#if 0 + glyph_metrics.horiBearingX -= hstrength / 2; + glyph_metrics.horiBearingY += vstrength; +#endif + if ( hstr < 2 ) + glyph_metrics.horiAdvance += hstrength; + } + + left = (INT)(glyph_metrics.horiBearingX * widthRatio) & -64; + right = (INT)((glyph_metrics.horiBearingX + glyph_metrics.width) * widthRatio + 63) & -64; + + adv = (INT)(glyph_metrics.horiAdvance * widthRatio + 63) >> 6; + lsb = left >> 6; + bbx = (right - left) >> 6; + if(!needsTransform) { - top = (ft_face->glyph->metrics.horiBearingY + 63) & -64; - bottom = (ft_face->glyph->metrics.horiBearingY - - ft_face->glyph->metrics.height) & -64; + top = (glyph_metrics.horiBearingY + 63) & -64; + bottom = (glyph_metrics.horiBearingY - glyph_metrics.height) & -64; lpgm->gmCellIncX = adv; lpgm->gmCellIncY = 0; } else { @@ -4298,10 +4419,8 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, FT_Vector vec; for(xc = 0; xc < 2; xc++) { for(yc = 0; yc < 2; yc++) { - vec.x = (ft_face->glyph->metrics.horiBearingX + - xc * ft_face->glyph->metrics.width); - vec.y = ft_face->glyph->metrics.horiBearingY - - yc * ft_face->glyph->metrics.height; + vec.x = glyph_metrics.horiBearingX + xc * glyph_metrics.width; + vec.y = glyph_metrics.horiBearingY - yc * glyph_metrics.height; TRACE("Vec %ld,%ld\n", vec.x, vec.y); pFT_Vector_Transform(&vec, &transMat); if(xc == 0 && yc == 0) { @@ -4321,7 +4440,7 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, top = (top + 63) & -64; TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom); - vec.x = ft_face->glyph->metrics.horiAdvance; + vec.x = glyph_metrics.horiAdvance; vec.y = 0; pFT_Vector_Transform(&vec, &transMat); lpgm->gmCellIncX = (vec.x+63) >> 6; @@ -4362,6 +4481,13 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, if(!buf || !buflen) break; + ft_bitmap.width = width; + ft_bitmap.rows = height; + ft_bitmap.pitch = pitch; + ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + ft_bitmap.buffer = buf; + memset( buf, 0, buflen ); + switch(ft_face->glyph->format) { case ft_glyph_format_bitmap: { @@ -4373,25 +4499,29 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, src += ft_face->glyph->bitmap.pitch; dst += pitch; } + if ( font->fake_bold ) + wine_ft_bitmap_embolden( &ft_bitmap, hstr, vstr ); 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, &transMat); - } - - pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); - - /* Note: FreeType will only set 'black' bits for us. */ - memset(buf, 0, needed); - pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); + if ( needsTransform ) + { + if ( font->fake_bold ) + wine_ft_outline_embolden( &ft_face->glyph->outline, hstrength, vstrength ); + pFT_Outline_Transform(&ft_face->glyph->outline, &transMat); + pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); + /* Note: FreeType will only set 'black' bits for us. */ + pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); + } + else + { + pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); + /* Note: FreeType will only set 'black' bits for us. */ + pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); + if ( font->fake_bold ) + wine_ft_bitmap_embolden( &ft_bitmap, hstr, vstr ); + } break; default: @@ -4416,6 +4546,13 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, if(!buf || !buflen) break; + ft_bitmap.width = width; + ft_bitmap.rows = height; + ft_bitmap.pitch = pitch; + ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; + ft_bitmap.buffer = buf; + memset( buf, 0, buflen ); + switch(ft_face->glyph->format) { case ft_glyph_format_bitmap: { @@ -4433,26 +4570,29 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, src += ft_face->glyph->bitmap.pitch; dst += pitch; } + if ( font->fake_bold ) + wine_ft_bitmap_embolden( &ft_bitmap, hstr, vstr ); + LeaveCriticalSection( &freetype_cs ); return needed; } 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, &transMat); - - pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); - - memset(ft_bitmap.buffer, 0, buflen); - - pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); - + if ( needsTransform ) + { + if ( font->fake_bold ) + wine_ft_outline_embolden( &ft_face->glyph->outline, hstrength, vstrength ); + pFT_Outline_Transform( &ft_face->glyph->outline, &transMat ); + pFT_Outline_Translate( &ft_face->glyph->outline, -left, -bottom ); + pFT_Outline_Get_Bitmap( library, &ft_face->glyph->outline, &ft_bitmap ); + } + else + { + pFT_Outline_Translate( &ft_face->glyph->outline, -left, -bottom ); + pFT_Outline_Get_Bitmap( library, &ft_face->glyph->outline, &ft_bitmap ); + if ( font->fake_bold ) + wine_ft_bitmap_embolden( &ft_bitmap, hstr, vstr ); + } if(format == GGO_GRAY2_BITMAP) mult = 4; else if(format == GGO_GRAY4_BITMAP) @@ -4493,6 +4633,9 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, if(buflen == 0) buf = NULL; + if ( font->fake_bold ) + wine_ft_outline_embolden( outline, hstrength, vstrength ); + if (needsTransform && buf) { pFT_Outline_Transform(outline, &transMat); } @@ -4573,6 +4716,9 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, FT_Vector cubic_control[4]; if(buflen == 0) buf = NULL; + if ( font->fake_bold ) + wine_ft_outline_embolden( outline, hstrength, vstrength ); + if (needsTransform && buf) { pFT_Outline_Transform(outline, &transMat); }