Example #1
0
static c_glyph* LoadGlyph(TTF_Font* font, Uint8 ch)
	{
	c_glyph* cached = &font->cache[ch];
	if (cached->pixmap.buffer)														// If already cached
		return cached;

	FT_Face face = font->face;
	if (FT_Load_Glyph(face, FT_Get_Char_Index(face, cpMap[ch]), FT_LOAD_NO_AUTOHINT))
		return 0;

	FT_GlyphSlot glyph = face->glyph;
	FT_Glyph_Metrics* metrics = &glyph->metrics;

	cached->minx = FT_FLOOR(metrics->horiBearingX);
	cached->maxx = FT_CEIL(metrics->horiBearingX+metrics->width);
	cached->maxy = FT_FLOOR(metrics->horiBearingY);
	cached->miny = cached->maxy-FT_CEIL(metrics->height);
	cached->yoffset = font->ascent-cached->maxy;

	if (FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL))								// Render the glyph
		return 0;

	FT_Bitmap* src = &glyph->bitmap;												// Copy information to cache
	FT_Bitmap* dst = &cached->pixmap;
	memcpy(dst, src, sizeof(*dst));
	if (dst->rows != 0)
		{
		int len = dst->pitch*dst->rows;
		dst->buffer = (unsigned char *)malloc(len);
		if (!dst->buffer)
			return 0;
		memcpy(dst->buffer, src->buffer, len);
		}
	return cached;
	}
Example #2
0
void TTF_SetCharSize(TTF_Font* font, int ptsize)
	{
	TTF_Flush_Cache(font);
	FT_Face face = font->face;
	if (FT_Set_Char_Size(face, 0, ptsize*64, 0, 0))									// Set the character size and use default DPI (72)
		E_Exit("TTF: Couldn't set font size");
	// Get the scalable font metrics for this font
	FT_Fixed scale = face->size->metrics.y_scale;
	font->ascent  = FT_CEIL(FT_MulFix(face->ascender, scale));
	font->descent = FT_CEIL(FT_MulFix(face->descender, scale));
	font->height  = font->ascent-font->descent;
	font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale));
	font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale));
	if (font->underline_height < 1)
		font->underline_height = 1;
	font->width = FT_FLOOR(FT_MulFix(face->max_advance_width, face->size->metrics.x_scale));
	}
Example #3
0
static FT_Error
Load_Glyph(TTF_Font * font, Uint16 ch, c_glyph * cached, int want)
{
    FT_Face face;
    FT_Error error;
    FT_GlyphSlot glyph;
    FT_Glyph_Metrics *metrics;
    FT_Outline *outline;

    if(!font || !font->face)
    {
        return FT_Err_Invalid_Handle;
    }

    face = font->face;

    /* Load the glyph */
    if(!cached->index)
    {
        cached->index = FT_Get_Char_Index(face, ch);
    }
    error = FT_Load_Glyph(face, cached->index, FT_LOAD_DEFAULT);
    if(error)
    {
        return error;
    }

    /* Get our glyph shortcuts */
    glyph = face->glyph;
    metrics = &glyph->metrics;
    outline = &glyph->outline;

    /* Get the glyph metrics if desired */
    if((want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS))
    {
        if(FT_IS_SCALABLE(face))
        {
            /* Get the bounding box */
            cached->minx = FT_FLOOR(metrics->horiBearingX);
            cached->maxx = cached->minx + FT_CEIL(metrics->width);
            cached->maxy = FT_FLOOR(metrics->horiBearingY);
            cached->miny = cached->maxy - FT_CEIL(metrics->height);
            cached->yoffset = font->ascent - cached->maxy;
            cached->advance = FT_CEIL(metrics->horiAdvance);
        }
        else
        {
            /* Get the bounding box for non-scalable format.
             * Again, freetype2 fills in many of the font metrics
             * with the value of 0, so some of the values we
             * need must be calculated differently with certain
             * assumptions about non-scalable formats.
             * */
            cached->minx = FT_FLOOR(metrics->horiBearingX);
            cached->maxx = cached->minx + FT_CEIL(metrics->horiAdvance);
            cached->maxy = FT_FLOOR(metrics->horiBearingY);
            cached->miny =
                cached->maxy -
                FT_CEIL(face->available_sizes[font->font_size_family].height);
            cached->yoffset = 0;
            cached->advance = FT_CEIL(metrics->horiAdvance);
        }

        /* Adjust for bold and italic text */
        if(font->style & TTF_STYLE_BOLD)
        {
            cached->maxx += font->glyph_overhang;
        }
        if(font->style & TTF_STYLE_ITALIC)
        {
            cached->maxx += (int) ceil(font->glyph_italics);
        }
        cached->stored |= CACHED_METRICS;
    }

    if(((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) ||
            ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)))
    {
        int mono = (want & CACHED_BITMAP);
        int i;
        FT_Bitmap *src;
        FT_Bitmap *dst;

        /* Handle the italic style */
        if(font->style & TTF_STYLE_ITALIC)
        {
            FT_Matrix shear;

            shear.xx = 1 << 16;
            shear.xy = (int) (font->glyph_italics * (1 << 16)) / font->height;
            shear.yx = 0;
            shear.yy = 1 << 16;

            FT_Outline_Transform(outline, &shear);
        }

        /* Render the glyph */
        if(mono)
        {
            error = FT_Render_Glyph(glyph, ft_render_mode_mono);
        }
        else
        {
            error = FT_Render_Glyph(glyph, ft_render_mode_normal);
        }
        if(error)
        {
            return error;
        }

        /* Copy over information to cache */
        src = &glyph->bitmap;
        if(mono)
        {
            dst = &cached->bitmap;
        }
        else
        {
            dst = &cached->pixmap;
        }
        memcpy(dst, src, sizeof(*dst));

        /* FT_Render_Glyph() and .fon fonts always generate a
         * two-color (black and white) glyphslot surface, even
         * when rendered in ft_render_mode_normal.  This is probably
         * a freetype2 bug because it is inconsistent with the
         * freetype2 documentation under FT_Render_Mode section.
         * */
        if(mono || !FT_IS_SCALABLE(face))
        {
            dst->pitch *= 8;
        }

        /* Adjust for bold and italic text */
        if(font->style & TTF_STYLE_BOLD)
        {
            int bump = font->glyph_overhang;

            dst->pitch += bump;
            dst->width += bump;
        }
        if(font->style & TTF_STYLE_ITALIC)
        {
            int bump = (int) ceil(font->glyph_italics);

            dst->pitch += bump;
            dst->width += bump;
        }

        if(dst->rows != 0)
        {
            dst->buffer = (unsigned char *) malloc(dst->pitch * dst->rows);
            if(!dst->buffer)
            {
                return FT_Err_Out_Of_Memory;
            }
            memset(dst->buffer, 0, dst->pitch * dst->rows);

            for(i = 0; i < src->rows; i++)
            {
                int soffset = i * src->pitch;
                int doffset = i * dst->pitch;

                if(mono)
                {
                    unsigned char *srcp = src->buffer + soffset;
                    unsigned char *dstp = dst->buffer + doffset;
                    int j;

                    for(j = 0; j < src->width; j += 8)
                    {
                        unsigned char ch = *srcp++;

                        *dstp++ = (ch & 0x80) >> 7;
                        ch <<= 1;
                        *dstp++ = (ch & 0x80) >> 7;
                        ch <<= 1;
                        *dstp++ = (ch & 0x80) >> 7;
                        ch <<= 1;
                        *dstp++ = (ch & 0x80) >> 7;
                        ch <<= 1;
                        *dstp++ = (ch & 0x80) >> 7;
                        ch <<= 1;
                        *dstp++ = (ch & 0x80) >> 7;
                        ch <<= 1;
                        *dstp++ = (ch & 0x80) >> 7;
                        ch <<= 1;
                        *dstp++ = (ch & 0x80) >> 7;
                    }
                }
                else if(!FT_IS_SCALABLE(face))
                {
                    /* This special case wouldn't
                     * be here if the FT_Render_Glyph()
                     * function wasn't buggy when it tried
                     * to render a .fon font with 256
                     * shades of gray.  Instead, it
                     * returns a black and white surface
                     * and we have to translate it back
                     * to a 256 gray shaded surface.
                     * */
                    unsigned char *srcp = src->buffer + soffset;
                    unsigned char *dstp = dst->buffer + doffset;
                    unsigned char ch;
                    int j, k;

                    for(j = 0; j < src->width; j += 8)
                    {
                        ch = *srcp++;
                        for(k = 0; k < 8; ++k)
                        {
                            if((ch & 0x80) >> 7)
                            {
                                *dstp++ = NUM_GRAYS - 1;
                            }
                            else
                            {
                                *dstp++ = 0x00;
                            }
                            ch <<= 1;
                        }
                    }
Example #4
0
TTF_Font *
TTF_OpenFontIndexRW(SDL_RWops * src, int freesrc, int ptsize, long index)
{
    TTF_Font *font;
    FT_Error error;
    FT_Face face;
    FT_Fixed scale;
    FT_Stream stream;
    int position;

    if(!TTF_initialized)
    {
        TTF_SetError("Library not initialized");
        return NULL;
    }

    /* Check to make sure we can seek in this stream */
    position = SDL_RWtell(src);
    if(position < 0)
    {
        TTF_SetError("Can't seek in stream");
        return NULL;
    }

    font = (TTF_Font *) malloc(sizeof *font);
    if(font == NULL)
    {
        TTF_SetError("Out of memory");
        return NULL;
    }
    memset(font, 0, sizeof(*font));

    font->src = src;
    font->freesrc = freesrc;

    stream = (FT_Stream) malloc(sizeof(*stream));
    if(stream == NULL)
    {
        TTF_SetError("Out of memory");
        TTF_CloseFont(font);
        return NULL;
    }
    memset(stream, 0, sizeof(*stream));

    /* 090303 Chase - Newer FT2 version sets this internally so we don't
    				have to. (Can't anyway, Don't have a definition for FT_Library)
    */
    // stream->memory = library->memory;

    stream->read = RWread;
    stream->descriptor.pointer = src;
    stream->pos = (unsigned long) position;
    SDL_RWseek(src, 0, SEEK_END);
    stream->size = (unsigned long) (SDL_RWtell(src) - position);
    SDL_RWseek(src, position, SEEK_SET);

    font->args.flags = FT_OPEN_STREAM;
    font->args.stream = stream;

    error = FT_Open_Face(library, &font->args, index, &font->face);
    if(error)
    {
        TTF_SetFTError("Couldn't load font file", error);
        TTF_CloseFont(font);
        return NULL;
    }
    face = font->face;

    /* Make sure that our font face is scalable (global metrics) */
    if(FT_IS_SCALABLE(face))
    {

        /* Set the character size and use default DPI (72) */
        error = FT_Set_Char_Size(font->face, 0, ptsize * 64, 0, 0);
        if(error)
        {
            TTF_SetFTError("Couldn't set font size", error);
            TTF_CloseFont(font);
            return NULL;
        }

        /* Get the scalable font metrics for this font */
        scale = face->size->metrics.y_scale;
        font->ascent = FT_CEIL(FT_MulFix(face->bbox.yMax, scale));
        font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale));
        font->height = font->ascent - font->descent + /* baseline */ 1;
        font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
        font->underline_offset =
            FT_FLOOR(FT_MulFix(face->underline_position, scale));
        font->underline_height =
            FT_FLOOR(FT_MulFix(face->underline_thickness, scale));

    }
    else
    {
        /* Non-scalable font case.  ptsize determines which family
         * or series of fonts to grab from the non-scalable format.
         * It is not the point size of the font.
         * */
        if(ptsize >= font->face->num_fixed_sizes)
            ptsize = font->face->num_fixed_sizes - 1;
        font->font_size_family = ptsize;
        error = FT_Set_Pixel_Sizes(face,
                                   face->available_sizes[ptsize].height,
                                   face->available_sizes[ptsize].width);
        /* With non-scalale fonts, Freetype2 likes to fill many of the
         * font metrics with the value of 0.  The size of the
         * non-scalable fonts must be determined differently
         * or sometimes cannot be determined.
         * */
        font->ascent = face->available_sizes[ptsize].height;
        font->descent = 0;
        font->height = face->available_sizes[ptsize].height;
        font->lineskip = FT_CEIL(font->ascent);
        font->underline_offset = FT_FLOOR(face->underline_position);
        font->underline_height = FT_FLOOR(face->underline_thickness);
    }

    if(font->underline_height < 1)
    {
        font->underline_height = 1;
    }

#ifdef DEBUG_FONTS
    printf("Font metrics:\n");
    printf("\tascent = %d, descent = %d\n", font->ascent, font->descent);
    printf("\theight = %d, lineskip = %d\n", font->height, font->lineskip);
    printf("\tunderline_offset = %d, underline_height = %d\n",
           font->underline_offset, font->underline_height);
#endif

    /* Set the default font style */
    font->style = TTF_STYLE_NORMAL;
    font->glyph_overhang = face->size->metrics.y_ppem / 10;
    /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
    font->glyph_italics = 0.207f;
    font->glyph_italics *= font->height;

    return font;
}
static FT_Error Load_Glyph( TTF_Font* font, Uint16 ch, c_glyph* cached, int want )
{
	FT_Face face;
	FT_Error error;
	FT_GlyphSlot glyph;
	FT_Glyph_Metrics* metrics;
	FT_Outline* outline;

	if ( !font || !font->face ) {
		return FT_Err_Invalid_Handle;
	}

	face = font->face;

	/* Load the glyph */
	if ( ! cached->index ) {
		cached->index = FT_Get_Char_Index( face, ch );
	}
	error = FT_Load_Glyph( face, cached->index, FT_LOAD_DEFAULT );
	if( error ) {
		return error;
	}

	/* Get our glyph shortcuts */
	glyph = face->glyph;
	metrics = &glyph->metrics;
	outline = &glyph->outline;

	/* Get the glyph metrics if desired */
	if ( (want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS) ) {
		if ( FT_IS_SCALABLE( face ) ) {
			/* Get the bounding box */
			cached->minx = FT_FLOOR(metrics->horiBearingX);
			cached->maxx = cached->minx + FT_CEIL(metrics->width);
			cached->maxy = FT_FLOOR(metrics->horiBearingY);
			cached->miny = cached->maxy - FT_CEIL(metrics->height);
			cached->yoffset = font->ascent - cached->maxy;
			cached->advance = FT_CEIL(metrics->horiAdvance);
		} else {
			/* Get the bounding box for non-scalable format.
			 * Again, freetype2 fills in many of the font metrics
			 * with the value of 0, so some of the values we
			 * need must be calculated differently with certain
			 * assumptions about non-scalable formats.
			 * */
			cached->minx = FT_FLOOR(metrics->horiBearingX);
			cached->maxx = cached->minx + FT_CEIL(metrics->horiAdvance);
			cached->maxy = FT_FLOOR(metrics->horiBearingY);
			cached->miny = cached->maxy - FT_CEIL(face->available_sizes[font->font_size_family].height);
			cached->yoffset = 0;
			cached->advance = FT_CEIL(metrics->horiAdvance);
		}
		
		/* Adjust for bold and italic text */
		if( font->style & TTF_STYLE_BOLD ) {
			cached->maxx += font->glyph_overhang;
		}
		if( font->style & TTF_STYLE_ITALIC ) {
			cached->maxx += (int)ceil(font->glyph_italics);
		}
		cached->stored |= CACHED_METRICS;
	}

	if ( ((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) ||
	     ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)) ) {
		int mono = (want & CACHED_BITMAP);
		int i;
		FT_Bitmap* src;
		FT_Bitmap* dst;

		/* Handle the italic style */
		if( font->style & TTF_STYLE_ITALIC ) {
			FT_Matrix shear;

			shear.xx = 1 << 16;
			shear.xy = (int) ( font->glyph_italics * ( 1 << 16 ) ) / font->height;
			shear.yx = 0;
			shear.yy = 1 << 16;

			FT_Outline_Transform( outline, &shear );
		}

		/* Render the glyph */
		if ( mono ) {
			error = FT_Render_Glyph( glyph, ft_render_mode_mono );
		} else {
			error = FT_Render_Glyph( glyph, ft_render_mode_normal );
		}
		if( error ) {
			return error;
		}

		/* Copy over information to cache */
		src = &glyph->bitmap;
		if ( mono ) {
			dst = &cached->bitmap;
		} else {
			dst = &cached->pixmap;
		}
		memcpy( dst, src, sizeof( *dst ) );

		/* FT_Render_Glyph() and .fon fonts always generate a
		 * two-color (black and white) glyphslot surface, even
		 * when rendered in ft_render_mode_normal. */
		/* FT_IS_SCALABLE() means that the font is in outline format,
		 * but does not imply that outline is rendered as 8-bit
		 * grayscale, because embedded bitmap/graymap is preferred
		 * (see FT_LOAD_DEFAULT section of FreeType2 API Reference).
		 * FT_Render_Glyph() canreturn two-color bitmap or 4/16/256-
		 * color graymap according to the format of embedded bitmap/
		 * graymap. */
		if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ) {
			dst->pitch *= 8;
		} else if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY2 ) {
			dst->pitch *= 4;
		} else if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY4 ) {
			dst->pitch *= 2;
		}

		/* Adjust for bold and italic text */
		if( font->style & TTF_STYLE_BOLD ) {
			int bump = font->glyph_overhang;
			dst->pitch += bump;
			dst->width += bump;
		}
		if( font->style & TTF_STYLE_ITALIC ) {
			int bump = (int)ceil(font->glyph_italics);
			dst->pitch += bump;
			dst->width += bump;
		}

		if (dst->rows != 0) {
			dst->buffer = (unsigned char *)malloc( dst->pitch * dst->rows );
			if( !dst->buffer ) {
				return FT_Err_Out_Of_Memory;
			}
			memset( dst->buffer, 0, dst->pitch * dst->rows );

			for( i = 0; i < src->rows; i++ ) {
				int soffset = i * src->pitch;
				int doffset = i * dst->pitch;
				if ( mono ) {
					unsigned char *srcp = src->buffer + soffset;
					unsigned char *dstp = dst->buffer + doffset;
					int j;
					if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ) {
						for ( j = 0; j < src->width; j += 8 ) {
							unsigned char ch = *srcp++;
							*dstp++ = (ch&0x80) >> 7;
							ch <<= 1;
							*dstp++ = (ch&0x80) >> 7;
							ch <<= 1;
							*dstp++ = (ch&0x80) >> 7;
							ch <<= 1;
							*dstp++ = (ch&0x80) >> 7;
							ch <<= 1;
							*dstp++ = (ch&0x80) >> 7;
							ch <<= 1;
							*dstp++ = (ch&0x80) >> 7;
							ch <<= 1;
							*dstp++ = (ch&0x80) >> 7;
							ch <<= 1;
							*dstp++ = (ch&0x80) >> 7;
						}
					}  else if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY2 ) {
						for ( j = 0; j < src->width; j += 4 ) {
							unsigned char ch = *srcp++;
							*dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0;
							ch <<= 2;
							*dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0;
							ch <<= 2;
							*dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0;
							ch <<= 2;
							*dstp++ = (((ch&0xA0) >> 6) >= 0x2) ? 1 : 0;
						}
					} else if ( glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY4 ) {
						for ( j = 0; j < src->width; j += 2 ) {
							unsigned char ch = *srcp++;
							*dstp++ = (((ch&0xF0) >> 4) >= 0x8) ? 1 : 0;
							ch <<= 4;
							*dstp++ = (((ch&0xF0) >> 4) >= 0x8) ? 1 : 0;
						}
					} else {
						for ( j = 0; j < src->width; j++ ) {
Example #6
0
static FT_Error Load_Glyph( TTF_Font* font, unsigned short ch, c_glyph* cached, int want)
{
        FT_Face face;
        FT_Error error;
        FT_GlyphSlot glyph;
        FT_Glyph_Metrics* metrics;
        FT_Outline* outline;
                              
        assert( font );
        assert( font->face );

        face = font->face;

        /* Load the glyph */
        if ( ! cached->index ) {
                cached->index = FT_Get_Char_Index( face, ch );
        }
        error = FT_Load_Glyph( face, cached->index, FT_LOAD_DEFAULT );
        if( error ) {
                return error;
        }
        /* Get our glyph shortcuts */
        glyph = face->glyph;
        metrics = &glyph->metrics;
        outline = &glyph->outline;

        /* Get the glyph metrics if desired */
        if ( (want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS) ) {
                /* Get the bounding box */
                cached->minx = FT_FLOOR(metrics->horiBearingX);
                cached->maxx = cached->minx + FT_CEIL(metrics->width);
                cached->maxy = FT_FLOOR(metrics->horiBearingY);
                cached->miny = cached->maxy - FT_CEIL(metrics->height);
                cached->yoffset = font->ascent - cached->maxy;
                cached->advance = FT_CEIL(metrics->horiAdvance);

                /* Adjust for bold and italic text */
                if( font->style & TTF_STYLE_BOLD ) {
                        cached->maxx += font->glyph_overhang;
                }
                if( font->style & TTF_STYLE_ITALIC ) {
                        cached->maxx += (int)ceil(font->glyph_italics);
                }
                cached->stored |= CACHED_METRICS;
        }

        if ( ((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) ||
             ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)) ) {
                int mono = (want & CACHED_BITMAP);
                int i;
                FT_Bitmap* src;
                FT_Bitmap* dst;

                /* Handle the italic style */
                if( font->style & TTF_STYLE_ITALIC ) {
                        FT_Matrix shear;

                        shear.xx = 1 << 16;
                        shear.xy = (int) ( font->glyph_italics * ( 1 << 16 ) )/ font->height;
                        shear.yx = 0;
                        shear.yy = 1 << 16;

                        FT_Outline_Transform( outline, &shear );
                }

                /* Render the glyph */
                if ( mono ) {
                        error = FT_Render_Glyph( glyph, ft_render_mode_mono );
                } else {
                        error = FT_Render_Glyph( glyph, ft_render_mode_normal );
                }
                if( error ) {
                        return error;
                }

                /* Copy over information to cache */
                src = &glyph->bitmap;
                if ( mono ) {
                        dst = &cached->bitmap;
                } else {
                        dst = &cached->pixmap;
                }
                memcpy( dst, src, sizeof( *dst ) );
                if ( mono ) {
                        dst->pitch *= 8;
                }

                /* Adjust for bold and italic text */
                if( font->style & TTF_STYLE_BOLD ) {
                        int bump = font->glyph_overhang;
                        dst->pitch += bump;
                        dst->width += bump;
                }
                if( font->style & TTF_STYLE_ITALIC ) {
                        int bump = (int)ceil(font->glyph_italics);
                        dst->pitch += bump;
                        dst->width += bump;
                }

                if (dst->rows != 0) {
                        dst->buffer = malloc( dst->pitch * dst->rows );
                        if( !dst->buffer ) {
                                return FT_Err_Out_Of_Memory;
                        }
                        memset( dst->buffer, 0, dst->pitch * dst->rows );

                        for( i = 0; i < src->rows; i++ ) {
                                int soffset = i * src->pitch;
                                int doffset = i * dst->pitch;
                                if ( mono ) {
                                        unsigned char *srcp = src->buffer + soffset;
                                        unsigned char *dstp = dst->buffer + doffset;
                                        int j;
                                        for ( j = 0; j < src->width; j += 8 ) {
                                                unsigned char ch = *srcp++;
                                                *dstp++ = (ch&0x80) >> 7;
                                                ch <<= 1;
                                                *dstp++ = (ch&0x80) >> 7;
                                                ch <<= 1;
                                                *dstp++ = (ch&0x80) >> 7;
                                                ch <<= 1;
                                                *dstp++ = (ch&0x80) >> 7;
                                                ch <<= 1;
                                                *dstp++ = (ch&0x80) >> 7;
                                                ch <<= 1;
                                                *dstp++ = (ch&0x80) >> 7;
                                                ch <<= 1;
                                                *dstp++ = (ch&0x80) >> 7;
                                                ch <<= 1;
                                                *dstp++ = (ch&0x80) >> 7;
                                        }
                                } else {
                                        memcpy(dst->buffer+doffset,
                                               src->buffer+soffset,src->pitch);
                                }
                        }
Example #7
0
static int LayoutLine( filter_t *p_filter,
                       paragraph_t *p_paragraph,
                       int i_start_offset, int i_end_offset,
                       line_desc_t **pp_line )
{
    if( p_paragraph->i_size <= 0 || p_paragraph->i_runs_count <= 0
     || i_start_offset >= i_end_offset
     || i_start_offset < 0 || i_start_offset >= p_paragraph->i_size
     || i_end_offset <= 0  || i_end_offset > p_paragraph->i_size )
    {
        msg_Err( p_filter,
                 "LayoutLine() invalid parameters. "
                 "Paragraph size: %d. Runs count: %d. "
                 "Start offset: %d. End offset: %d",
                 p_paragraph->i_size, p_paragraph->i_runs_count,
                 i_start_offset, i_end_offset );
        return VLC_EGENERIC;
    }

    line_desc_t *p_line = NewLine( i_end_offset - i_start_offset );

    if( !p_line )
        return VLC_ENOMEM;

    filter_sys_t *p_sys = p_filter->p_sys;
    int i_last_run = -1;
    run_desc_t *p_run = 0;
    text_style_t *p_style = 0;
    FT_Face p_face = 0;
    FT_Vector pen = { .x = 0, .y = 0 };
    int i_line_index = 0;

    int i_font_width = 0;
    int i_ul_offset = 0;
    int i_ul_thickness = 0;

#ifdef HAVE_FRIBIDI
    fribidi_reorder_line( 0, p_paragraph->p_types + i_start_offset,
                          i_end_offset - i_start_offset,
                          0, p_paragraph->paragraph_type,
                          p_paragraph->p_levels + i_start_offset,
                          0, p_paragraph->pi_reordered_indices + i_start_offset );
#endif

    for( int i = i_start_offset; i < i_end_offset; ++i, ++i_line_index )
    {
        int i_paragraph_index;
#ifdef HAVE_FRIBIDI
        i_paragraph_index = p_paragraph->pi_reordered_indices[ i ];
#else
        i_paragraph_index = i;
#endif

        line_character_t *p_ch = p_line->p_character + i_line_index;
        glyph_bitmaps_t *p_bitmaps =
                p_paragraph->p_glyph_bitmaps + i_paragraph_index;

        if( !p_bitmaps->p_glyph )
        {
            --i_line_index;
            continue;
        }

        if( i_last_run != p_paragraph->pi_run_ids[ i_paragraph_index ] )
        {
            i_last_run = p_paragraph->pi_run_ids[ i_paragraph_index ];
            p_run = p_paragraph->p_runs + i_last_run;
            p_style = p_run->p_style;
            p_face = p_run->p_face;

            i_font_width = p_style->i_style_flags & STYLE_HALFWIDTH ?
                           p_style->i_font_size / 2 : p_style->i_font_size;
        }

        FT_Vector pen_new = {
            .x = pen.x + p_paragraph->p_glyph_bitmaps[ i_paragraph_index ].i_x_offset,
            .y = pen.y + p_paragraph->p_glyph_bitmaps[ i_paragraph_index ].i_y_offset
        };
        FT_Vector pen_shadow = {
            .x = pen_new.x + p_sys->f_shadow_vector_x * ( i_font_width << 6 ),
            .y = pen_new.y + p_sys->f_shadow_vector_y * ( p_style->i_font_size << 6 )
        };

        if( p_bitmaps->p_shadow )
        {
            if( FT_Glyph_To_Bitmap( &p_bitmaps->p_shadow, FT_RENDER_MODE_NORMAL,
                                    &pen_shadow, 0 ) )
                p_bitmaps->p_shadow = 0;
            else
                FT_Glyph_Get_CBox( p_bitmaps->p_shadow, ft_glyph_bbox_pixels,
                                   &p_bitmaps->shadow_bbox );
        }
        if( p_bitmaps->p_glyph )
        {
            if( FT_Glyph_To_Bitmap( &p_bitmaps->p_glyph, FT_RENDER_MODE_NORMAL,
                                    &pen_new, 1 ) )
            {
                FT_Done_Glyph( p_bitmaps->p_glyph );
                if( p_bitmaps->p_outline )
                    FT_Done_Glyph( p_bitmaps->p_outline );
                if( p_bitmaps->p_shadow )
                    FT_Done_Glyph( p_bitmaps->p_shadow );
                --i_line_index;
                continue;
            }
            else
                FT_Glyph_Get_CBox( p_bitmaps->p_glyph, ft_glyph_bbox_pixels,
                                   &p_bitmaps->glyph_bbox );
        }
        if( p_bitmaps->p_outline )
        {
            if( FT_Glyph_To_Bitmap( &p_bitmaps->p_outline, FT_RENDER_MODE_NORMAL,
                                    &pen_new, 1 ) )
            {
                FT_Done_Glyph( p_bitmaps->p_outline );
                p_bitmaps->p_outline = 0;
            }
            else
                FT_Glyph_Get_CBox( p_bitmaps->p_outline, ft_glyph_bbox_pixels,
                                   &p_bitmaps->outline_bbox );
        }

        FixGlyph( p_bitmaps->p_glyph, &p_bitmaps->glyph_bbox,
                  p_bitmaps->i_x_advance, p_bitmaps->i_y_advance,
                  &pen_new );
        if( p_bitmaps->p_outline )
            FixGlyph( p_bitmaps->p_outline, &p_bitmaps->outline_bbox,
                      p_bitmaps->i_x_advance, p_bitmaps->i_y_advance,
                      &pen_new );
        if( p_bitmaps->p_shadow )
            FixGlyph( p_bitmaps->p_shadow, &p_bitmaps->shadow_bbox,
                      p_bitmaps->i_x_advance, p_bitmaps->i_y_advance,
                      &pen_shadow );

        int i_line_offset    = 0;
        int i_line_thickness = 0;
        text_style_t *p_glyph_style = p_paragraph->pp_styles[ i_paragraph_index ];
        if( p_glyph_style->i_style_flags & (STYLE_UNDERLINE | STYLE_STRIKEOUT) )
        {
            i_line_offset =
                abs( FT_FLOOR( FT_MulFix( p_face->underline_position,
                                          p_face->size->metrics.y_scale ) ) );

            i_line_thickness =
                abs( FT_CEIL( FT_MulFix( p_face->underline_thickness,
                                         p_face->size->metrics.y_scale ) ) );

            if( p_glyph_style->i_style_flags & STYLE_STRIKEOUT )
            {
                /* Move the baseline to make it strikethrough instead of
                 * underline. That means that strikethrough takes precedence
                 */
                i_line_offset -=
                    abs( FT_FLOOR( FT_MulFix( p_face->descender * 2,
                                              p_face->size->metrics.y_scale ) ) );
            }
            else if( i_line_thickness > 0 )
            {
                p_bitmaps->glyph_bbox.yMin =
                    __MIN( p_bitmaps->glyph_bbox.yMin,
                           - i_line_offset - i_line_thickness );

                /* The real underline thickness and position are
                 * updated once the whole line has been parsed */
                i_ul_offset = __MAX( i_ul_offset, i_line_offset );
                i_ul_thickness = __MAX( i_ul_thickness, i_line_thickness );
                i_line_thickness = -1;
            }
        }

        p_ch->p_glyph = ( FT_BitmapGlyph ) p_bitmaps->p_glyph;
        p_ch->p_outline = ( FT_BitmapGlyph ) p_bitmaps->p_outline;
        p_ch->p_shadow = ( FT_BitmapGlyph ) p_bitmaps->p_shadow;

        bool b_karaoke = p_paragraph->pi_karaoke_bar[ i_paragraph_index ] != 0;
        p_ch->i_color = b_karaoke ?
                        ( uint32_t ) p_glyph_style->i_karaoke_background_color
                      |              p_glyph_style->i_karaoke_background_alpha << 24
                      : ( uint32_t ) p_glyph_style->i_font_color
                      |              p_glyph_style->i_font_alpha << 24;

        p_ch->i_line_thickness = i_line_thickness;
        p_ch->i_line_offset = i_line_offset;

        BBoxEnlarge( &p_line->bbox, &p_bitmaps->glyph_bbox );
        if( p_bitmaps->p_outline )
            BBoxEnlarge( &p_line->bbox, &p_bitmaps->outline_bbox );
        if( p_bitmaps->p_shadow )
            BBoxEnlarge( &p_line->bbox, &p_bitmaps->shadow_bbox );

        pen.x += p_bitmaps->i_x_advance;
        pen.y += p_bitmaps->i_y_advance;
    }

    p_line->i_width = __MAX( 0, p_line->bbox.xMax - p_line->bbox.xMin );
    p_line->i_height = __MAX( 0, p_line->bbox.yMax - p_line->bbox.yMin );
    p_line->i_character_count = i_line_index;

    if( i_ul_thickness > 0 )
    {
        for( int i = 0; i < p_line->i_character_count; i++ )
        {
            line_character_t *ch = &p_line->p_character[i];
            if( ch->i_line_thickness < 0 )
            {
                ch->i_line_offset    = i_ul_offset;
                ch->i_line_thickness = i_ul_thickness;
            }
        }
    }

    *pp_line = p_line;
    return VLC_SUCCESS;
}

static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph,
                            int i_max_pixel_width, line_desc_t **pp_lines )
{
    if( p_paragraph->i_size <= 0 || p_paragraph->i_runs_count <= 0 )
    {
        msg_Err( p_filter, "LayoutParagraph() invalid parameters. "
                 "Paragraph size: %d. Runs count %d",
                 p_paragraph->i_size, p_paragraph->i_runs_count );
        return VLC_EGENERIC;
    }

    int i_line_start = 0;
    FT_Pos i_width = 0;
    FT_Pos i_max_width = i_max_pixel_width << 6;
    FT_Pos i_preferred_width = 0;
    FT_Pos i_total_width = 0;
    FT_Pos i_last_space_width = 0;
    int i_last_space = -1;
    line_desc_t *p_first_line = 0;
    line_desc_t **pp_line = &p_first_line;

    for( int i = 0; i < p_paragraph->i_size; ++i )
    {
#ifdef HAVE_FRIBIDI
        p_paragraph->pi_reordered_indices[ i ] = i;
#endif
        i_total_width += p_paragraph->p_glyph_bitmaps[ i ].i_x_advance;
    }

    int i_line_count = i_total_width / i_max_width + 1;
    i_preferred_width = i_total_width / i_line_count;

    for( int i = 0; i <= p_paragraph->i_size; ++i )
    {
        if( i == p_paragraph->i_size )
        {
            if( i_line_start < i )
                if( LayoutLine( p_filter, p_paragraph,
                                i_line_start, i, pp_line ) )
                    goto error;

            break;
        }

        if( p_paragraph->p_code_points[ i ] == ' '
#ifdef HAVE_FRIBIDI
            || p_paragraph->p_types[ i ] == FRIBIDI_TYPE_WS
#endif
          )
        {
            if( i_line_start == i )
            {
                /*
                 * Free orphaned white space glyphs not belonging to any lines.
                 * At this point p_shadow points to either p_glyph or p_outline,
                 * so we should not free it explicitly.
                 */
                if( p_paragraph->p_glyph_bitmaps[ i ].p_glyph )
                    FT_Done_Glyph( p_paragraph->p_glyph_bitmaps[ i ].p_glyph );
                if( p_paragraph->p_glyph_bitmaps[ i ].p_outline )
                    FT_Done_Glyph( p_paragraph->p_glyph_bitmaps[ i ].p_outline );

                i_line_start = i + 1;
                continue;
            }

            if( i_last_space == i - 1 )
            {
                p_paragraph->p_glyph_bitmaps[ i - 1 ].i_x_advance = 0;
                i_last_space = i;
                continue;
            }

            i_last_space = i;
            i_last_space_width = i_width;
        }

        i_width += p_paragraph->p_glyph_bitmaps[ i ].i_x_advance;

        if( i_last_space_width >= i_preferred_width
         || i_width >= i_max_width )
        {
            if( i_line_start == i )
            {
                msg_Err( p_filter,
                         "LayoutParagraph(): Width of single glyph exceeds maximum" );
                goto error;
            }

            int i_end_offset;
            if( i_last_space > i_line_start )
                i_end_offset = i_last_space;
            else
                i_end_offset = i;

            if( LayoutLine( p_filter, p_paragraph, i_line_start,
                            i_end_offset, pp_line ) )
                goto error;

            pp_line = &( *pp_line )->p_next;
            i_line_start = i_end_offset;
            i = i_line_start - 1;
            i_width = 0;
            i_last_space_width = 0;
        }
    }

    *pp_lines = p_first_line;
    return VLC_SUCCESS;

error:
    for( int i = i_line_start; i < p_paragraph->i_size; ++i )
    {
        if( p_paragraph->p_glyph_bitmaps[ i ].p_glyph )
            FT_Done_Glyph( p_paragraph->p_glyph_bitmaps[ i ].p_glyph );
        if( p_paragraph->p_glyph_bitmaps[ i ].p_outline )
            FT_Done_Glyph( p_paragraph->p_glyph_bitmaps[ i ].p_outline );
    }
    if( p_first_line )
        FreeLines( p_first_line );
    return VLC_EGENERIC;
}

int LayoutText( filter_t *p_filter, line_desc_t **pp_lines,
                FT_BBox *p_bbox, int *pi_max_face_height,

                uni_char_t *psz_text, text_style_t **pp_styles,
                uint32_t *pi_k_dates, int i_len )
{
    line_desc_t *p_first_line = 0;
    line_desc_t **pp_line = &p_first_line;
    paragraph_t *p_paragraph = 0;
    int i_paragraph_start = 0;
    int i_max_height = 0;

    for( int i = 0; i <= i_len; ++i )
    {
        if( i == i_len || psz_text[ i ] == '\n' )
        {
            if( i_paragraph_start == i )
            {
                i_paragraph_start = i + 1;
                continue;
            }

            p_paragraph = NewParagraph( p_filter, i - i_paragraph_start,
                                        psz_text + i_paragraph_start,
                                        pp_styles + i_paragraph_start,
                                        pi_k_dates ?
                                        pi_k_dates + i_paragraph_start : 0,
                                        20 );
            if( !p_paragraph )
            {
                if( p_first_line ) FreeLines( p_first_line );
                return VLC_ENOMEM;
            }

#ifdef HAVE_FRIBIDI
            if( AnalyzeParagraph( p_paragraph ) )
                goto error;
#endif

            if( ItemizeParagraph( p_filter, p_paragraph ) )
                goto error;

#if defined HAVE_HARFBUZZ
            if( ShapeParagraphHarfBuzz( p_filter, &p_paragraph ) )
                goto error;

            if( LoadGlyphs( p_filter, p_paragraph, true, false ) )
                goto error;

#elif defined HAVE_FRIBIDI
            if( ShapeParagraphFriBidi( p_filter, p_paragraph ) )
                goto error;
            if( LoadGlyphs( p_filter, p_paragraph, false, true ) )
                goto error;
            if( RemoveZeroWidthCharacters( p_paragraph ) )
                goto error;
            if( ZeroNsmAdvance( p_paragraph ) )
                goto error;
#else
            if( LoadGlyphs( p_filter, p_paragraph, false, true ) )
                goto error;
#endif

            /*
             * Set max line width to allow for outline and shadow glyphs,
             * and any extra width caused by visual reordering
             */
            int i_max_width = ( int ) p_filter->fmt_out.video.i_visible_width
                              - 2 * p_filter->p_sys->style.i_font_size;
            if( LayoutParagraph( p_filter, p_paragraph,
                                 i_max_width, pp_line ) )
                goto error;

            FreeParagraph( p_paragraph );
            p_paragraph = 0;

            for( ; *pp_line; pp_line = &( *pp_line )->p_next )
                i_max_height = __MAX( i_max_height, ( *pp_line )->i_height );

            i_paragraph_start = i + 1;
        }
    }

    int i_base_line = 0;
    FT_BBox bbox = {
        .xMin = INT_MAX,
        .yMin = INT_MAX,
        .xMax = INT_MIN,
        .yMax = INT_MIN
    };

    for( line_desc_t *p_line = p_first_line; p_line; p_line = p_line->p_next )
    {
        p_line->i_base_line = i_base_line;
        p_line->bbox.yMin -= i_base_line;
        p_line->bbox.yMax -= i_base_line;
        BBoxEnlarge( &bbox, &p_line->bbox );

        i_base_line += i_max_height;
    }

    *pp_lines = p_first_line;
    *p_bbox = bbox;
    *pi_max_face_height = i_max_height;
    return VLC_SUCCESS;

error:
    if( p_first_line ) FreeLines( p_first_line );
    if( p_paragraph ) FreeParagraph( p_paragraph );
    return VLC_EGENERIC;
}
Example #8
0
TTF_Font* TTF_OpenFontIndex( const char *file, int ptsize, long index )
{
        TTF_Font* font;
        FT_Error error;
        FT_Face face;
        FT_Fixed scale;

	extern int strict_font;

        font = (TTF_Font*) malloc(sizeof *font);
        if ( font == NULL ) {
                fprintf(stderr, "Out of memory\n" );
                return NULL;
        }
        memset( font, 0, sizeof( *font ) );

        /* Open the font and create ancillary data */
        error = FT_New_Face( library, file, 0, &font->face );

	if( error && !strict_font )
		error=FT_New_Memory_Face(library, (const FT_Byte*)DroidSans_ttf, DROIDSANS_SIZE, 0, &font->face );

        if( error ) {
                printf( "Couldn't load font file\n");
                free( font );
                return NULL;
        }

        if ( index != 0 ) {
                if ( font->face->num_faces > index ) {
                        FT_Done_Face( font->face );
                        error = FT_New_Face( library, file, index, &font->face
);
                        if( error ) {
                                printf( "Couldn't get font face\n");
                                free( font );
                                return NULL;
                        }
                } else {
                        fprintf(stderr, "No such font face\n");
                        free( font );
                        return NULL;
                }
        }
        face = font->face;

        /* Make sure that our font face is scalable (global metrics) */
        if ( ! FT_IS_SCALABLE(face) ) {
                fprintf(stderr,"Font face is not scalable\n");
                TTF_CloseFont( font );
                return NULL;
        }
       /* Set the character size and use default DPI (72) */
        error = FT_Set_Char_Size( font->face, 0, ptsize * 64, 0, 0 );
        if( error ) {
                fprintf(stderr, "Couldn't set font size\n");
                TTF_CloseFont( font );
                return NULL;
        }
        
        /* Get the scalable font metrics for this font */
        scale = face->size->metrics.y_scale;
        font->ascent  = FT_CEIL(FT_MulFix(face->bbox.yMax, scale));
        font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale));
        font->height  = font->ascent - font->descent + /* baseline */ 1;
        font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
        font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale));
        font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale));
        if ( font->underline_height < 1 ) {
                font->underline_height = 1;
        }
#ifdef DEBUG_FONTS
        printf("Font metrics:\n");
        printf("\tascent = %d, descent = %d\n",
                font->ascent, font->descent);
        printf("\theight = %d, lineskip = %d\n",
                font->height, font->lineskip);
        printf("\tunderline_offset = %d, underline_height = %d\n",
                font->underline_offset, font->underline_height);
#endif

        /* Set the default font style */
        font->style = TTF_STYLE_NORMAL;
        font->glyph_overhang = face->size->metrics.y_ppem / 10;
        /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */

        /*font->glyph_italics = 0.207f;
        font->glyph_italics *= font->height;*/

        return font;
}
Example #9
0
static constexpr inline FT_Long
FT_CEIL(FT_Long x)
{
  return FT_FLOOR(x + 63);
}
Example #10
0
PixelSize
Font::TextSize(const TCHAR *text) const
{
  assert(text != nullptr);
#ifndef _UNICODE
  assert(ValidateUTF8(text));
#endif

  const FT_Face face = this->face;
  const bool use_kerning = FT_HAS_KERNING(face);

  int x = 0, minx = 0, maxx = 0;
  unsigned prev_index = 0;

#ifndef ENABLE_OPENGL
  const ScopeLock protect(freetype_mutex);
#endif

  while (true) {
    const auto n = NextChar(text);
    if (n.first == 0)
      break;

    const unsigned ch = n.first;
    text = n.second;

    FT_UInt i = FT_Get_Char_Index(face, ch);
    if (i == 0)
      continue;

    FT_Error error = FT_Load_Glyph(face, i, load_flags);
    if (error)
      continue;

    const FT_GlyphSlot glyph = face->glyph;
    const FT_Glyph_Metrics &metrics = glyph->metrics;

    if (use_kerning) {
      if (prev_index != 0 && i != 0) {
        FT_Vector delta;
        FT_Get_Kerning(face, prev_index, i, ft_kerning_default,
                       &delta);
        x += delta.x >> 6;
      }

      prev_index = i;
    }

    const int glyph_minx = FT_FLOOR(metrics.horiBearingX);
    const int glyph_maxx = minx + FT_CEIL(metrics.width);
    const int glyph_advance = FT_CEIL(metrics.horiAdvance);

    int z = x + glyph_minx;
    if (z < minx)
      minx = z;

    z = x + std::max(glyph_maxx, glyph_advance);
    if (z > maxx)
      maxx = z;

    x += glyph_advance;
  }
Example #11
0
const Glyph& TTFFont::GetGlyph(ieWord chr) const
{
#if HAVE_ICONV
	if (!core->TLKEncoding.multibyte) {
		char* oldchar = (char*)&chr;
		ieWord unicodeChr = 0;
		char* newchar = (char*)&unicodeChr;
		size_t in = (core->TLKEncoding.widechar) ? 2 : 1, out = 2;

		// TODO: make this work on BE systems
		// TODO: maybe we want to work with non-unicode fonts?
		iconv_t cd = iconv_open("UTF-16LE", core->TLKEncoding.encoding.c_str());
	#if __FreeBSD__
		size_t ret = iconv(cd, (const char **)&oldchar, &in, &newchar, &out);
	#else
		size_t ret = iconv(cd, &oldchar, &in, &newchar, &out);
	#endif
		if (ret != GEM_OK) {
			Log(ERROR, "FONT", "iconv error: %d", errno);
		}
		iconv_close(cd);
		chr = unicodeChr;
	}
#endif
	// first check if the glyph already exists
	const Glyph& g = Font::GetGlyph(chr);
	if (g.pixels) {
		return g;
	}

	// attempt to generate glyph

	// TODO: fix the font styles!
	/*
	// currently gemrb has exclusive styles...
	// TODO: make styles ORable
	style = NORMAL;
	if ( face->style_flags & FT_STYLE_FLAG_ITALIC ) {
		style = ITALIC;
	}
	if ( face->style_flags & FT_STYLE_FLAG_BOLD ) {
		// bold overrides italic
		// TODO: allow bold and italic together
		style = BOLD;
	}

	glyph_overhang = face->size->metrics.y_ppem / 10;
	// x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle
	glyph_italics = 0.207f;
	glyph_italics *= height;
	*/
	FT_Error error = 0;
	FT_UInt index = FT_Get_Char_Index(face, chr);
	if (!index) {
		return AliasBlank(chr);
	}

	error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT | FT_LOAD_TARGET_MONO);
	if( error ) {
		LogFTError(error);
		return AliasBlank(chr);
	}

	FT_GlyphSlot glyph = face->glyph;
	FT_Glyph_Metrics* metrics = &glyph->metrics;
	/*
	//int maxx, yoffset;
	if ( FT_IS_SCALABLE( face ) ) {
		// Get the bounding box
		maxx = FT_FLOOR(metrics->horiBearingX) + FT_CEIL(metrics->width);
		yoffset = ascent - FT_FLOOR(metrics->horiBearingY);
	} else {
		// Get the bounding box for non-scalable format.
		// Again, freetype2 fills in many of the font metrics
		// with the value of 0, so some of the values we
		// need must be calculated differently with certain
		// assumptions about non-scalable formats.

		maxx = FT_FLOOR(metrics->horiBearingX) + FT_CEIL(metrics->horiAdvance);
		yoffset = 0;
	}

	// TODO: handle styles for fonts that dont do it themselves

	 FIXME: maxx is currently unused.
	 glyph spacing is non existant right now
	 font styles are non functional too
	 */

	FT_Bitmap* bitmap;
	uint8_t* pixels = NULL;

	/* Render the glyph */
	error = FT_Render_Glyph( glyph, ft_render_mode_normal );
	if( error ) {
		LogFTError(error);
		return AliasBlank(chr);
	}

	bitmap = &glyph->bitmap;

	Size sprSize(bitmap->width, bitmap->rows);

	/* Ensure the width of the pixmap is correct. On some cases,
	 * freetype may report a larger pixmap than possible.*/
	/*
	if (sprSize.w > maxx) {
		sprSize.w = maxx;
	}*/

	if (sprSize.IsEmpty()) {
		return AliasBlank(chr);
	}

	// we need 1px empty space on each side
	sprSize.w += 2;

	pixels = (uint8_t*)malloc(sprSize.w * sprSize.h);
	uint8_t* dest = pixels;
	uint8_t* src = bitmap->buffer;

	for( int row = 0; row < sprSize.h; row++ ) {
		// TODO: handle italics. we will need to offset the row by font->glyph_italics * row i think.

		// add 1px left padding
		memset(dest++, 0, 1);
		// -2 to account for padding
		memcpy(dest, src, sprSize.w - 2);
		dest += sprSize.w - 2;
		src += bitmap->pitch;
		// add 1px right padding
		memset(dest++, 0, 1);
	}
	// assert that we fill the buffer exactly
	assert((dest - pixels) == (sprSize.w * sprSize.h));

	// TODO: do an underline if requested

	Sprite2D* spr = core->GetVideoDriver()->CreateSprite8(sprSize.w, sprSize.h, pixels, NULL, true, 0);
	spr->YPos = FT_FLOOR(metrics->horiBearingY);
	// FIXME: casting away const
	const Glyph& ret = ((TTFFont*)this)->CreateGlyphForCharSprite(chr, spr);
	spr->release();
	return ret;
}
Example #12
0
TTF_Font* TTF_OpenFontIndexRW( FILE* src, int freesrc, int ptsize, long index )
{
	TTF_Font* font;
	FT_Error error;
	FT_Face face;
	FT_Fixed scale;
	FT_Stream stream;
	FT_CharMap found;
	int position, i;

	if ( ! TTF_initialized ) {
		TTF_SetError( "Library not initialized" );
		return NULL;
	}

	/* Check to make sure we can seek in this stream */
	position = ftell(src);
	if ( position < 0 ) {
		TTF_SetError( "Can't seek in stream" );
		return NULL;
	}

	font = (TTF_Font*) malloc(sizeof *font);
	if ( font == NULL ) {
		TTF_SetError( "Out of memory" );
		return NULL;
	}
	memset(font, 0, sizeof(*font));

	font->src = src;
	font->freesrc = freesrc;

	stream = (FT_Stream)malloc(sizeof(*stream));
	if ( stream == NULL ) {
		TTF_SetError( "Out of memory" );
		TTF_CloseFont( font );
		return NULL;
	}
	memset(stream, 0, sizeof(*stream));

	stream->read = ft_read;
	stream->descriptor.pointer = src;
	stream->pos = (unsigned long)position;
	fseek(src, 0, SEEK_END);
	stream->size = (unsigned long)(ftell(src) - position);
	fseek(src, position, SEEK_SET);

	font->args.flags = FT_OPEN_STREAM;
	font->args.stream = stream;

	error = FT_Open_Face( library, &font->args, index, &font->face );
	if( error ) {
		TTF_SetFTError( "Couldn't load font file", error );
		TTF_CloseFont( font );
		return NULL;
	}
	face = font->face;

	/* Set charmap for loaded font */
	found = 0;
	for (i = 0; i < face->num_charmaps; i++) {
		FT_CharMap charmap = face->charmaps[i];
/* Windows Unicode */
		if ((charmap->platform_id == 3 && charmap->encoding_id == 1) 
/* Windows Symbol */
		 || (charmap->platform_id == 3 && charmap->encoding_id == 0)
/* ISO Unicode */
		 || (charmap->platform_id == 2 && charmap->encoding_id == 1)
/* Apple Unicode */
		 || (charmap->platform_id == 0)) { 
			found = charmap;
			break;
		}
	}
	if ( found ) {
		/* If this fails, continue using the default charmap */
		FT_Set_Charmap(face, found);
	}

	/* Make sure that our font face is scalable (global metrics) */
	if ( FT_IS_SCALABLE(face) ) {

	  	/* Set the character size and use default DPI (72) */
	  	error = FT_Set_Char_Size( font->face, 0, ptsize * 64, 0, 0 );
			if( error ) {
	    	TTF_SetFTError( "Couldn't set font size", error );
	    	TTF_CloseFont( font );
	    	return NULL;
	  }

	  /* Get the scalable font metrics for this font */
	  scale = face->size->metrics.y_scale;
	  font->ascent  = FT_CEIL(FT_MulFix(face->ascender, scale));
	  font->descent = FT_CEIL(FT_MulFix(face->descender, scale));
	  font->height  = font->ascent - font->descent + /* baseline */ 1;
	  font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
	  font->underline_offset = FT_FLOOR(
			FT_MulFix(face->underline_position, scale));
	  font->underline_height = FT_FLOOR(
			FT_MulFix(face->underline_thickness, scale));

	} else {
		/* Non-scalable font case.  ptsize determines which family
		 * or series of fonts to grab from the non-scalable format.
		 * It is not the point size of the font.
		 * */
		if ( ptsize >= font->face->num_fixed_sizes )
			ptsize = font->face->num_fixed_sizes - 1;
		font->font_size_family = ptsize;
		error = FT_Set_Pixel_Sizes( face,
				face->available_sizes[ptsize].height,
				face->available_sizes[ptsize].width );
	  	/* With non-scalale fonts, Freetype2 likes to fill many of the
		 * font metrics with the value of 0.  The size of the
		 * non-scalable fonts must be determined differently
		 * or sometimes cannot be determined.
		 * */
	  	font->ascent = face->available_sizes[ptsize].height;
	  	font->descent = 0;
	  	font->height = face->available_sizes[ptsize].height;
	  	font->lineskip = FT_CEIL(font->ascent);
	  	font->underline_offset = FT_FLOOR(face->underline_position);
	  	font->underline_height = FT_FLOOR(face->underline_thickness);
	}

	if ( font->underline_height < 1 ) {
		font->underline_height = 1;
	}

#ifdef DEBUG_FONTS
	printf("Font metrics:\n");
	printf("\tascent = %d, descent = %d\n",
		font->ascent, font->descent);
	printf("\theight = %d, lineskip = %d\n",
		font->height, font->lineskip);
	printf("\tunderline_offset = %d, underline_height = %d\n",
		font->underline_offset, font->underline_height);
	printf("\tunderline_top_row = %d, strikethrough_top_row = %d\n",
		TTF_underline_top_row(font), TTF_strikethrough_top_row(font));
#endif

	/* Initialize the font face style */
	font->face_style = TTF_STYLE_NORMAL;
	if ( font->face->style_flags & FT_STYLE_FLAG_BOLD ) {
		font->face_style |= TTF_STYLE_BOLD;
	}
	if ( font->face->style_flags & FT_STYLE_FLAG_ITALIC ) {
		font->face_style |= TTF_STYLE_ITALIC;
	}
	/* Set the default font style */
	font->style = font->face_style;
	font->outline = 0;
	font->kerning = 1;
	font->glyph_overhang = face->size->metrics.y_ppem / 10;
	/* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
	font->glyph_italics = 0.207f;
	font->glyph_italics *= font->height;

	return font;
}