static FT_Error PCF_Glyph_Load( FT_GlyphSlot slot, FT_Size size, FT_UInt glyph_index, FT_Int32 load_flags ) { PCF_Face face = (PCF_Face)FT_SIZE_FACE( size ); FT_Stream stream = face->root.stream; FT_Error error = PCF_Err_Ok; FT_Bitmap* bitmap = &slot->bitmap; PCF_Metric metric; int bytes; FT_UNUSED( load_flags ); FT_TRACE4(( "load_glyph %d ---", glyph_index )); if ( !face ) { error = PCF_Err_Invalid_Argument; goto Exit; } if ( glyph_index > 0 ) glyph_index--; metric = face->metrics + glyph_index; bitmap->rows = metric->ascent + metric->descent; bitmap->width = metric->rightSideBearing - metric->leftSideBearing; bitmap->num_grays = 1; bitmap->pixel_mode = FT_PIXEL_MODE_MONO; FT_TRACE6(( "BIT_ORDER %d ; BYTE_ORDER %d ; GLYPH_PAD %d\n", PCF_BIT_ORDER( face->bitmapsFormat ), PCF_BYTE_ORDER( face->bitmapsFormat ), PCF_GLYPH_PAD( face->bitmapsFormat ) )); switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) ) { case 1: bitmap->pitch = ( bitmap->width + 7 ) >> 3; break; case 2: bitmap->pitch = ( ( bitmap->width + 15 ) >> 4 ) << 1; break; case 4: bitmap->pitch = ( ( bitmap->width + 31 ) >> 5 ) << 2; break; case 8: bitmap->pitch = ( ( bitmap->width + 63 ) >> 6 ) << 3; break; default: return PCF_Err_Invalid_File_Format; } /* XXX: to do: are there cases that need repadding the bitmap? */ bytes = bitmap->pitch * bitmap->rows; error = ft_glyphslot_alloc_bitmap( slot, bytes ); if ( error ) goto Exit; if ( FT_STREAM_SEEK( metric->bits ) || FT_STREAM_READ( bitmap->buffer, bytes ) ) goto Exit; if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst ) BitOrderInvert( bitmap->buffer, bytes ); if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) != PCF_BIT_ORDER( face->bitmapsFormat ) ) ) { switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) ) { case 1: break; case 2: TwoByteSwap( bitmap->buffer, bytes ); break; case 4: FourByteSwap( bitmap->buffer, bytes ); break; } } slot->bitmap_left = metric->leftSideBearing; slot->bitmap_top = metric->ascent; slot->metrics.horiAdvance = metric->characterWidth << 6; slot->metrics.horiBearingX = metric->leftSideBearing << 6; slot->metrics.horiBearingY = metric->ascent << 6; slot->metrics.width = ( metric->rightSideBearing - metric->leftSideBearing ) << 6; slot->metrics.height = bitmap->rows << 6; slot->linearHoriAdvance = (FT_Fixed)bitmap->width << 16; slot->format = FT_GLYPH_FORMAT_BITMAP; FT_TRACE4(( " --- ok\n" )); Exit: return error; }
Load_SBit_Png( FT_GlyphSlot slot, FT_Int x_offset, FT_Int y_offset, FT_Int pix_bits, TT_SBit_Metrics metrics, FT_Memory memory, FT_Byte* data, FT_UInt png_len, FT_Bool populate_map_and_metrics ) { FT_Bitmap *map = &slot->bitmap; FT_Error error = FT_Err_Ok; FT_StreamRec stream; png_structp png; png_infop info; png_uint_32 imgWidth, imgHeight; int bitdepth, color_type, interlace; FT_Int i; png_byte* *rows = NULL; /* pacify compiler */ if ( x_offset < 0 || y_offset < 0 ) { error = FT_THROW( Invalid_Argument ); goto Exit; } if ( !populate_map_and_metrics && ( x_offset + metrics->width > map->width || y_offset + metrics->height > map->rows || pix_bits != 32 || map->pixel_mode != FT_PIXEL_MODE_BGRA ) ) { error = FT_THROW( Invalid_Argument ); goto Exit; } FT_Stream_OpenMemory( &stream, data, png_len ); png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, error_callback, warning_callback ); if ( !png ) { error = FT_THROW( Out_Of_Memory ); goto Exit; } info = png_create_info_struct( png ); if ( !info ) { error = FT_THROW( Out_Of_Memory ); png_destroy_read_struct( &png, NULL, NULL ); goto Exit; } if ( ft_setjmp( png_jmpbuf( png ) ) ) { error = FT_THROW( Invalid_File_Format ); goto DestroyExit; } png_set_read_fn( png, &stream, read_data_from_FT_Stream ); png_read_info( png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, NULL, NULL ); if ( error || ( !populate_map_and_metrics && ( (FT_Int)imgWidth != metrics->width || (FT_Int)imgHeight != metrics->height ) ) ) goto DestroyExit; if ( populate_map_and_metrics ) { FT_Long size; metrics->width = (FT_Int)imgWidth; metrics->height = (FT_Int)imgHeight; map->width = metrics->width; map->rows = metrics->height; map->pixel_mode = FT_PIXEL_MODE_BGRA; map->pitch = map->width * 4; map->num_grays = 256; size = map->rows * map->pitch; error = ft_glyphslot_alloc_bitmap( slot, size ); if ( error ) goto DestroyExit; } /* convert palette/gray image to rgb */ if ( color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( png ); /* expand gray bit depth if needed */ if ( color_type == PNG_COLOR_TYPE_GRAY ) { #if PNG_LIBPNG_VER >= 10209 png_set_expand_gray_1_2_4_to_8( png ); #else png_set_gray_1_2_4_to_8( png ); #endif } /* transform transparency to alpha */ if ( png_get_valid(png, info, PNG_INFO_tRNS ) ) png_set_tRNS_to_alpha( png ); if ( bitdepth == 16 ) png_set_strip_16( png ); if ( bitdepth < 8 ) png_set_packing( png ); /* convert grayscale to RGB */ if ( color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( png ); if ( interlace != PNG_INTERLACE_NONE ) png_set_interlace_handling( png ); png_set_filler( png, 0xFF, PNG_FILLER_AFTER ); /* recheck header after setting EXPAND options */ png_read_update_info(png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, NULL, NULL ); if ( bitdepth != 8 || !( color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA ) ) { error = FT_THROW( Invalid_File_Format ); goto DestroyExit; } switch ( color_type ) { default: /* Shouldn't happen, but fall through. */ case PNG_COLOR_TYPE_RGB_ALPHA: png_set_read_user_transform_fn( png, premultiply_data ); break; case PNG_COLOR_TYPE_RGB: /* Humm, this smells. Carry on though. */ png_set_read_user_transform_fn( png, convert_bytes_to_data ); break; } if ( FT_NEW_ARRAY( rows, imgHeight ) ) { error = FT_THROW( Out_Of_Memory ); goto DestroyExit; } for ( i = 0; i < (FT_Int)imgHeight; i++ ) rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4; png_read_image( png, rows ); FT_FREE( rows ); png_read_end( png, info ); DestroyExit: png_destroy_read_struct( &png, &info, NULL ); FT_Stream_Close( &stream ); Exit: return error; }
tt_face_colr_blend_layer( TT_Face face, FT_UInt color_index, FT_GlyphSlot dstSlot, FT_GlyphSlot srcSlot ) { FT_Error error; FT_UInt x, y; FT_Byte b, g, r, alpha; FT_ULong size; FT_Byte* src; FT_Byte* dst; if ( !dstSlot->bitmap.buffer ) { /* Initialize destination of color bitmap */ /* with the size of first component. */ dstSlot->bitmap_left = srcSlot->bitmap_left; dstSlot->bitmap_top = srcSlot->bitmap_top; dstSlot->bitmap.width = srcSlot->bitmap.width; dstSlot->bitmap.rows = srcSlot->bitmap.rows; dstSlot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA; dstSlot->bitmap.pitch = (int)dstSlot->bitmap.width * 4; dstSlot->bitmap.num_grays = 256; size = dstSlot->bitmap.rows * (unsigned int)dstSlot->bitmap.pitch; error = ft_glyphslot_alloc_bitmap( dstSlot, size ); if ( error ) return error; FT_MEM_ZERO( dstSlot->bitmap.buffer, size ); } else { /* Resize destination if needed such that new component fits. */ FT_Int x_min, x_max, y_min, y_max; x_min = FT_MIN( dstSlot->bitmap_left, srcSlot->bitmap_left ); x_max = FT_MAX( dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width, srcSlot->bitmap_left + (FT_Int)srcSlot->bitmap.width ); y_min = FT_MIN( dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows, srcSlot->bitmap_top - (FT_Int)srcSlot->bitmap.rows ); y_max = FT_MAX( dstSlot->bitmap_top, srcSlot->bitmap_top ); if ( x_min != dstSlot->bitmap_left || x_max != dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width || y_min != dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows || y_max != dstSlot->bitmap_top ) { FT_Memory memory = face->root.memory; FT_UInt width = (FT_UInt)( x_max - x_min ); FT_UInt rows = (FT_UInt)( y_max - y_min ); FT_UInt pitch = width * 4; FT_Byte* buf = NULL; FT_Byte* p; FT_Byte* q; size = rows * pitch; if ( FT_ALLOC( buf, size ) ) return error; p = dstSlot->bitmap.buffer; q = buf + (int)pitch * ( y_max - dstSlot->bitmap_top ) + 4 * ( dstSlot->bitmap_left - x_min ); for ( y = 0; y < dstSlot->bitmap.rows; y++ ) { FT_MEM_COPY( q, p, dstSlot->bitmap.width * 4 ); p += dstSlot->bitmap.pitch; q += pitch; } ft_glyphslot_set_bitmap( dstSlot, buf ); dstSlot->bitmap_top = y_max; dstSlot->bitmap_left = x_min; dstSlot->bitmap.width = width; dstSlot->bitmap.rows = rows; dstSlot->bitmap.pitch = (int)pitch; dstSlot->internal->flags |= FT_GLYPH_OWN_BITMAP; dstSlot->format = FT_GLYPH_FORMAT_BITMAP; } } if ( color_index == 0xFFFF ) { if ( face->have_foreground_color ) { b = face->foreground_color.blue; g = face->foreground_color.green; r = face->foreground_color.red; alpha = face->foreground_color.alpha; } else { if ( face->palette_data.palette_flags && ( face->palette_data.palette_flags[face->palette_index] & FT_PALETTE_FOR_DARK_BACKGROUND ) ) { /* white opaque */ b = 0xFF; g = 0xFF; r = 0xFF; alpha = 0xFF; } else { /* black opaque */ b = 0x00; g = 0x00; r = 0x00; alpha = 0xFF; } } } else { b = face->palette[color_index].blue; g = face->palette[color_index].green; r = face->palette[color_index].red; alpha = face->palette[color_index].alpha; } /* XXX Convert if srcSlot.bitmap is not grey? */ src = srcSlot->bitmap.buffer; dst = dstSlot->bitmap.buffer + dstSlot->bitmap.pitch * ( dstSlot->bitmap_top - srcSlot->bitmap_top ) + 4 * ( srcSlot->bitmap_left - dstSlot->bitmap_left ); for ( y = 0; y < srcSlot->bitmap.rows; y++ ) { for ( x = 0; x < srcSlot->bitmap.width; x++ ) { int aa = src[x]; int fa = alpha * aa / 255; int fb = b * fa / 255; int fg = g * fa / 255; int fr = r * fa / 255; int ba2 = 255 - fa; int bb = dst[4 * x + 0]; int bg = dst[4 * x + 1]; int br = dst[4 * x + 2]; int ba = dst[4 * x + 3]; dst[4 * x + 0] = (FT_Byte)( bb * ba2 / 255 + fb ); dst[4 * x + 1] = (FT_Byte)( bg * ba2 / 255 + fg ); dst[4 * x + 2] = (FT_Byte)( br * ba2 / 255 + fr ); dst[4 * x + 3] = (FT_Byte)( ba * ba2 / 255 + fa ); } src += srcSlot->bitmap.pitch; dst += dstSlot->bitmap.pitch; } return FT_Err_Ok; }