Esempio n. 1
0
File: Font.cpp Progetto: PKEuS/SFML
Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, float outlineThickness) const
{
    // The glyph to return
    Glyph glyph;

    // First, transform our ugly void* to a FT_Face
    FT_Face face = static_cast<FT_Face>(m_face);
    if (!face)
        return glyph;

    // Set the character size
    if (!setCurrentSize(characterSize))
        return glyph;

    // Load the glyph corresponding to the code point
    FT_Int32 flags = FT_LOAD_TARGET_NORMAL | FT_LOAD_FORCE_AUTOHINT;
    if (outlineThickness != 0)
        flags |= FT_LOAD_NO_BITMAP;
    if (FT_Load_Char(face, codePoint, flags) != 0)
        return glyph;

    // Retrieve the glyph
    FT_Glyph glyphDesc;
    if (FT_Get_Glyph(face->glyph, &glyphDesc) != 0)
        return glyph;

    // Apply bold and outline (there is no fallback for outline) if necessary -- first technique using outline (highest quality)
    FT_Pos weight = 1 << 6;
    bool outline = (glyphDesc->format == FT_GLYPH_FORMAT_OUTLINE);
    if (outline)
    {
        if (bold)
        {
            FT_OutlineGlyph outlineGlyph = (FT_OutlineGlyph)glyphDesc;
            FT_Outline_Embolden(&outlineGlyph->outline, weight);
        }

        if (outlineThickness != 0)
        {
            FT_Stroker stroker = static_cast<FT_Stroker>(m_stroker);

            FT_Stroker_Set(stroker, static_cast<FT_Fixed>(outlineThickness * static_cast<float>(1 << 6)), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
            FT_Glyph_Stroke(&glyphDesc, stroker, true);
        }
    }

    // Convert the glyph to a bitmap (i.e. rasterize it)
    FT_Glyph_To_Bitmap(&glyphDesc, FT_RENDER_MODE_NORMAL, 0, 1);
    FT_Bitmap& bitmap = reinterpret_cast<FT_BitmapGlyph>(glyphDesc)->bitmap;

    // Apply bold if necessary -- fallback technique using bitmap (lower quality)
    if (!outline)
    {
        if (bold)
            FT_Bitmap_Embolden(static_cast<FT_Library>(m_library), &bitmap, weight, weight);

        if (outlineThickness != 0)
            err() << "Failed to outline glyph (no fallback available)" << std::endl;
    }

    // Compute the glyph's advance offset
    glyph.advance = static_cast<float>(face->glyph->metrics.horiAdvance) / static_cast<float>(1 << 6);
    if (bold)
        glyph.advance += static_cast<float>(weight) / static_cast<float>(1 << 6);

    int width  = bitmap.width;
    int height = bitmap.rows;

    if ((width > 0) && (height > 0))
    {
        // Leave a small padding around characters, so that filtering doesn't
        // pollute them with pixels from neighbors
        const unsigned int padding = 1;

        width += 2 * padding;
        height += 2 * padding;

        // Get the glyphs page corresponding to the character size
        Page& page = m_pages[characterSize];

        // Find a good position for the new glyph into the texture
        glyph.textureRect = findGlyphRect(page, width, height);

        // Make sure the texture data is positioned in the center
        // of the allocated texture rectangle
        glyph.textureRect.left += padding;
        glyph.textureRect.top += padding;
        glyph.textureRect.width -= 2 * padding;
        glyph.textureRect.height -= 2 * padding;

        // Compute the glyph's bounding box
        glyph.bounds.left   =  static_cast<float>(face->glyph->metrics.horiBearingX) / static_cast<float>(1 << 6);
        glyph.bounds.top    = -static_cast<float>(face->glyph->metrics.horiBearingY) / static_cast<float>(1 << 6);
        glyph.bounds.width  =  static_cast<float>(face->glyph->metrics.width)        / static_cast<float>(1 << 6) + outlineThickness * 2;
        glyph.bounds.height =  static_cast<float>(face->glyph->metrics.height)       / static_cast<float>(1 << 6) + outlineThickness * 2;

        // Resize the pixel buffer to the new size and fill it with transparent white pixels
        m_pixelBuffer.resize(width * height * 4);

        Uint8* current = &m_pixelBuffer[0];
        Uint8* end = current + width * height * 4;

        while (current != end)
        {
            (*current++) = 255;
            (*current++) = 255;
            (*current++) = 255;
            (*current++) = 0;
        }

        // Extract the glyph's pixels from the bitmap
        const Uint8* pixels = bitmap.buffer;
        if (bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
        {
            // Pixels are 1 bit monochrome values
            for (unsigned int y = padding; y < height - padding; ++y)
            {
                for (unsigned int x = padding; x < width - padding; ++x)
                {
                    // The color channels remain white, just fill the alpha channel
                    std::size_t index = x + y * width;
                    m_pixelBuffer[index * 4 + 3] = ((pixels[(x - padding) / 8]) & (1 << (7 - ((x - padding) % 8)))) ? 255 : 0;
                }
                pixels += bitmap.pitch;
            }
        }
        else
        {
            // Pixels are 8 bits gray levels
            for (unsigned int y = padding; y < height - padding; ++y)
            {
                for (unsigned int x = padding; x < width - padding; ++x)
                {
                    // The color channels remain white, just fill the alpha channel
                    std::size_t index = x + y * width;
                    m_pixelBuffer[index * 4 + 3] = pixels[x - padding];
                }
                pixels += bitmap.pitch;
            }
        }

        // Write the pixels to the texture
        unsigned int x = glyph.textureRect.left - padding;
        unsigned int y = glyph.textureRect.top - padding;
        unsigned int w = glyph.textureRect.width + 2 * padding;
        unsigned int h = glyph.textureRect.height + 2 * padding;
        page.texture.update(&m_pixelBuffer[0], w, h, x, y);
    }

    // Delete the FT glyph
    FT_Done_Glyph(glyphDesc);

    // Done :)
    return glyph;
}
Esempio n. 2
0
void SubtitleRenderer::load_glyph(InternalChar ch) {
  VGfloat escapement[2]{};

  auto load_glyph_internal =
  [&](FT_Face ft_face, VGFont vg_font, bool border) {
    try {
      auto glyph_index = FT_Get_Char_Index(ft_face, ch.codepoint());
      ENFORCE(!FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_NO_HINTING));

      FT_Glyph glyph;
      ENFORCE(!FT_Get_Glyph(ft_face->glyph, &glyph));
      SCOPE_EXIT {FT_Done_Glyph(glyph);};

      if (border)
        ENFORCE(!FT_Glyph_StrokeBorder(&glyph, ft_stroker_, 0, 1));

      ENFORCE(!FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, NULL, 1));
      FT_BitmapGlyph bit_glyph = (FT_BitmapGlyph) glyph;
      FT_Bitmap& bitmap = bit_glyph->bitmap;

      VGImage image{};
      VGfloat glyph_origin[2]{};

      if (bitmap.width > 0 && bitmap.rows > 0) {
        constexpr VGfloat blur_stddev = 0.52;
        const int padding = static_cast<int>(3*blur_stddev + 0.5);
        const int image_width = bitmap.width + padding*2;
        const int image_height = bitmap.rows + padding*2;

        image = vgCreateImage(VG_A_8, image_width, image_height,
                              VG_IMAGE_QUALITY_NONANTIALIASED);
        assert(image);
        
        if (bitmap.pitch > 0) {
          vgImageSubData(image,
                         bitmap.buffer + bitmap.pitch*(bitmap.rows-1),
                         -bitmap.pitch,
                         VG_A_8,
                         padding,
                         padding,
                         bitmap.width,
                         bitmap.rows);
          assert(!vgGetError());
        } else {
          vgImageSubData(image,
                         bitmap.buffer,
                         bitmap.pitch,
                         VG_A_8,
                         padding,
                         padding,
                         bitmap.width,
                         bitmap.rows);
          assert(!vgGetError());
        }

        auto softened_image = vgCreateImage(VG_A_8,
                                            image_width,
                                            image_height,
                                            VG_IMAGE_QUALITY_NONANTIALIASED);
        assert(softened_image);

        // Even out hard and soft edges
        vgGaussianBlur(softened_image, image, blur_stddev, blur_stddev, VG_TILE_FILL);
        assert(!vgGetError());

        vgDestroyImage(image);
        assert(!vgGetError());

        image = softened_image;

        glyph_origin[0] = static_cast<VGfloat>(padding - bit_glyph->left);
        glyph_origin[1] = static_cast<VGfloat>(padding + bitmap.rows - bit_glyph->top - 1);
      }

      escapement[0] = static_cast<VGfloat>((ft_face->glyph->advance.x + 32) / 64);
      escapement[1] = 0;

      vgSetGlyphToImage(vg_font, ch.val, image, glyph_origin, escapement);
      assert(!vgGetError());

      if (image) {
        vgDestroyImage(image);
        assert(!vgGetError());
      }
    } catch(...) {
      escapement[0] = 0;
      escapement[1] = 0;
      vgSetGlyphToImage(vg_font, ch.val, VG_INVALID_HANDLE, escapement, escapement);
      assert(!vgGetError());
    }
  };

  if (!ch.italic()) {
    load_glyph_internal(ft_face_, vg_font_, false);
    glyphs_[ch].advance = escapement[0];
    load_glyph_internal(ft_face_, vg_font_border_, true);
  } else {
    load_glyph_internal(ft_face_italic_, vg_font_, false);
    glyphs_[ch].advance = escapement[0];
    load_glyph_internal(ft_face_italic_, vg_font_border_, true);
  }
}
Esempio n. 3
0
bool xFT2FontCharLoader::_loadResource(xWCharType& _char , xFT2FontChar*& pRes, int& ResSize,unsigned int arg)
{
	//if(FT_Load_Glyph( m_FT_Face, FT_Get_Char_Index( m_FT_Face, _char ), FT_LOAD_DEFAULT ))
	//	throw std::runtime_error("FT_Load_Glyph failed");

	FT_Int32 load_flags = FT_LOAD_RENDER|FT_LOAD_FORCE_AUTOHINT ;

	if(m_bAntilias) 
		load_flags |= ( FT_LOAD_TARGET_NORMAL| FT_LOAD_TARGET_LIGHT);
	else
		load_flags |= ( FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO );



	if(pRes == NULL)
	{
		pRes = new xFT2FontChar(m_pRenderer ,  this );
		if(pRes == NULL)
			return false;
	}
	//得到字模
	FT_UInt  glyph_index;
	/* retrieve glyph index from character code */
	glyph_index = FT_Get_Char_Index( m_FT_Face, _char );
	/* load glyph image into the slot (erase previous one) */
	int error = FT_Load_Glyph( m_FT_Face, glyph_index, FT_LOAD_DEFAULT );
    
	//if(m_bBold)
	//{
	//	int xStrenth = GetBoldenStrength(m_bBold , m_w);
	//	int yStrenth = GetBoldenStrength(m_bBold , m_h);
	//	FT2_GlyphSlot_Embolden(m_FT_Face->glyph , xStrenth , yStrenth );
	//}
	if(m_bAntilias)
	{
		error = FT_Render_Glyph( m_FT_Face->glyph, FT_RENDER_MODE_NORMAL );
	}
	else
	{
		error = FT_Render_Glyph( m_FT_Face->glyph, FT_RENDER_MODE_NORMAL );
	}


	FT_Glyph glyph;
	if(FT_Get_Glyph( m_FT_Face->glyph, &glyph ))
	{
		XEVOL_LOG(eXL_DEBUG_HIGH,"FT_Load_Glyph failed\n");
		return false;
	}
	FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;

	//取道位图数据
	FT_Bitmap& bitmap = bitmap_glyph->bitmap;

	//把位图数据拷贝自己定义的数据区里.这样旧可以画到需要的东西上面了。
	int width  =  bitmap.width;
	int height =  bitmap.rows;

	m_FT_Face->size->metrics.y_ppem;
	m_FT_Face->glyph->metrics.horiAdvance;
	pRes->m_adv_x = m_FT_Face->glyph->advance.x / 64.0f;
	pRes->m_adv_y = m_FT_Face->size->metrics.y_ppem; //m_FT_Face->glyph->metrics.horiBearingY / 64.0f;
	pRes->m_left = (float)bitmap_glyph->left;
	pRes->m_top  = (float)bitmap_glyph->top;

	int   tex_pitch =  0;
	unsigned char* tex_pixel = NULL;
    IBaseTexture* pTexture = NULL;
#ifndef _FONT_FULL_TEXTURE_
	if(pRes->m_pTexture != NULL)
	{
		pRes->m_pTexture->KillObject();
	}

	if(width == 0 || height == 0)
	{
		FT_Done_Glyph(glyph);
		return true;
	}

	if(m_pRenderer->isTextureSupport( PIXELFORMAT_ALPHA8 ) )
	{
		pRes->m_pTexture = m_pRenderer->createTexture(  width,height, PIXELFORMAT_ALPHA8   , false);//Alpha8);
	}																		 						
	else																	 						
	{																		 						
		pRes->m_pTexture = m_pRenderer->createTexture(  width,height, PIXELFORMAT_B8G8R8A8 , false);//RGBA);
	}
	
	if(pRes->m_pTexture == NULL)
		return width == 0 && height == 0;

    pTexture = pRes->m_pTexture;
	xTextureLockArea lockInfo;
	pTexture->lock(eLock_WriteDiscard , lockInfo);
	tex_pixel = (unsigned char*)lockInfo.m_pixels ;
	tex_pitch = lockInfo.m_picth ;

	pRes->m_tex_w = width ;
	pRes->m_tex_h = height;

#else
    pTexture = m_pTexture;
	pRes->m_tex_idx = m_idxManager.useIndex();
	pRes->m_tex_y   = pRes->m_tex_idx / m_nCharOfRow;
	int nFontWidth  = m_tex_w / m_nCharOfRow;
	int nFontHeight = m_tex_h / m_nCharOfRow;


	pRes->m_tex_y   = nFontHeight * pRes->m_tex_y;
    pRes->m_tex_x   = (pRes->m_tex_idx % m_nCharOfRow ) * nFontWidth;

	pRes->m_tex_w = width ;
	pRes->m_tex_h = height;

	xTextureLockArea lockInfo;
	pTexture->lock(eLock_WriteDiscard , lockInfo);
	tex_pixel = (unsigned char*)lockInfo.m_pixels ;
	tex_pitch = lockInfo.m_picth ;
	if(pTexture->format() == PIXELFORMAT_B8G8R8A8)
	{
		tex_pixel += lockInfo.m_picth * pRes->m_tex_y + pRes->m_tex_x * 4;
	}
	else
	{
		tex_pixel += lockInfo.m_picth * pRes->m_tex_y + pRes->m_tex_x;
	}
	
#endif



	float grayScale = 1.0f;

	if( m_bAntilias == false ) grayScale = 1.3f;
	//灰度图
	if(bitmap.pixel_mode == FT_PIXEL_MODE_GRAY)
	{
		for(int y=0; y  < height ; y++)
		{
			for(int x=0; x < width; x++)
			{
				int _y = y;
				unsigned char _vl =  0;
				if(x < bitmap.width && y < bitmap.rows) 
				{
					_vl =  (x>=bitmap.width || y>=bitmap.rows) ? 0 : bitmap.buffer[x + bitmap.width*y];
				}
				//if(_vl > 25 && _vl < 220) _vl = 220;

				unsigned int iVal = _vl; iVal = (int)(grayScale * iVal);
				if(iVal > 255) iVal = 255;
				if(pTexture->format() == PIXELFORMAT_B8G8R8A8)
				{

					tex_pixel[(4*x + _y * tex_pitch)+0] = 0xff;
					tex_pixel[(4*x + _y * tex_pitch)+1] = 0xff;
					tex_pixel[(4*x + _y * tex_pitch)+2] = 0xff;
					tex_pixel[(4*x + _y * tex_pitch)+3] = (unsigned char)iVal;
				}
				else
				{
					tex_pixel[(1*x + _y * tex_pitch)+0] = (unsigned char)iVal;
				}				
			}
		}
	}
	else if(bitmap.pixel_mode == FT_PIXEL_MODE_MONO) //单色图
	{
		for(int y=0; y  < height ; y++)
		{
			for(int x=0; x < width; x++)
			{
				int _y = y;
				unsigned char _vl =  0;
				if(x < bitmap.width && y < bitmap.rows) 
				{
					_vl =  ((bitmap.buffer[(y * bitmap.pitch) + x / 8] << (x % 8)) & 0x80) ? 0xFFFFFFFF : 0x00000000;
				}
				unsigned int iVal = _vl; iVal = (int)(grayScale * iVal);
				if(iVal > 255) iVal = 255;

				if(pTexture->format() == PIXELFORMAT_B8G8R8A8)
				{
					tex_pixel[(4*x + _y * tex_pitch)+0] = 0xff;
					tex_pixel[(4*x + _y * tex_pitch)+1] = 0xff;
					tex_pixel[(4*x + _y * tex_pitch)+2] = 0xff;
					tex_pixel[(4*x + _y * tex_pitch)+3] = (unsigned char)iVal;
				}
				else
				{
					tex_pixel[(1*x + _y * tex_pitch)+0] = (unsigned char)iVal;
				}

			}
		}
	}
	pTexture->unlock(lockInfo);
	pTexture->validate();
	FT_Done_Glyph(glyph);
	ResSize = 1;
	return true;
}
Esempio n. 4
0
void agg_text_renderer<T>::render(glyph_positions const& pos)
{
    glyphs_.clear();
    prepare_glyphs(pos);
    FT_Error  error;
    FT_Vector start;
    FT_Vector start_halo;
    int height = pixmap_.height();
    pixel_position const& base_point = pos.get_base_point();

    start.x =  static_cast<FT_Pos>(base_point.x * (1 << 6));
    start.y =  static_cast<FT_Pos>((height - base_point.y) * (1 << 6));
    start_halo = start;
    start.x += transform_.tx * 64;
    start.y += transform_.ty * 64;
    start_halo.x += halo_transform_.tx * 64;
    start_halo.y += halo_transform_.ty * 64;

    FT_Matrix halo_matrix;
    halo_matrix.xx = halo_transform_.sx  * 0x10000L;
    halo_matrix.xy = halo_transform_.shx * 0x10000L;
    halo_matrix.yy = halo_transform_.sy  * 0x10000L;
    halo_matrix.yx = halo_transform_.shy * 0x10000L;

    FT_Matrix matrix;
    matrix.xx = transform_.sx  * 0x10000L;
    matrix.xy = transform_.shx * 0x10000L;
    matrix.yy = transform_.sy  * 0x10000L;
    matrix.yx = transform_.shy * 0x10000L;

    // default formatting
    double halo_radius = 0;
    color black(0,0,0);
    unsigned fill = black.rgba();
    unsigned halo_fill = black.rgba();
    double text_opacity = 1.0;
    double halo_opacity = 1.0;

    for (auto const& glyph : glyphs_)
    {
        halo_fill = glyph.properties.halo_fill.rgba();
        halo_opacity = glyph.properties.halo_opacity;
        halo_radius = glyph.properties.halo_radius * scale_factor_;
        // make sure we've got reasonable values.
        if (halo_radius <= 0.0 || halo_radius > 1024.0) continue;
        FT_Glyph g;
        error = FT_Glyph_Copy(glyph.image, &g);
        if (!error)
        {
            FT_Glyph_Transform(g, &halo_matrix, &start_halo);
            if (rasterizer_ == HALO_RASTERIZER_FULL)
            {
                stroker_->init(halo_radius);
                FT_Glyph_Stroke(&g, stroker_->get(), 1);
                error = FT_Glyph_To_Bitmap(&g, FT_RENDER_MODE_NORMAL, 0, 1);
                if (!error)
                {
                    FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(g);
                    composite_bitmap(pixmap_,
                                     &bit->bitmap,
                                     halo_fill,
                                     bit->left,
                                     height - bit->top,
                                     halo_opacity,
                                     halo_comp_op_);
                }
            }
            else
            {
                error = FT_Glyph_To_Bitmap(&g, FT_RENDER_MODE_NORMAL, 0, 1);
                if (!error)
                {
                    FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(g);
                    render_halo(&bit->bitmap,
                                halo_fill,
                                bit->left,
                                height - bit->top,
                                halo_radius,
                                halo_opacity,
                                halo_comp_op_);
                }
            }
        }
        FT_Done_Glyph(g);
    }

    // render actual text
    for (auto & glyph : glyphs_)
    {
        fill = glyph.properties.fill.rgba();
        text_opacity = glyph.properties.text_opacity;
        FT_Glyph_Transform(glyph.image, &matrix, &start);
        error = FT_Glyph_To_Bitmap(&glyph.image ,FT_RENDER_MODE_NORMAL, 0, 1);
        if (!error)
        {
            FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(glyph.image);
            composite_bitmap(pixmap_,
                             &bit->bitmap,
                             fill,
                             bit->left,
                             height - bit->top,
                             text_opacity,
                             comp_op_);
        }
        FT_Done_Glyph(glyph.image);
    }

}
Esempio n. 5
0
YUV_error text_to_overlay_player(p_info_rec* p_info, overlay* ovly, char* text,
                          int max_width, int min_width,
                          int x_margin, int y_margin,
                          int center,
                          int tab_width,
                          int enable_align_right,
                          char* font, const int size,
                          const int aspect_ratio_num,
                          const int aspect_ratio_den)
{
    info_rec*   info;
    BYTE*   srcLine;
    BYTE*   dstLine;
    int     j;
    int     error;
    int     result;

    // initialise our data
    if (*p_info == NULL)
    {
        result = allocate_info(p_info);
        if (result < 0)
            return result;
    }
    info = *p_info;
    result = set_font(info, font, size, aspect_ratio_num, aspect_ratio_den);
    if (result < 0)
        return result;
    // render text using freetype2
    {
        #define MAX_GLYPHS 100
        FT_GlyphSlot    slot = info->face->glyph;  /* a small shortcut */
        FT_UInt     glyph_idx;
        FT_UInt     last_glyph;
        FT_Vector   delta;
        FT_Bool     use_kerning;
        int     pen_x, pen_y, n, margin;
        FT_Glyph    glyphs[MAX_GLYPHS];   /* glyph image    */
        FT_Vector   pos   [MAX_GLYPHS];   /* glyph position */
        FT_UInt     num_glyphs;
        FT_UInt     render_num_glyphs;
        FT_UInt     vis_last_glyph;
        int     vis_last;   // index of end of last "word"
        int     vis_width;  // width to vis_last
        int     x_offset = 0;
        int     align_right = 0;
        int     align_right_glyph = 0;
        int     align_right_shift;

        use_kerning = FT_HAS_KERNING(info->face);
        // compute initial pen position using font metrics
        n = info->face->bbox.yMax - info->face->bbox.yMin;//info->face->ascender - info->face->descender;
        pen_x = ((-info->face->bbox.xMin * size) + (n / 2)) / n;
        pen_y = ((info->face->bbox.yMax * size) + (n / 2)) / n;
        margin = pen_x;
        // convert each character to a glyph and set its position
        num_glyphs = 0;
        vis_last = -1;
        vis_last_glyph = 0;
        vis_width = 0;
        last_glyph = FT_Get_Char_Index(info->face, ' ');
        for (n = 0; n < (int)strlen(text); n++)
        {
            if (text[n] == '\n')
                break;
            if (num_glyphs >= MAX_GLYPHS)
                break;
            if (tab_width > 0 && text[n] == '\t')
            {
                pen_x += size - (pen_x % size);
            }
            // a '>>' sequence results in alignment of the following text to the right
            else if (enable_align_right && !align_right && text[n] == '>' && text[n + 1] == '>')
            {
                n += 1;
                align_right = 1;
                align_right_glyph = num_glyphs;
                continue;
            }
            else
            {
                glyph_idx = FT_Get_Char_Index(info->face, text[n]);
                if (use_kerning && last_glyph && glyph_idx)
                {
                    FT_Get_Kerning(info->face, last_glyph, glyph_idx,
                                   FT_KERNING_DEFAULT, &delta);
                    pen_x += delta.x / 64;
                }
                error = FT_Load_Glyph(info->face, glyph_idx, FT_LOAD_DEFAULT);
                if (error)
                    continue;  /* ignore errors */
                error = FT_Get_Glyph(info->face->glyph, &glyphs[num_glyphs]);
                if (error)
                    continue;  /* ignore errors */
                if (pen_y - slot->bitmap_top < 0)
                {
                    fprintf(stderr, "Character '%c' ascends too high\n", text[n]);
                    pen_y = slot->bitmap_top;
                }
                if (pen_y - slot->bitmap_top + slot->bitmap.rows > size)
                {
                    fprintf(stderr, "Character '%c' descends too low\n", text[n]);
                    exit(1);
                }
                pos[num_glyphs].x = pen_x;
                pos[num_glyphs].y = pen_y;

                pen_x += slot->advance.x / 64;
                last_glyph = glyph_idx;
                num_glyphs++;
            }

            if (pen_x + (margin * 2) + (x_margin * 2) > max_width)
                break;

            if (text[n] != ' ' &&
               (text[n+1] == ' ' || text[n+1] == '\0' || text[n+1] == '\n'))
            {
                vis_last_glyph = num_glyphs;
                vis_last = n;
                vis_width = pen_x;
            }
        }
        // truncate string to end of last word
        if (vis_last < 0)   // haven't found end of first word!
        {
            vis_last_glyph = num_glyphs;
            vis_last = n - 1;
            vis_width = pen_x;
        }
        if (vis_width + (margin * 2) + (x_margin * 2) > max_width)
        {
            vis_last_glyph--;
            vis_last--;
            vis_width -= slot->advance.x / 64;
        }
        render_num_glyphs = vis_last_glyph;
        result = vis_last + 1;
        // do right alignment if there is space
        if (align_right)
        {
            align_right_shift = max_width - (vis_width + (margin * 2) + (x_margin * 2));
            if (align_right_shift > 0)
            {
                for (n = align_right_glyph; n < (int)render_num_glyphs; n++)
                {
                    pos[n].x += align_right_shift;
                }
            }
        }
        // find start of next word
        while (text[result] == ' ' || text[result] == '\n')
            result++;
        // set overlay dimensions
        ovly->w = vis_width + (margin * 2) + (x_margin * 2);
        // set width >= min_width and center
        if (ovly->w < min_width && min_width <= max_width)
        {
            if (center)
            {
                x_offset = (min_width - ovly->w) / 2;
            }
            ovly->w = min_width;
        }
        ovly->h = size + 2 * y_margin;
//        fprintf(stderr, "Area of '%s' = (%d x %d)\n", text, ovly->w, ovly->h);
        ovly->ssx = -1;
        ovly->ssy = -1;
        // alloc memory
        ovly->buff = malloc(ovly->w * ovly->h * 2);
        if (ovly->buff == NULL)
            return YUV_no_memory;
        memset(ovly->buff, 0, ovly->w * ovly->h * 2);
        ovly->Cbuff = NULL;
        // render glyphs
        for (n = 0; n < (int)render_num_glyphs; n++)
        {
            error = FT_Glyph_To_Bitmap(&glyphs[n], FT_RENDER_MODE_NORMAL,
                                       0, 1);
            if (!error)
            {
                FT_BitmapGlyph  bit = (FT_BitmapGlyph)glyphs[n];
                srcLine = bit->bitmap.buffer;
                dstLine = ovly->buff + ((pos[n].y - bit->top) * ovly->w) +
                                        pos[n].x + bit->left +
                                        x_margin +
                                        y_margin * ovly->w +
                                        x_offset;
                // TODO: fix the problem with offsets
                if (dstLine < ovly->buff)
                    dstLine = ovly->buff;
                for (j = 0; j < bit->bitmap.rows; j++)
                {
                    memcpy(dstLine, srcLine, bit->bitmap.width);
                    srcLine += bit->bitmap.width;
                    dstLine += ovly->w;
                }
            }
        }
        // cleanup glyphs
        for (n = 0; n < (int)num_glyphs; n++)
        {
            FT_Done_Glyph(glyphs[n]);
        }
    }
    return result;  // length of string actually rendered
}
Esempio n. 6
0
  FT_Get_Glyph( FT_GlyphSlot  slot,
                FT_Glyph     *aglyph )
  {
    FT_Library  library;
    FT_Error    error;
    FT_Glyph    glyph;

    const FT_Glyph_Class*  clazz = 0;


    if ( !slot )
      return FT_Err_Invalid_Slot_Handle;

    library = slot->library;

    if ( !aglyph )
      return FT_Err_Invalid_Argument;

    /* if it is a bitmap, that's easy :-) */
    if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
      clazz = &ft_bitmap_glyph_class;

    /* it it is an outline too */
    else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
      clazz = &ft_outline_glyph_class;

    else
    {
      /* try to find a renderer that supports the glyph image format */
      FT_Renderer  render = FT_Lookup_Renderer( library, slot->format, 0 );


      if ( render )
        clazz = &render->glyph_class;
    }

    if ( !clazz )
    {
      error = FT_Err_Invalid_Glyph_Format;
      goto Exit;
    }

    /* create FT_Glyph object */
    error = ft_new_glyph( library, clazz, &glyph );
    if ( error )
      goto Exit;

    /* copy advance while converting it to 16.16 format */
    glyph->advance.x = slot->advance.x << 10;
    glyph->advance.y = slot->advance.y << 10;

    /* now import the image from the glyph slot */
    error = clazz->glyph_init( glyph, slot );

    /* if an error occurred, destroy the glyph */
    if ( error )
      FT_Done_Glyph( glyph );
    else
      *aglyph = glyph;

  Exit:
    return error;
  }
Esempio n. 7
0
static GF_Glyph *ft_load_glyph(GF_FontReader *dr, u32 glyph_name)
{
	GF_Glyph *glyph;
	u32 glyph_idx;
	FT_BBox bbox;
	FT_OutlineGlyph outline;
	ft_outliner outl;
	FT_Outline_Funcs ft_outl_funcs;

	FTBuilder *ftpriv = (FTBuilder *)dr->udta;
	if (!ftpriv->active_face || !glyph_name) return NULL;

	FT_Select_Charmap(ftpriv->active_face, FT_ENCODING_UNICODE);

	glyph_idx = FT_Get_Char_Index(ftpriv->active_face, glyph_name);
	/*missing glyph*/
	if (!glyph_idx) {
		GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[FreeType] Glyph not found for char %d in font %s (style %s)\n", glyph_name, ftpriv->active_face->family_name, ftpriv->active_face->style_name));
		return NULL;
	}

	/*work in design units*/
	FT_Load_Glyph(ftpriv->active_face, glyph_idx, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);

	FT_Get_Glyph(ftpriv->active_face->glyph, (FT_Glyph*)&outline);

#ifdef FT_GLYPH_FORMAT_OUTLINE
	/*oops not vectorial...*/
	if (outline->root.format != FT_GLYPH_FORMAT_OUTLINE) return NULL;
#endif


	GF_SAFEALLOC(glyph, GF_Glyph);
	GF_SAFEALLOC(glyph->path, GF_Path);

	/*setup outliner*/
	ft_outl_funcs.shift = 0;
	ft_outl_funcs.delta = 0;
	ft_outl_funcs.move_to = ft_move_to;
	ft_outl_funcs.line_to = ft_line_to;
	ft_outl_funcs.conic_to = ft_conic_to;
	ft_outl_funcs.cubic_to = ft_cubic_to;
	outl.path = glyph->path;
	outl.ftpriv = ftpriv;
	
	/*FreeType is marvelous and gives back the right advance on space char !!!*/
	FT_Outline_Decompose(&outline->outline, &ft_outl_funcs, &outl);

	FT_Glyph_Get_CBox((FT_Glyph) outline, ft_glyph_bbox_unscaled, &bbox);

	glyph->ID = glyph_name;
	glyph->utf_name = glyph_name;
	glyph->horiz_advance = ftpriv->active_face->glyph->metrics.horiAdvance;
	glyph->vert_advance = ftpriv->active_face->glyph->metrics.vertAdvance;
/*
	glyph->x = bbox.xMin;
	glyph->y = bbox.yMax;
*/
	glyph->width = ftpriv->active_face->glyph->metrics.width;
	glyph->height = ftpriv->active_face->glyph->metrics.height;
	FT_Done_Glyph((FT_Glyph) outline);
	return glyph;
}
Esempio n. 8
0
 ~glyph_t () { FT_Done_Glyph(image);}
Esempio n. 9
0
void EMSCRIPTEN_KEEPALIVE c_Glyph_done(long glyph) {
    FT_Done_Glyph((FT_Glyph)glyph);
}
Esempio n. 10
0
//-------------------------------------------------------------------------------------------------------
StringManager::BChar::~BChar()
{
    FT_Done_Glyph(m_pGlyph);
}
Esempio n. 11
0
Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) const
{
    // The glyph to return
    Glyph glyph;

    // First, transform our ugly void* to a FT_Face
    FT_Face face = static_cast<FT_Face>(m_face);
    if (!face)
        return glyph;

    // Set the character size
    if (!setCurrentSize(characterSize))
        return glyph;

    // Load the glyph corresponding to the code point
    if (FT_Load_Char(face, codePoint, FT_LOAD_TARGET_NORMAL | FT_LOAD_FORCE_AUTOHINT) != 0)
        return glyph;

    // Retrieve the glyph
    FT_Glyph glyphDesc;
    if (FT_Get_Glyph(face->glyph, &glyphDesc) != 0)
        return glyph;

    // Apply bold if necessary -- first technique using outline (highest quality)
    FT_Pos weight = 1 << 6;
    bool outline = (glyphDesc->format == FT_GLYPH_FORMAT_OUTLINE);
    if (bold && outline)
    {
        FT_OutlineGlyph outlineGlyph = (FT_OutlineGlyph)glyphDesc;
        FT_Outline_Embolden(&outlineGlyph->outline, weight);
    }

    // Convert the glyph to a bitmap (i.e. rasterize it)
    FT_Glyph_To_Bitmap(&glyphDesc, FT_RENDER_MODE_NORMAL, 0, 1);
    FT_Bitmap& bitmap = reinterpret_cast<FT_BitmapGlyph>(glyphDesc)->bitmap;

    // Apply bold if necessary -- fallback technique using bitmap (lower quality)
    if (bold && !outline)
    {
        FT_Bitmap_Embolden(static_cast<FT_Library>(m_library), &bitmap, weight, weight);
    }

    // Compute the glyph's advance offset
    glyph.advance = static_cast<float>(face->glyph->metrics.horiAdvance) / static_cast<float>(1 << 6);
    if (bold)
        glyph.advance += static_cast<float>(weight) / static_cast<float>(1 << 6);

    int width  = bitmap.width;
    int height = bitmap.rows;

    if ((width > 0) && (height > 0))
    {
        // Leave a small padding around characters, so that filtering doesn't
        // pollute them with pixels from neighbors
        const unsigned int padding = 1;

        // Get the glyphs page corresponding to the character size
        Page& page = m_pages[characterSize];

        // Find a good position for the new glyph into the texture
        glyph.textureRect = findGlyphRect(page, width + 2 * padding, height + 2 * padding);

        // Make sure the texture data is positioned in the center
        // of the allocated texture rectangle
        glyph.textureRect.left += padding;
        glyph.textureRect.top += padding;
        glyph.textureRect.width -= 2 * padding;
        glyph.textureRect.height -= 2 * padding;

        // Compute the glyph's bounding box
        glyph.bounds.left   = static_cast<float>(face->glyph->metrics.horiBearingX) / static_cast<float>(1 << 6);
        glyph.bounds.top    = -static_cast<float>(face->glyph->metrics.horiBearingY) / static_cast<float>(1 << 6);
        glyph.bounds.width  = static_cast<float>(face->glyph->metrics.width) / static_cast<float>(1 << 6);
        glyph.bounds.height = static_cast<float>(face->glyph->metrics.height) / static_cast<float>(1 << 6);

        // Extract the glyph's pixels from the bitmap
        m_pixelBuffer.resize(width * height * 4, 255);
        const Uint8* pixels = bitmap.buffer;
        if (bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
        {
            // Pixels are 1 bit monochrome values
            for (int y = 0; y < height; ++y)
            {
                for (int x = 0; x < width; ++x)
                {
                    // The color channels remain white, just fill the alpha channel
                    std::size_t index = (x + y * width) * 4 + 3;
                    m_pixelBuffer[index] = ((pixels[x / 8]) & (1 << (7 - (x % 8)))) ? 255 : 0;
                }
                pixels += bitmap.pitch;
            }
        }
        else
        {
            // Pixels are 8 bits gray levels
            for (int y = 0; y < height; ++y)
            {
                for (int x = 0; x < width; ++x)
                {
                    // The color channels remain white, just fill the alpha channel
                    std::size_t index = (x + y * width) * 4 + 3;
                    m_pixelBuffer[index] = pixels[x];
                }
                pixels += bitmap.pitch;
            }
        }

        // Write the pixels to the texture
        unsigned int x = glyph.textureRect.left;
        unsigned int y = glyph.textureRect.top;
        unsigned int w = glyph.textureRect.width;
        unsigned int h = glyph.textureRect.height;
        page.texture.update(&m_pixelBuffer[0], w, h, x, y);
    }

    // Delete the FT glyph
    FT_Done_Glyph(glyphDesc);

    // Force an OpenGL flush, so that the font's texture will appear updated
    // in all contexts immediately (solves problems in multi-threaded apps)
    glCheck(glFlush());

    // Done :)
    return glyph;
}
Esempio n. 12
0
////////////////////////////////////////////////////////////
/// Create a bitmap font from a font face and a characters set
////////////////////////////////////////////////////////////
FT_Error FontLoader::CreateBitmapFont(FT_Face FontFace, unsigned int CharSize, std::wstring Charset, Font& LoadedFont)
{
    // If no characters set has been provided, we take the default one (31 - 255 ASCII codes)
    if (Charset.empty())
        Charset = ourDefaultCharset;

    // Always add these special characters
    Charset += L" \n\v\t";

    // Clear the font's previous character map
    LoadedFont.myCharacters.clear();

    // Let's find how many characters to put in each row to make them fit into a squared texture
    GLint MaxSize;
    GLCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxSize));
    int NbChars = static_cast<int>(sqrt(static_cast<double>(Charset.length())) * 0.75);

    // Clamp the character size to make sure we won't create a texture too big
    if (NbChars * CharSize >= static_cast<unsigned int>(MaxSize))
        CharSize = MaxSize / NbChars;

    // Initialize the dimensions
    unsigned int Left      = 0;
    unsigned int Top       = 0;
    unsigned int TexWidth  = Image::GetValidTextureSize(CharSize * NbChars);
    unsigned int TexHeight = Image::GetValidTextureSize(CharSize * NbChars);
    std::vector<unsigned int> Tops(TexWidth, 0);

    // Create the bitmap font (all black for now -- we're going to fill it up)
    LoadedFont.myTexture.Create(TexWidth, TexHeight, Color(0, 0, 0, 0));

    // Setup the font size
    FT_Error Error = FT_Set_Pixel_Sizes(FontFace, CharSize, CharSize);
    if (Error)
        return Error;

    // Select the unicode character map
    Error = FT_Select_Charmap(FontFace, FT_ENCODING_UNICODE);
    if (Error)
        return Error;

    // Render the characters set to a bitmap
    std::map<wchar_t, IntRect> Coords;
    for (std::size_t i = 0; i < Charset.length(); ++i)
    {
        // Get the current character to generate
        wchar_t c = Charset[i];
        Font::Character& CurChar = LoadedFont.myCharacters[c];

        // Load the glyph corresponding to the current character
        Error = FT_Load_Char(FontFace, c, FT_LOAD_DEFAULT);
        if (Error)
            return Error;

        // Convert the glyph to a bitmap (ie. rasterize it)
        FT_Glyph Glyph;
        Error = FT_Get_Glyph(FontFace->glyph, &Glyph);
        if (Error)
            return Error;
        FT_Glyph_To_Bitmap(&Glyph, ft_render_mode_normal, 0, 1);
        FT_BitmapGlyph BitmapGlyph = (FT_BitmapGlyph)Glyph;
        FT_Bitmap& Bitmap = BitmapGlyph->bitmap;

        // Should we handle other pixel modes ?
        if (Bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
            return FT_Err_Cannot_Render_Glyph;

        // Make sure we don't go over the texture width
        if (Left + Bitmap.width + 1 >= TexWidth)
            Left = 0;

        // Compute the top coordinate
        Top = Tops[Left];
        for (int x = 0; x < Bitmap.width + 1; ++x)
            Top = std::max(Top, Tops[Left + x]);
        Top++;

        // Make sure we don't go over the texture height -- resize it if we need more space
        if (Top + Bitmap.rows + 1 >= TexHeight)
        {
            TexHeight *= 2;
            LoadedFont.myTexture.Resize(TexWidth, TexHeight, Color(0, 0, 0, 0));
        }

        // Store the character's position and size
        CurChar.Rect.Left   = BitmapGlyph->left;
        CurChar.Rect.Top    = -BitmapGlyph->top;
        CurChar.Rect.Right  = CurChar.Rect.Left + Bitmap.width;
        CurChar.Rect.Bottom = Bitmap.rows - BitmapGlyph->top;
        CurChar.Advance     = FontFace->glyph->advance.x / 64;

        // Texture size may change, so let the texture coordinates be calculated later
        Coords[c] = IntRect(Left + 1, Top + 1, Left + Bitmap.width + 1, Top + Bitmap.rows + 1);

        // Draw the glyph into our bitmap font
        const Uint8* Pixels = Bitmap.buffer;
        for (int y = 0; y < Bitmap.rows; ++y)
        {
            for (int x = 0; x < Bitmap.width; ++x)
            {
                LoadedFont.myTexture.SetPixel(x + Left + 1, y + Top + 1, Color(255, 255, 255, Pixels[x]));
            }
            Pixels += Bitmap.pitch;
        }

        // Update the rendering coordinates
        for (int x = 0; x < Bitmap.width + 1; ++x)
            Tops[Left + x] = Top + Bitmap.rows;
        Left += Bitmap.width + 1;

        // Delete the glyph
        FT_Done_Glyph(Glyph);
    }

    // Now that the texture has its final size, we can precompute texture coordinates
    for (std::size_t i = 0; i < Charset.size(); ++i)
    {
        wchar_t c = Charset[i];
        LoadedFont.myCharacters[c].Coord = LoadedFont.myTexture.GetTexCoords(Coords[c], false);
    }

    // Update the character size (it may have been changed by the function)
    LoadedFont.myCharSize = CharSize;

    return 0;
}
fz_pixmap *
fz_renderftstrokedglyph(fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_strokestate *state)
{
	FT_Face face = font->ftface;
	float expansion = fz_matrixexpansion(ctm);
	int linewidth = state->linewidth * expansion * 64 / 2;
	FT_Matrix m;
	FT_Vector v;
	FT_Error fterr;
	FT_Stroker stroker;
	FT_Glyph glyph;
	FT_BitmapGlyph bitmap;
	fz_pixmap *pix;
	int y;

	m.xx = trm.a * 64; /* should be 65536 */
	m.yx = trm.b * 64;
	m.xy = trm.c * 64;
	m.yy = trm.d * 64;
	v.x = trm.e * 64;
	v.y = trm.f * 64;

	fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */
	if (fterr)
	{
		fz_warn("FT_Set_Char_Size: %s", ft_errorstring(fterr));
		return nil;
	}

	FT_Set_Transform(face, &m, &v);

	fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
	if (fterr)
	{
		fz_warn("FT_Load_Glyph(gid %d): %s", gid, ft_errorstring(fterr));
		return nil;
	}

	fterr = FT_Stroker_New(fz_ftlib, &stroker);
	if (fterr)
	{
		fz_warn("FT_Stroker_New: %s", ft_errorstring(fterr));
		return nil;
	}

	FT_Stroker_Set(stroker, linewidth, state->linecap, state->linejoin, state->miterlimit * 65536);

	fterr = FT_Get_Glyph(face->glyph, &glyph);
	if (fterr)
	{
		fz_warn("FT_Get_Glyph: %s", ft_errorstring(fterr));
		FT_Stroker_Done(stroker);
		return nil;
	}

	fterr = FT_Glyph_Stroke(&glyph, stroker, 1);
	if (fterr)
	{
		fz_warn("FT_Glyph_Stroke: %s", ft_errorstring(fterr));
		FT_Done_Glyph(glyph);
		FT_Stroker_Done(stroker);
		return nil;
	}

	fterr = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
	if (fterr)
	{
		fz_warn("FT_Glyph_To_Bitmap: %s", ft_errorstring(fterr));
		FT_Done_Glyph(glyph);
		FT_Stroker_Done(stroker);
		return nil;
	}

	bitmap = (FT_BitmapGlyph)glyph;
	pix = fz_newpixmap(NULL,
		bitmap->left,
		bitmap->top - bitmap->bitmap.rows,
		bitmap->bitmap.width,
		bitmap->bitmap.rows);

	for (y = 0; y < pix->h; y++)
	{
		memcpy(pix->samples + y * pix->w,
			bitmap->bitmap.buffer + (pix->h - y - 1) * bitmap->bitmap.pitch,
			pix->w);
	}

	FT_Done_Glyph(glyph);
	FT_Stroker_Done(stroker);

	return pix;
}
Esempio n. 14
0
static say_glyph *say_font_load_glyph(say_font *font, say_font_page *page,
                                      uint32_t codepoint, uint8_t bold,
                                      size_t size) {
  uint32_t bold_codepoint = ((bold ? 1 : 0) << 31) | codepoint;

  say_glyph *glyph = malloc(sizeof(say_glyph));
  say_table_set(page->glyphs, bold_codepoint, glyph);

  glyph->offset   = 0;
  glyph->bounds   = say_make_rect(2, 0, 2, 2);
  glyph->sub_rect = say_make_rect(2, 0, 2, 2);

  if (!(font->face && say_font_set_size(font, size)))
    return glyph;

  if (FT_Load_Char(font->face, codepoint, FT_LOAD_TARGET_NORMAL) != 0)
    return glyph;

  FT_Glyph ft_glyph;
  if (FT_Get_Glyph(font->face->glyph, &ft_glyph) != 0)
    return glyph;

  FT_Pos weight = 1 << 6;
  uint8_t outline = ft_glyph->format == FT_GLYPH_FORMAT_OUTLINE;

  if (bold && outline) {
    FT_OutlineGlyph outline_glyph = (FT_OutlineGlyph)ft_glyph;
    FT_Outline_Embolden(&outline_glyph->outline, weight);
  }

  FT_Glyph_To_Bitmap(&ft_glyph, FT_RENDER_MODE_NORMAL, 0, 1);
  FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)ft_glyph;
  FT_Bitmap *bitmap = &bitmap_glyph->bitmap;

  if (bold && !outline) {
    FT_Bitmap_Embolden(font->library, bitmap, weight, weight);
  }

  glyph->offset = ft_glyph->advance.x >> 16;
  if (bold)
    glyph->offset += weight >> 6;

  int width  = bitmap->width;
  int height = bitmap->rows;

  if (width > 0 && height > 0) {
    static const int padding = 1;
    glyph->sub_rect = say_page_find_rect(page,
                                         width  + (2 * padding),
                                         height + (2 * padding));

    glyph->bounds.x = +bitmap_glyph->left - padding;
    glyph->bounds.y = -bitmap_glyph->top - padding;
    glyph->bounds.w = width   + (2 * padding);
    glyph->bounds.h = height  + (2 * padding);

    say_rect actual_rect = glyph->sub_rect;
    actual_rect.x += padding;
    actual_rect.y += padding;
    actual_rect.w -= 2 * padding;
    actual_rect.h -= 2 * padding;

    uint8_t *pixels = bitmap->buffer;

    if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO) {
      for (int y = actual_rect.y; y < actual_rect.y + actual_rect.h; y++) {
        for (int x = actual_rect.x; x < actual_rect.x + actual_rect.w; x++) {
          int pixel_x = x - actual_rect.x;
          uint8_t alpha = ((pixels[pixel_x / 8]) &
                           (1 << (7 - (pixel_x % 8)))) ? 255 : 0;
          say_image_set(page->image, x, y,
                        say_make_color(255, 255, 255, alpha));
        }

        pixels += bitmap->pitch;
      }
    }
    else {
      for (int y = actual_rect.y; y < actual_rect.y + actual_rect.h;
           y++) {
        for (int x = actual_rect.x; x < actual_rect.x + actual_rect.w;
             x++) {
          int pixel_x = x - actual_rect.x;
          say_image_set(page->image, x, y,
                        say_make_color(255, 255, 255, pixels[pixel_x]));
        }

        pixels += bitmap->pitch;
      }
    }
  }

  FT_Done_Glyph(ft_glyph);

  return glyph;
}
Esempio n. 15
0
  static FT_Error
  Render_Stroke( int  num_indices,
                 int  first_index )
  {
    int           start_x, start_y, step_y, x, y;
    int           i;
    FT_Size       size;
    FT_Face       face;
    FT_GlyphSlot  slot;

    FT_Fixed  radius;


    error = FTDemo_Get_Size( handle, &size );

    if ( error )
    {
      /* probably a non-existent bitmap font size */
      return error;
    }

    INIT_SIZE( size, start_x, start_y, step_y, x, y );
    face = size->face;
    slot = face->glyph;

    radius = status.radius * ( status.ptsize * status.res / 72 );

    FT_Stroker_Set( handle->stroker, radius,
                    FT_STROKER_LINECAP_ROUND,
                    FT_STROKER_LINEJOIN_ROUND,
                    0 );

    for ( i = first_index; i < num_indices; i++ )
    {
      int  gindex;


      if ( handle->encoding == FT_ENCODING_NONE )
        gindex = i;
      else
        gindex = FTDemo_Get_Index( handle, i );

      error = FT_Load_Glyph( face, gindex,
                             handle->load_flags | FT_LOAD_NO_BITMAP );

      if ( !error && slot->format == FT_GLYPH_FORMAT_OUTLINE )
      {
        FT_Glyph  glyph;


        error = FT_Get_Glyph( slot, &glyph );
        if ( error )
          goto Next;

        error = FT_Glyph_Stroke( &glyph, handle->stroker, 1 );
        if ( error )
        {
          FT_Done_Glyph( glyph );
          goto Next;
        }

        error = FTDemo_Draw_Glyph( handle, display, glyph, &x, &y );
        if ( !error )
          FT_Done_Glyph( glyph );

        if ( error )
          goto Next;
        else if ( X_TOO_LONG( x, size, display ) )
        {
          x  = start_x;
          y += step_y;

          if ( Y_TOO_LONG( y, size, display ) )
            break;
        }
      }
      else
    Next:
        status.Fail++;
    }

    return error;
  }
Esempio n. 16
0
    bool Font::CreateFromFile( const char* path, const uint32_t font_size, const bool smooth, const uint32_t start_char, const size_t num_chars )
    {
        if( path == NULL || font_size == 0 || num_chars == 0 || _num_glyphs > 0 ) return false;

        Mojo::Services::Filesystem* filesystem = MOJO_GET_SERVICE(Filesystem);
        Mojo::Filesystem::File* file = filesystem->Open(path, Mojo::Filesystem::FILE_READ);
        if( !file ) return false;

        size_t file_len = filesystem->Length(file);
        if( file_len == 0 ) {
            filesystem->Close(file);
            return false;
        }

        // todo: Use FT_Open_Face to read the file instead?

        uint8_t* buffer = new uint8_t[file_len]; {
            uint32_t num_bytes_read = 0;
            while( num_bytes_read < file_len ) {
                size_t read = filesystem->Read(file, file_len - num_bytes_read, (void*)&buffer[num_bytes_read]);
                mojo_assertf(read > 0, "Font::CreateFromFile\n -> Services/Filesystem error?\n");
                num_bytes_read += read;
            }
        }

        filesystem->Close(file);

        FT_Face ft_face;
        if( FT_New_Memory_Face(Mojo::GetFreeTypeLibrary(), (const FT_Byte*)buffer, file_len, 0, &ft_face) ) {
            delete[] buffer;
            return false;
        }

        FT_Set_Char_Size(ft_face, font_size * 64, font_size * 64, 72, 72);

        const float line_height = ft_face->size->metrics.height >> 6;

        // Load the glyphs
        Font::Glyph*    glyphs       = new Font::Glyph[num_chars];
        FT_Glyph*       ft_glyphs    = new FT_Glyph[num_chars];
        FT_BitmapGlyph* bm_glyphs    = (FT_BitmapGlyph*)ft_glyphs;

        float blo = 0.0f;
        uint32_t bm_max_width = 0, bm_max_height = 0;
        for( uint32_t i = 0; i < num_chars; ++i ) {
            FT_Load_Char(ft_face, start_char + i, FT_LOAD_DEFAULT);
            FT_Get_Glyph(ft_face->glyph, &ft_glyphs[i]);

            glyphs[i].x_advance = ft_face->glyph->advance.x >> 6;
            glyphs[i].y_advance = ft_face->glyph->advance.y >> 6;
            glyphs[i].x_bearing = (FT_HAS_VERTICAL(ft_face) ? ft_face->glyph->metrics.vertBearingX : ft_face->glyph->metrics.horiBearingX) >> 6;
            glyphs[i].y_bearing = (FT_HAS_VERTICAL(ft_face) ? ft_face->glyph->metrics.vertBearingY : ft_face->glyph->metrics.horiBearingY) >> 6;
            
            FT_Glyph_To_Bitmap(&ft_glyphs[i], smooth ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1);

            const FT_Bitmap bitmap = bm_glyphs[i]->bitmap;
            glyphs[i].width  = bitmap.width;
            glyphs[i].height = bitmap.rows;

            bm_max_width  = bm_max_width < bitmap.width ? bitmap.width : bm_max_width;
            bm_max_height = bm_max_height < bitmap.rows ? bitmap.rows : bm_max_height;

            const float gbl = -glyphs[i].y_bearing + glyphs[i].height;
            blo = (blo < gbl) ? gbl : blo;
        }

        // Determine the texture atlas size
        uint32_t atlas_width = 0, atlas_height = 0; {
            static const struct { uint32_t width, height, area; } atlas_sizes[] = {
                {  64,  64,  64 *  64 }, { 128, 128, 128 * 128 },
                { 256, 256, 256 * 256 }, { 512, 512, 512 * 512 }
            };

            uint32_t min_area = 0;
            for( uint32_t i = 0; i < num_chars; ++i ) min_area += uint32_t((glyphs[i].width + 2) * (bm_max_height + 2));

            for( uint32_t i = 0; i < 4; ++i ) {
                if( atlas_sizes[i].area < min_area ) continue;

                const uint32_t index = (i > 3) ? 3 : i;
                atlas_width  = atlas_sizes[index].width;
                atlas_height = atlas_sizes[index].height;
                break;
            }

            if( atlas_width == 0 || atlas_height == 0 ) {
                for( uint32_t i = 0; i < num_chars; ++i ) FT_Done_Glyph(ft_glyphs[i]);
                delete[] ft_glyphs;
                delete[] glyphs;

                FT_Done_Face(ft_face);
                delete[] buffer;

                return false;
            }
        }

        Mojo::TextureAtlas tex_atlas = Mojo::TextureAtlas(atlas_width, atlas_height, 32);
        Mojo::BookshelfTexturePacker tex_packer = Mojo::BookshelfTexturePacker(&tex_atlas);

        uint8_t* bm_buffer = new uint8_t[bm_max_width * bm_max_height * 4];
        for( uint32_t i = 0; i < num_chars; ++i ) {
            const FT_Bitmap bitmap = bm_glyphs[i]->bitmap;
            if( bitmap.width == 0 || bitmap.rows == 0 ) continue;

            memset((void*)bm_buffer, 255, bm_max_width * bm_max_height * 4);

            switch( bitmap.pixel_mode ) {
                default: {
                    mojo_assertf(0, "Font::CreateFromFile()\n -> Pixel mode not supported.\n"); 
                } break;

                case FT_PIXEL_MODE_MONO: {
                    const uint8_t* bm_pixels = (const uint8_t*)bitmap.buffer;
                    const uint32_t y_offset = 0;

                    for( uint32_t y = 0; y < bitmap.rows; ++y ) {
                        for( uint32_t x = 0; x < bitmap.width; ++x ) bm_buffer[(x + y * bitmap.width) * 4 + 3] = ((bm_pixels[x / 8]) & (1 << (7 - (x % 8)))) ? 0xFF : 0x00;
                        bm_pixels += bitmap.pitch;
                    }
                } break;
                
                case FT_PIXEL_MODE_GRAY: {
                    const uint8_t* bm_pixels = (const uint8_t*)bitmap.buffer;

                    for( uint32_t y = 0; y < bitmap.rows; ++y ) {
                        for( uint32_t x = 0; x < bitmap.width; ++x ) bm_buffer[(x + y * bitmap.width) * 4 + 3] = bm_pixels[x];
                        bm_pixels += bitmap.pitch;
                    }
                } break;
            }

            Mojo::Recti packed_rect;
            if( !tex_packer.Pack(bitmap.width, bitmap.rows, 1, bm_buffer, packed_rect) ) {
                Mojo::DebugPrintf(DBG_WARNING, "Font::CreateFromFile()\n -> unable to pack character '%c'\n", i + start_char);              
            }

            glyphs[i].tex_coords[0] = (float)packed_rect.x / atlas_width;
            glyphs[i].tex_coords[1] = (float)packed_rect.y / atlas_height;
            glyphs[i].tex_coords[2] = (float)(packed_rect.x + packed_rect.width) / atlas_width;
            glyphs[i].tex_coords[3] = (float)(packed_rect.y + packed_rect.height) / atlas_height;
        }
        delete[] bm_buffer;

        // Unload the glyphs
        for( uint32_t i = 0; i < num_chars; ++i ) FT_Done_Glyph(ft_glyphs[i]);
        delete[] ft_glyphs;

        FT_Done_Face(ft_face);
        delete[] buffer;

        // Update
        _font_atlas  = tex_atlas.Compile();
        _start_glyph = start_char;
        _num_glyphs  = num_chars;
        _glyphs      = glyphs;
        _base_line   = bm_max_height - blo;
        _line_height = line_height;

        return true;
    }
Esempio n. 17
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;
}
Esempio n. 18
0
// ----------------------------------------------- texture_font_load_glyphs ---
size_t
texture_font_load_glyphs( texture_font_t * self,
                          const wchar_t * charcodes )
{
    assert( self );
    assert( charcodes );

    size_t i, x, y, width, height, depth, w, h;
    FT_Library library;
    FT_Error error;
    FT_Face face;
    FT_Glyph ft_glyph;
    FT_GlyphSlot slot;
    FT_Bitmap ft_bitmap;

    FT_UInt glyph_index;
    texture_glyph_t *glyph;
    ivec4 region;
    size_t missed = 0;
    width  = self->atlas->width;
    height = self->atlas->height;
    depth  = self->atlas->depth;

    if( !texture_font_load_face( &library, self->filename, self->size, &face ) )
    {
        return wcslen(charcodes);
    }

    /* Load each glyph */
    for( i=0; i<wcslen(charcodes); ++i )
    {
        glyph_index = FT_Get_Char_Index( face, charcodes[i] );
        // WARNING: We use texture-atlas depth to guess if user wants
        //          LCD subpixel rendering
        FT_Int32 flags = 0;

        if( self->outline_type > 0 )
        {
            flags |= FT_LOAD_NO_BITMAP;
        }
        else
        {
            flags |= FT_LOAD_RENDER;
        }

        if( !self->hinting )
        {
            flags |= FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT;
        }
        else
        {
            flags |= FT_LOAD_FORCE_AUTOHINT;
        }


        if( depth == 3 )
        {
            FT_Library_SetLcdFilter( library, FT_LCD_FILTER_LIGHT );
            flags |= FT_LOAD_TARGET_LCD;
            if( self->filtering )
            {
                FT_Library_SetLcdFilterWeights( library, self->lcd_weights );
            }
        }
        error = FT_Load_Glyph( face, glyph_index, flags );

        if( error )
        {
            fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n",
                     __LINE__, FT_Errors[error].code, FT_Errors[error].message );
            FT_Done_FreeType( library );
            return wcslen(charcodes)-i;
        }

        int ft_bitmap_width = 0;
        int ft_bitmap_rows = 0;
        int ft_bitmap_pitch = 0;
        int ft_glyph_top = 0;
        int ft_glyph_left = 0;
        if( self->outline_type == 0 )
        {
            slot            = face->glyph;
            ft_bitmap       = slot->bitmap;
            ft_bitmap_width = slot->bitmap.width;
            ft_bitmap_rows  = slot->bitmap.rows;
            ft_bitmap_pitch = slot->bitmap.pitch;
            ft_glyph_top    = slot->bitmap_top;
            ft_glyph_left   = slot->bitmap_left;
        }
        else
        {
            FT_Stroker stroker;
            error = FT_Stroker_New( library, &stroker );
            if( error )
            {
                fprintf(stderr, "FT_Error (0x%02x) : %s\n",
                        FT_Errors[error].code, FT_Errors[error].message);
                return 0;
            }
            FT_Stroker_Set( stroker,
                            (int)(self->outline_thickness *64),
                            FT_STROKER_LINECAP_ROUND,
                            FT_STROKER_LINEJOIN_ROUND,
                            0);
            error = FT_Get_Glyph( face->glyph, &ft_glyph);
            if( error )
            {
                fprintf(stderr, "FT_Error (0x%02x) : %s\n",
                        FT_Errors[error].code, FT_Errors[error].message);
                return 0;
            }

            if( self->outline_type == 1 )
            {
                error = FT_Glyph_Stroke( &ft_glyph, stroker, 1 );
            }
            else if ( self->outline_type == 2 )
            {
                error = FT_Glyph_StrokeBorder( &ft_glyph, stroker, 0, 1 );
            }
            else if ( self->outline_type == 3 )
            {
                error = FT_Glyph_StrokeBorder( &ft_glyph, stroker, 1, 1 );
            }
            if( error )
            {
                fprintf(stderr, "FT_Error (0x%02x) : %s\n",
                        FT_Errors[error].code, FT_Errors[error].message);
                return 0;
            }
          
            if( depth == 1)
            {
                error = FT_Glyph_To_Bitmap( &ft_glyph, FT_RENDER_MODE_NORMAL, 0, 1);
                if( error )
                {
                    fprintf(stderr, "FT_Error (0x%02x) : %s\n",
                            FT_Errors[error].code, FT_Errors[error].message);
                    return 0;
                }
            }
            else
            {
                error = FT_Glyph_To_Bitmap( &ft_glyph, FT_RENDER_MODE_LCD, 0, 1);
                if( error )
                {
                    fprintf(stderr, "FT_Error (0x%02x) : %s\n",
                            FT_Errors[error].code, FT_Errors[error].message);
                    return 0;
                }
            }
            FT_BitmapGlyph ft_bitmap_glyph = (FT_BitmapGlyph) ft_glyph;
            ft_bitmap       = ft_bitmap_glyph->bitmap;
            ft_bitmap_width = ft_bitmap.width;
            ft_bitmap_rows  = ft_bitmap.rows;
            ft_bitmap_pitch = ft_bitmap.pitch;
            ft_glyph_top    = ft_bitmap_glyph->top;
            ft_glyph_left   = ft_bitmap_glyph->left;
            FT_Stroker_Done(stroker);
        }


        // We want each glyph to be separated by at least one black pixel
        // (for example for shader used in demo-subpixel.c)
        w = ft_bitmap_width/depth + 1;
        h = ft_bitmap_rows + 1;
        region = texture_atlas_get_region( self->atlas, w, h );
        if ( region.x < 0 )
        {
            missed++;
            fprintf( stderr, "Texture atlas is full (line %d)\n",  __LINE__ );
            continue;
        }
        w = w - 1;
        h = h - 1;
        x = region.x;
        y = region.y;
        texture_atlas_set_region( self->atlas, x, y, w, h,
                                  ft_bitmap.buffer, ft_bitmap.pitch );

        glyph = texture_glyph_new( );
        glyph->charcode = charcodes[i];
        glyph->width    = w;
        glyph->height   = h;
        glyph->outline_type = self->outline_type;
        glyph->outline_thickness = self->outline_thickness;
        glyph->offset_x = ft_glyph_left;
        glyph->offset_y = ft_glyph_top;
        glyph->s0       = x/(float)width;
        glyph->t0       = y/(float)height;
        glyph->s1       = (x + glyph->width)/(float)width;
        glyph->t1       = (y + glyph->height)/(float)height;

        // Discard hinting to get advance
        FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING);
        slot = face->glyph;
        glyph->advance_x = slot->advance.x/64.0;
        glyph->advance_y = slot->advance.y/64.0;

        vector_push_back( self->glyphs, &glyph );

        if( self->outline_type > 0 )
        {
            FT_Done_Glyph( ft_glyph );
        }
    }
    FT_Done_Face( face );
    FT_Done_FreeType( library );
    texture_atlas_upload( self->atlas );
    texture_font_generate_kerning( self );
    return missed;
}
Esempio n. 19
0
// Load a character glyph
Font::Glyph Font::LoadGlyph( char ch, unsigned int size )
{
    Glyph glyph;

    // Ensure we can even retrieve the glyph
    if ( !_fontFace || !SetCurrentSize( size ) )
    {
        return glyph;
    }

    // Attempt to load the font's glyph for the given character
    if ( 0 != FT_Load_Char( _myFontFace, ch, FT_LOAD_TARGET_NORMAL | FT_LOAD_FORCE_AUTOHINT ) )
    {
        return glyph;
    }

    // Get the glyph's description
    FT_Glyph ftGlyph;
    if ( 0 != FT_Get_Glyph( _myFontFace->glyph, &ftGlyph ) )
    {
        return glyph;
    }

    // Rasterize the glyph
    FT_Glyph_To_Bitmap( &ftGlyph, FT_RENDER_MODE_NORMAL, 0, 1 );
    FT_Bitmap& bitmap = reinterpret_cast<FT_BitmapGlyph>( ftGlyph )->bitmap;

    // Get the glyph's advance
    glyph.Advance = static_cast<float>( _myFontFace->glyph->metrics.horiAdvance ) * KerningScale;

    int width = bitmap.width;
    int height = bitmap.rows;

    if ( ( width > 0 ) && ( height > 0 ) )
    {
        // Get the glyph's page
        GlyphPage& page = _pages[ size ];

        // Leave a small padding around characters, so that filtering doesn't
        // pollute them with pixels from neighbors
        const unsigned int padding = 1;
        
        // Find a good position for the new glyph into the texture
        UintRect emptyArea = FindGlyphRect( page, width + 2 * padding, height + 2 * padding );;

        // Ensure the texture data is in the center of the texture rectangle
        emptyArea.X += padding;
        emptyArea.Y += padding;
        emptyArea.Width -= 2 * padding;
        emptyArea.Height -= 2 * padding;
        glyph.TextureBounds = emptyArea;

        // Set the glyph's bounding box
        glyph.Bounds.X      =  ( _myFontFace->glyph->metrics.horiBearingX ) * KerningScale;
        glyph.Bounds.Y      = -( _myFontFace->glyph->metrics.horiBearingY ) * KerningScale;
        glyph.Bounds.Width  =  ( _myFontFace->glyph->metrics.width        ) * KerningScale;
        glyph.Bounds.Height =  ( _myFontFace->glyph->metrics.height       ) * KerningScale;


        // Extract the glyph's pixels from the bitmap
        _pixelBuffer.resize( width * height * 4, 255 );
        const unsigned char* pixels = bitmap.buffer;
        if ( bitmap.pixel_mode == FT_PIXEL_MODE_MONO )
        {
            // Pixels are 1 bit monochrome values
            for ( int y = 0; y < height; ++y )
            {
                for ( int x = 0; x < width; ++x )
                {
                    // The color channels remain white, just fill the alpha channel
                    std::size_t index = ( x + y * width ) * 4 + 3;
                    _pixelBuffer[ index ] = ( ( pixels[ x / 8 ] ) & ( 1 << ( 7 - ( x % 8 ) ) ) ) ? 255 : 0;
                }
                pixels += bitmap.pitch;
            }
        }
        else
        {
            // Pixels are 8 bits gray levels
            for ( int y = 0; y < height; ++y )
            {
                for ( int x = 0; x < width; ++x )
                {
                    // The color channels remain white, just fill the alpha channel
                    std::size_t index = ( x + y * width ) * 4 + 3;
                    _pixelBuffer[ index ] = pixels[ x ];
                }
                pixels += bitmap.pitch;
            }
        }

        // Write the pixels to the texture
        page.Texture->UpdateArea( emptyArea.X, emptyArea.Y, emptyArea.Width, emptyArea.Height, &_pixelBuffer[ 0 ] );
    }

    // Cleanup
    FT_Done_Glyph( ftGlyph );

    return glyph;
}
Esempio n. 20
0
/** 转换FT_GlyphSlot类型数据为LCUI_FontBMP */
static int Convert_FTGlyph( LCUI_FontBMP *bmp, FT_GlyphSlot slot, int mode )
{
	int error;
	size_t size;
	FT_BitmapGlyph bitmap_glyph;
	FT_Glyph  glyph;

	/* 从字形槽中提取一个字形图像
	 * 请注意,创建的FT_Glyph对象必须与FT_Done_Glyph成对使用 */
	error = FT_Get_Glyph( slot, &glyph );
	if(error) {
		return -1;
	}
	/*---------------------- 打印字体信息 --------------------------
	printf(" width= %ld,  met->height= %ld\n"
	"horiBearingX = %ld, horiBearingY = %ld, horiAdvance = %ld\n"
	"vertBearingX = %ld, vertBearingY = %ld,  vertAdvance = %ld\n",
	slot->metrics.width>>6, slot->metrics.height>>6,
	slot->metrics.horiBearingX>>6, slot->metrics.horiBearingY>>6,
	slot->metrics.horiAdvance>>6, slot->metrics.vertBearingX>>6,
	slot->metrics.vertBearingY>>6, slot->metrics.vertAdvance>>6 );
	------------------------------------------------------------*/
	if ( glyph->format != FT_GLYPH_FORMAT_BITMAP ) {
		error = FT_Glyph_To_Bitmap(&glyph, mode, 0 ,1);
		if(error) {
			return -1;
		}
	}
	bitmap_glyph = (FT_BitmapGlyph)glyph;
	/*
	 * FT_Glyph_Metrics结构体中保存字形度量,通过face->glyph->metrics结
	 * 构访问,可得到字形的宽、高、左边界距、上边界距、水平跨距等等。
	 * 注意:因为不是所有的字体都包含垂直度量,当FT_HAS_VERTICAL为假时,
	 * vertBearingX,vertBearingY和vertAdvance的值是不可靠的,目前暂不考虑
	 * 此情况的处理。
	 * */
	bmp->top = bitmap_glyph->top;
	bmp->left = slot->metrics.horiBearingX>>6;
	bmp->rows = bitmap_glyph->bitmap.rows;
	bmp->width = bitmap_glyph->bitmap.width;
	bmp->advance.x = slot->metrics.horiAdvance>>6;	/* 水平跨距 */
	bmp->advance.y = slot->metrics.vertAdvance>>6;	/* 垂直跨距 */
	/* 分配内存,用于保存字体位图 */
	size = bmp->rows * bmp->width * sizeof(uchar_t);
	bmp->buffer = (uchar_t*)malloc( size );
	if( !bmp->buffer ) {
		FT_Done_Glyph(glyph);
		return -1;
	}

	switch( bitmap_glyph->bitmap.pixel_mode ) {
	    /* 8位灰度位图,直接拷贝 */
	    case FT_PIXEL_MODE_GRAY:
		memcpy( bmp->buffer, bitmap_glyph->bitmap.buffer, size );
		break;
	    /* 单色点阵图,需要转换 */
	    case FT_PIXEL_MODE_MONO: {
		FT_Bitmap bitmap;
		FT_Library lib;
		FT_Int x, y;
		uchar_t *t, *s;

		lib = FontLIB_GetLibrary();
		FT_Bitmap_New( &bitmap );
		/* 转换位图bitmap_glyph->bitmap至bitmap,1个像素占1个字节 */
		FT_Bitmap_Convert( lib, &bitmap_glyph->bitmap, &bitmap, 1);
		s = bitmap.buffer;
		t = bmp->buffer;
		for( y=0; y<bmp->rows; ++y ) {
			for( x=0; x<bmp->width; ++x ) {
				*t = *s?255:0;
				++t,++s;
			}
		}
		FT_Bitmap_Done( lib, &bitmap );
		break;
	    }
	    /* 其它像素模式的位图,暂时先直接填充255,等需要时再完善 */
	    default:
		memset( bmp->buffer, 255, size );
		break;
	}
	FT_Done_Glyph(glyph);
	return size;
}
int main(int argc, char *argv[]) {
	int                i, j, err, size, first=' ', last='~',
	                   bitmapOffset = 0, x, y, byte;
	char              *fontName, c, *ptr;
	FT_Library         library;
	FT_Face            face;
	FT_Glyph           glyph;
	FT_Bitmap         *bitmap;
	FT_BitmapGlyphRec *g;
	GFXglyph          *table;
	uint8_t            bit;

	// Parse command line.  Valid syntaxes are:
	//   fontconvert [filename] [size]
	//   fontconvert [filename] [size] [last char]
	//   fontconvert [filename] [size] [first char] [last char]
	// Unless overridden, default first and last chars are
	// ' ' (space) and '~', respectively

	if(argc < 3) {
		fprintf(stderr, "Usage: %s fontfile size [first] [last]\n",
		  argv[0]);
		return 1;
	}

	size = atoi(argv[2]);

	if(argc == 4) {
		last  = atoi(argv[3]);
	} else if(argc == 5) {
		first = atoi(argv[3]);
		last  = atoi(argv[4]);
	}

	if(last < first) {
		i     = first;
		first = last;
		last  = i;
	}

	ptr = strrchr(argv[1], '/'); // Find last slash in filename
	if(ptr) ptr++;         // First character of filename (path stripped)
	else    ptr = argv[1]; // No path; font in local dir.

	// Allocate space for font name and glyph table
	if((!(fontName = malloc(strlen(ptr) + 20))) ||
	   (!(table = (GFXglyph *)malloc((last - first + 1) *
	    sizeof(GFXglyph))))) {
		fprintf(stderr, "Malloc error\n");
		return 1;
	}

	// Derive font table names from filename.  Period (filename
	// extension) is truncated and replaced with the font size & bits.
	strcpy(fontName, ptr);
	ptr = strrchr(fontName, '.'); // Find last period (file ext)
	if(!ptr) ptr = &fontName[strlen(fontName)]; // If none, append
	// Insert font size and 7/8 bit.  fontName was alloc'd w/extra
	// space to allow this, we're not sprintfing into Forbidden Zone.
	sprintf(ptr, "%dpt%db", size, (last > 127) ? 8 : 7);
	// Space and punctuation chars in name replaced w/ underscores.  
	for(i=0; (c=fontName[i]); i++) {
		if(isspace(c) || ispunct(c)) fontName[i] = '_';
	}

	// Init FreeType lib, load font
	if((err = FT_Init_FreeType(&library))) {
		fprintf(stderr, "FreeType init error: %d", err);
		return err;
	}
	if((err = FT_New_Face(library, argv[1], 0, &face))) {
		fprintf(stderr, "Font load error: %d", err);
		FT_Done_FreeType(library);
		return err;
	}

	// << 6 because '26dot6' fixed-point format
	FT_Set_Char_Size(face, size << 6, 0, DPI, 0);

	// Currently all symbols from 'first' to 'last' are processed.
	// Fonts may contain WAY more glyphs than that, but this code
	// will need to handle encoding stuff to deal with extracting
	// the right symbols, and that's not done yet.
	// fprintf(stderr, "%ld glyphs\n", face->num_glyphs);

	printf("package Giza.Bitmap_Fonts.%s is\n\n", fontName);

	printf("   %sBitmaps : aliased constant Font_Bitmap := (\n  ",
               fontName);

	// Process glyphs and output huge bitmap data array
	for(i=first, j=0; i<=last; i++, j++) {
		// MONO renderer provides clean image with perfect crop
		// (no wasted pixels) via bitmap struct.
		if((err = FT_Load_Char(face, i, FT_LOAD_TARGET_MONO))) {
			fprintf(stderr, "Error %d loading char '%c'\n",
			  err, i);
			continue;
		}

		if((err = FT_Render_Glyph(face->glyph,
		  FT_RENDER_MODE_MONO))) {
			fprintf(stderr, "Error %d rendering char '%c'\n",
			  err, i);
			continue;
		}

		if((err = FT_Get_Glyph(face->glyph, &glyph))) {
			fprintf(stderr, "Error %d getting glyph '%c'\n",
			  err, i);
			continue;
		}

		bitmap = &face->glyph->bitmap;
		g      = (FT_BitmapGlyphRec *)glyph;

		// Minimal font and per-glyph information is stored to
		// reduce flash space requirements.  Glyph bitmaps are
		// fully bit-packed; no per-scanline pad, though end of
		// each character may be padded to next byte boundary
		// when needed.  16-bit offset means 64K max for bitmaps,
		// code currently doesn't check for overflow.  (Doesn't
		// check that size & offsets are within bounds either for
		// that matter...please convert fonts responsibly.)
		table[j].bitmapOffset = bitmapOffset;
		table[j].width        = bitmap->width;
		table[j].height       = bitmap->rows;
		table[j].xAdvance     = face->glyph->advance.x >> 6;
		table[j].xOffset      = g->left;
		table[j].yOffset      = 1 - g->top;

		for(y=0; y < bitmap->rows; y++) {
			for(x=0;x < bitmap->width; x++) {
				byte = x / 8;
				bit  = 0x80 >> (x & 7);
				enbit(bitmap->buffer[
				  y * bitmap->pitch + byte] & bit);
			}
		}

		// Pad end of char bitmap to next byte boundary if needed
		int n = (bitmap->width * bitmap->rows) & 7;
		if(n) { // Pixel count not an even multiple of 8?
			n = 8 - n; // # bits to next multiple
			while(n--) enbit(0);
		}
		bitmapOffset += (bitmap->width * bitmap->rows + 7) / 8;

		FT_Done_Glyph(glyph);
	}

	printf(");\n\n"); // End bitmap array

	// Output glyph attributes table (one per character)
	printf("   %sGlyphs : aliased constant Glyph_Array := (\n",
               fontName);
	for(i=first, j=0; i<=last; i++, j++) {
		printf("  (%d, %d, %d, %d, %d, %d)",
		  table[j].bitmapOffset,
		  table[j].width,
		  table[j].height,
		  table[j].xAdvance,
		  table[j].xOffset,
		  table[j].yOffset);
		if(i < last) {
			printf(",   -- 0x%02X", i);
			if((i >= ' ') && (i <= '~')) {
				printf(" '%c'", i);
			}
			putchar('\n');
		}
	}
	printf("); -- 0x%02X", last);
	if((last >= ' ') && (last <= '~')) printf(" '%c'", last);
	printf("\n\n");

	// Output font structure
	printf("   Font : Bitmap_Font :=\n");
        printf("     (%sBitmaps'Access,\n", fontName);
        printf("      %sGlyphs'Access,\n", fontName);
	printf("      16#%02X#,\n", first);
	printf("      16#%02X#,\n", last);
	printf("      %ld);\n", face->size->metrics.height >> 6);

	printf("end Giza.Bitmap_Fonts.%s;\n", fontName);

	FT_Done_FreeType(library);

	return 0;
}
Esempio n. 22
0
Shape2D FontEngine_Freetype::load_glyph_outline(int c, int &out_advance_x)
{
	out_advance_x = 0;

	FT_UInt glyph_index;

	glyph_index = FT_Get_Char_Index( face, FT_ULong(c) );

	FT_Error error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
	if ( error )
	{
		throw Exception("freetype: error loading glyph");
	}

	FT_Glyph glyph;

	error = FT_Get_Glyph( face->glyph, &glyph );

	if ( error )
	{
		throw Exception("freetype: error getting glyph");
	}

	FT_OutlineGlyph ft_outline_glyph_rec = (FT_OutlineGlyph)glyph;
	FT_Outline ft_outline = ft_outline_glyph_rec->outline;

	Shape2D outline;

//	cl_write_console_line(string_format("Num contours: %1", ft_outline.n_contours));

	for( int cont = 0; cont < ft_outline.n_contours; cont++ )
	{
//		cl_write_console_line(string_format("Num points in contour %1: %2", cont, ft_outline.contours[0]+1));
		
		Path2D contour;
		
		// debug: dump contents of points array to terminal
//		for( int i = 0; i <= ft_outline.contours[cont]; ++i )
//		{
//			FT_Vector pos = ft_outline.points[i];
//			cl_write_console_line(string_format("dump points[%1]: (%2,%3) \t type: %4", i, pos.x, pos.y, ft_outline.tags[i]));
//		}
		
		std::vector<TaggedPoint> points = get_contour_points(cont, &ft_outline);
		points.push_back(points.front()); // just to simplify, it's removed later.

		for( unsigned int i = 0; i < points.size()-1; i++ )
		{
			TaggedPoint &tp = points[i];

			if( tp.tag == FT_Curve_Tag_On )
			{
				contour.add_line_to(tp.pos);
			}
			else if( tp.tag == FT_Curve_Tag_Conic )
			{
				// TODO: i - 1 is safe here because we made sure the contour will start with a Tag_On.
				BezierCurve curve;
				curve.add_control_point( points[i-1].pos);
				curve.add_control_point( tp.pos );
				curve.add_control_point( points[i+1].pos );
				contour.add_curve(curve);
			}
			else if( tp.tag == FT_Curve_Tag_Cubic && points[i-1].tag == FT_Curve_Tag_Cubic )
			{
				BezierCurve curve;
				curve.add_control_point( points[i-2].pos);
				curve.add_control_point( points[i-1].pos);
				curve.add_control_point( tp.pos );
				curve.add_control_point( points[i+1].pos );
				contour.add_curve(curve);
			}			
		}

		outline.add_path(contour);
	}

	FT_Done_Glyph(glyph);

	out_advance_x = get_advance_x( c );

	return outline;
}
Esempio n. 23
0
int text_to_overlay(p_info_rec* p_info, overlay* ovly, char* text,
                    int max_width, char* font, const int size, 
                    const int aspect_ratio_num,
                    const int aspect_ratio_den)
{
    info_rec*	info;
    BYTE*	srcLine;
    BYTE*	dstLine;
    int		j;
    int		error;
    int		result;

    // initialise our data
    if (*p_info == NULL)
    {
        result = allocate_info(p_info);
        if (result < 0)
            return result;
    }
    info = *p_info;
    result = set_font(info, font, size, aspect_ratio_num, aspect_ratio_den);
    if (result < 0)
        return result;
    // render text using freetype2
    {
        #define MAX_GLYPHS 100
        FT_GlyphSlot	slot = info->face->glyph;  /* a small shortcut */
        FT_UInt		glyph_idx;
        FT_UInt		last_glyph;
        FT_Vector	delta;
        FT_Bool		use_kerning;
        int		pen_x, pen_y, n, margin;
        FT_Glyph	glyphs[MAX_GLYPHS];   /* glyph image    */    
        FT_Vector	pos   [MAX_GLYPHS];   /* glyph position */    
        FT_UInt		num_glyphs;
        int		vis_last;	// index of end of last "word"
        int		vis_width;	// width to vis_last

        use_kerning = FT_HAS_KERNING(info->face);
        // font metrics are unreliable, so use actual rendered characters
        // set left margin using a capital M character
        glyph_idx = FT_Get_Char_Index(info->face, 'M');
        FT_Load_Glyph(info->face, glyph_idx, FT_LOAD_DEFAULT);
        FT_Get_Glyph(info->face->glyph, &glyphs[0]);
        pen_x = slot->metrics.horiBearingX;
        margin = pen_x;
        FT_Done_Glyph(glyphs[0]);
        // set baseline using a capital A character
        glyph_idx = FT_Get_Char_Index(info->face, 'A');
        FT_Load_Glyph(info->face, glyph_idx, FT_LOAD_DEFAULT);
        FT_Get_Glyph(info->face->glyph, &glyphs[0]);
        pen_y = slot->metrics.horiBearingY;
        FT_Done_Glyph(glyphs[0]);
        // convert each character to a glyph and set its position
        num_glyphs = 0;
        vis_last = -1;
        vis_width = 0;
        last_glyph = FT_Get_Char_Index(info->face, ' ');
        for (n = 0; n < (int)strlen(text); n++)
        {
            if (text[n] == '\n')
                break;
            if (num_glyphs >= MAX_GLYPHS)
                break;
            glyph_idx = FT_Get_Char_Index(info->face, text[n]);
            if (use_kerning && last_glyph && glyph_idx)
            {
                FT_Get_Kerning(info->face, last_glyph, glyph_idx,
                               FT_KERNING_DEFAULT, &delta);
                pen_x += delta.x;
            }
            error = FT_Load_Glyph(info->face, glyph_idx, FT_LOAD_DEFAULT);
            if (error)
                continue;  /* ignore errors */
            error = FT_Get_Glyph(info->face->glyph, &glyphs[num_glyphs]);
            if (error)
                continue;  /* ignore errors */
            if (pen_y - slot->metrics.horiBearingY < 0)
            {
                fprintf(stderr, "Character '%c' ascends too high\n", text[n]);
                pen_y = slot->metrics.horiBearingY;
            }
            if (pen_y - slot->metrics.horiBearingY +
                        slot->metrics.height > size * 64)
            {
                fprintf(stderr, "Character '%c' descends too low\n", text[n]);
                exit(1);
            }
            pos[num_glyphs].x = pen_x;
            pos[num_glyphs].y = -pen_y;

            pen_x += slot->advance.x;
            last_glyph = glyph_idx;
            num_glyphs++;

            if (pen_x + (margin * 2) > max_width * 64)
                break;

            if (text[n] != ' ' &&
               (text[n+1] == ' ' || text[n+1] == '\0' || text[n+1] == '\n'))
            {
                vis_last = n;
                vis_width = pen_x;
            }
        }
        // truncate string to end of last word
        if (vis_last < 0)	// haven't found end of first word!
        {
            vis_last = num_glyphs - 1;
            vis_width = pen_x;
        }
        num_glyphs = vis_last + 1;
        // find start of next word
        result = num_glyphs;
        while (text[result] == ' ' || text[result] == '\n')
            result++;
        // set overlay dimensions
        ovly->w = (vis_width + (margin * 2)) / 64;
        ovly->h = size;
//        fprintf(stderr, "Area of '%s' = (%d x %d)\n", text, ovly->w, ovly->h);
        ovly->ssx = -1;
        ovly->ssy = -1;
        // alloc memory
        ovly->buff = malloc(ovly->w * ovly->h * 2);
        if (ovly->buff == NULL)
            return YUV_no_memory;
        memset(ovly->buff, 0, ovly->w * ovly->h * 2);
        ovly->Cbuff = NULL;
        // render glyphs in pre-calculated positions
        for (n = 0; n < (int)num_glyphs; n++)
        {
            error = FT_Glyph_To_Bitmap(&glyphs[n], FT_RENDER_MODE_NORMAL,
                                       &pos[n], 1);
            if (!error)
            {
                FT_BitmapGlyph	bit = (FT_BitmapGlyph)glyphs[n];
                srcLine = bit->bitmap.buffer;
                dstLine = ovly->buff - (bit->top * ovly->w) + bit->left;
                for (j = 0; j < bit->bitmap.rows; j++)
                {
                    memcpy(dstLine, srcLine, bit->bitmap.width);
                    srcLine += bit->bitmap.width;
                    dstLine += ovly->w;
                }
            }
            FT_Done_Glyph(glyphs[n]);
        }
    }
    return result;	// length of string actually rendered
}
/*
 * Renders a glyph immediately, then tries to puts it into cache.
 * rend and rend->face must be not 0
 */
static GLYPH* _gk_rend_workout(GLYPH_REND* const rend,const unsigned unicode)
{
    unsigned glyph_index;
    int bmp_size;
    int error;
    int center_x = 0,center_y = 0;
    FT_Glyph ft_glyph = 0;
    GLYPH* glyph;
    GLYPH_FACE* actual_face;
    unsigned actual_code;

#ifdef GLYPH_LOG
    if (glyph_log) fprintf(glyph_log,"_gk_rend_workout(%p,%d) begin\n",(void*)rend,unicode);
#endif

    CARE(rend && rend->face);
    CARE(unicode > 0);
    CARE(unicode <= GK_MAX_UNICODE);

    funcname = "_gk_rend_workout()";

    _gk_find_mapping(rend->face,unicode,&actual_face,&actual_code);
    if (!actual_face || !actual_code) return 0;
    if (!actual_face->face) return 0;

    glyph_index = FT_Get_Char_Index(actual_face->face,actual_code);
    if (!glyph_index)
    {
        if (unicode==rend->undefined_char || unicode==rend->error_char) return 0;
        else return _gk_rend_render(rend,rend->undefined_char);
    }

#ifdef GLYPH_LOG
    if (glyph_log) fprintf(glyph_log,"    glyph_index is %u\n",glyph_index);
#endif

    /* Preparing for glyph loading: setting size */
    /*FT_Activate_Size(size);*/
    if (actual_face == rend->face)
    {
        error = (rend->size == 0);
        if (!error) actual_face->face->size = rend->size;
    }
    else
    {
        error = (actual_face->own_size == 0);
        if (!error)
        {
            actual_face->face->size = actual_face->own_size;
            error = FT_Set_Char_Size(actual_face->face,rend->hsize,rend->vsize,72,72);
        }
    }

#ifdef GLYPH_LOG
    if (error)
    {
        if (glyph_log) fprintf(glyph_log,"    Failed to select size\n");
    }
    else
    {
        if (glyph_log) fprintf(glyph_log,"    Size selected successfully\n");
    }
#endif

    /* Loading a glyph with FreeType */
    if (!error)
    {
        error = FT_Load_Glyph(actual_face->face,glyph_index,rend->load_flags);
        if (error)
            _gk_msg("Error: %s: FT_Load_Glyph() bugs on glyph (#%d) for character U+%04X\n",funcname,glyph_index,unicode);
        else
        {
            error = (actual_face->face->glyph == 0);
            if (error) _gk_msg("Error: %s: Empty glyph slot after FT_Load_Glyph()\n",funcname);
        }

/*#ifdef GLYPH_LOG
        if (error)
        {
            if (glyph_log) fprintf(glyph_log,"    Could not load a glyph with FT_Load_Glyph()\n");
        }
        else
        {
            if (glyph_log) fprintf(glyph_log,"    Loaded a glyph with FT_Load_Glyph()\n");
        }
#endif*/
    }


    /* Getting center coordinates (MEGA-HACK) */
    /* This whole idea should be re-made in more optimal way */
    if (!error)
    {
/*#ifdef GLYPH_LOG
        if (glyph_log) fprintf(glyph_log,"    Getting a center point\n");
#endif*/
        FT_Glyph g = 0;
        error = FT_Get_Glyph(actual_face->face->glyph, &g);
/*#ifdef GLYPH_LOG
        if (glyph_log)
        {
            if (error)
                fprintf(glyph_log,"    FT_Get_Glyph() failed\n");
            else
                fprintf(glyph_log,"    FT_Get_Glyph() succeeded\n");
            if (g)
                fprintf(glyph_log,"    FT_Get_Glyph() returned not 0\n");
            else
                fprintf(glyph_log,"    FT_Get_Glyph() returned 0\n");
        }
#endif*/

        error = error || !g;
        if (!error && g->format==FT_GLYPH_FORMAT_OUTLINE)
        {
/*#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"    Calling FT_Glyph_To_Bitmap()\n");
#endif*/
            error = FT_Glyph_To_Bitmap(&g,rend->render_mode,0,1);
/*#ifdef GLYPH_LOG
            if (glyph_log)
            {
                if (error)
                    fprintf(glyph_log,"    FT_Glyph_To_Bitmap() failed\n");
                else
                    fprintf(glyph_log,"    FT_Glyph_To_Bitmap() succeeded\n");
            }
#endif*/
            if (!error)
            {
                center_x = 64 * ((FT_BitmapGlyph)g)->left + 64 * ((FT_BitmapGlyph)g)->bitmap.width / 2;
                center_y = 64 * ((FT_BitmapGlyph)g)->top - 64 * ((FT_BitmapGlyph)g)->bitmap.rows / 2;
                /*center_x = 64 * ((FT_BitmapGlyph)g)->bitmap.width / 2;
                center_y = -64 * ((FT_BitmapGlyph)g)->bitmap.rows / 2;*/
            }
        }
        if (g)
        {
/*#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"    Calling FT_Done_Glyph()\n");
#endif*/
            FT_Done_Glyph(g);
        }
/*#ifdef GLYPH_LOG
        if (glyph_log)
        {
            if (error)
                fprintf(glyph_log,"    Could not find a center point\n");
            else
                fprintf(glyph_log,"    Computed a center point\n");
        }
#endif*/
    }




    /* Emboldening the glyph */
    if (!error)
    {
        if (rend->bold_strength && actual_face->face->glyph->format==FT_GLYPH_FORMAT_OUTLINE)
        {
            int xstr, ystr, xstr2, ystr2;
            int xmin,xmax,ymin,ymax;
            int center_dx, center_dy;
            FT_GlyphSlot slot = actual_face->face->glyph;

#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"        Emboldening the glyph by %d\n",rend->bold_strength);
#endif

            xstr = rend->bold_strength * 
                   FT_MulFix( actual_face->face->units_per_EM, actual_face->face->size->metrics.y_scale ) / 2400;
            ystr = xstr;
#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            xstr = %d, ystr = %d\n",xstr,ystr);
#endif
            GK_Outline_Embolden(&slot->outline,xstr,&xmin,&xmax,&ymin,&ymax);
#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            xmin = %d, xmax = %d\n",xmin,xmax);
            if (glyph_log) fprintf(glyph_log,"            ymin = %d, ymax = %d\n",ymin,ymax);
#endif
            /*xstr = xstr * 2;
            ystr = xstr;*/
#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            xstr = %d, ystr = %d\n",xstr,ystr);
#endif

            xstr2 = xmin+xmax;
            ystr2 = ymin+ymax;
#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            xstr2 = %d, ystr2 = %d\n",xstr2,ystr2);
            if (glyph_log) fprintf(glyph_log,"            xscale = %.5f\n",((double)actual_face->face->size->metrics.x_scale)/65536);
            if (glyph_log) fprintf(glyph_log,"            yscale = %.5f\n",((double)actual_face->face->size->metrics.y_scale)/65536);
#endif

            if (slot->advance.x) slot->advance.x += xstr;
            if (slot->advance.y) slot->advance.y += ystr;

            slot->metrics.width        += xstr * 2;
            slot->metrics.height       += ystr * 2;
            /*slot->metrics.horiBearingX -= xmin;*/
            slot->metrics.horiBearingY += ystr * 2;
            slot->metrics.horiAdvance  += xstr * 2;
            slot->metrics.vertBearingX -= xstr;
            slot->metrics.vertBearingY += ystr * 2;
            slot->metrics.vertAdvance  += ystr * 2;

            /*center_dx = (int)( (double)xstr / 2 * (double)actual_face->face->size->metrics.x_scale / (80000) );
            center_dy = (int)( (double)ystr / 2 * (double)actual_face->face->size->metrics.y_scale / (65536) );*/

            center_dx = (int)( (double)rend->bold_strength * (double)actual_face->face->size->metrics.x_ppem / 80);
            center_dy = (int)( (double)rend->bold_strength * (double)actual_face->face->size->metrics.y_ppem / 80);

#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            center_x += %.1f\n",((double)center_dx)/64);
            if (glyph_log) fprintf(glyph_log,"            center_y += %.1f\n",((double)center_dx)/64);
#endif

            center_x += center_dx;
            center_y += center_dy;

            /*center_x += xstr;*/
            /*center_y += ymin;*/

            /*FT_GlyphSlot_Embolden(slot);*/
        }
    }

    /* Getting a glyph from FreeType */
    if (!error)
    {
        error = FT_Get_Glyph(actual_face->face->glyph, &ft_glyph);
        error = error || !ft_glyph;
        if (error)
            _gk_msg("Error: %s: Can't get a glyph with FT_Get_Glyph() call. Glyph (#%d) for character U+%04X\n",
            funcname,glyph_index,unicode);
    }

    /* Transforming the glyph to apply rotation and italics */
    if (!error && ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE && rend->do_matrix_transform)
    {
        error = FT_Glyph_Transform(ft_glyph,&rend->matrix,0);
        if (!error)
        {
            FT_Vector c;
            c.x = center_x;
            c.y = center_y;
            FT_Vector_Transform(&c,&rend->matrix);
            center_x = c.x;
            center_y = c.y;
        }
    }

    /* Converting glyph to bitmap */
    if (!error && ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE)
    {
        error = FT_Glyph_To_Bitmap(&ft_glyph,rend->render_mode,0,1);
        if (error) _gk_msg("Error: %s: FT_Glyph_To_Bitmap() bugs on character U+%04X\n",funcname,unicode);
    }

    /* Checking if we have bitmap now */
    if (!error)
    {
        error = (ft_glyph->format!=FT_GLYPH_FORMAT_BITMAP);
        if (error) _gk_msg("Error: %s: Glyph is not FT_GLYPH_FORMAT_BITMAP after rendering with FT_Glyph_To_Bitmap()\n",funcname);
    }

#ifdef GLYPH_LOG
/*    {
        if (glyph_log)
        {
            fprintf(glyph_log,"    We got a bitmap glyph from FreeType!\n");
            if (ft_glyph->format==FT_GLYPH_FORMAT_BITMAP)
            {
                fprintf(glyph_log,"        Format: FT_GLYPH_FORMAT_BITMAP\n");
                fprintf(glyph_log,"        Size: %dx%d, pitch: %d\n",
                                  ((FT_BitmapGlyph)ft_glyph)->bitmap.width,
                                  ((FT_BitmapGlyph)ft_glyph)->bitmap.rows,
                                  ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch);
                if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_MONO)
                {
                    int x,y;
                    int pitch = ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch;
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_MONO\n");
                    fprintf(glyph_log,"        Buffer:\n");
                    for (y=0; y < ((FT_BitmapGlyph)ft_glyph)->bitmap.rows; y++)
                    {
                        fprintf(glyph_log,"            ");
                        for (x=0; x < ((FT_BitmapGlyph)ft_glyph)->bitmap.width; x++)
                        {
                            unsigned char byte = ((unsigned char*)((FT_BitmapGlyph)ft_glyph)->bitmap.buffer)[y*pitch+x];
                            unsigned char mask = 128 >> (x%8);
                            fprintf(glyph_log,"%s",(byte&mask)?" *":" .");
                        }
                        fprintf(glyph_log,"\n");
                    }
                }
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_GRAY\n");
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY2)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_GRAY2\n");
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY4)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_GRAY4\n");
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_LCD)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_LCD\n");
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_LCD_V)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_LCD_V\n");
            }
            else if (ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE)
            {
                fprintf(glyph_log,"        Format: FT_GLYPH_FORMAT_OUTLINE\n");
            }
            fprintf(glyph_log,"        Advance: ( %.1f , %.1f ) pixels\n",
                    ((double)ft_glyph->advance.x)/0x10000,((double)ft_glyph->advance.y)/0x10000);
        }
    }*/
#endif

    if (!error)
    {
        error = ( ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch < 0 );
        if (error) _gk_msg("Error: rend_workout(): Rendered glyph has negative pitch value, can't handle\n"); /* FIXME */
    }

    if (!error)
    {
        glyph = (GLYPH*)_gk_malloc(sizeof(GLYPH));
        error = (glyph == 0);
    }

    if (error || !ft_glyph)
    {
        if (ft_glyph) FT_Done_Glyph(ft_glyph);

        if (unicode==rend->error_char) return 0;
        else return _gk_rend_render(rend,rend->error_char);
    }

    glyph->unicode = unicode;
    glyph->width = ((FT_BitmapGlyph)ft_glyph)->bitmap.width;
    glyph->height = ((FT_BitmapGlyph)ft_glyph)->bitmap.rows;
    glyph->left = ((FT_BitmapGlyph)ft_glyph)->left;
    glyph->top = ((FT_BitmapGlyph)ft_glyph)->top;
    glyph->advance_x = ft_glyph->advance.x >> 10;
    glyph->advance_y = ft_glyph->advance.y >> 10;
    glyph->center_x = (center_x + 31) / 64;
    glyph->center_y = (center_y + 31) / 64;

    glyph->index = 0;
    glyph->prev = 0;
    glyph->next = 0;
    glyph->bmp = 0;
    glyph->bmpsize = 0;

    _gk_msg("rendering character '%c'\n",unicode);

    bmp_size = glyph->width*glyph->height;
    if (!bmp_size) /* empty glyph, like space (' ') character */
    {
        if (rend->index) _gk_glyph_index_add_glyph(rend->index,glyph);
        FT_Done_Glyph(ft_glyph);
        return glyph;
    }

    if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
    {
#ifdef GLYPH_TARGET_KNOWS_MONO_BITPACK
        int pitch1 = (glyph->width+7)>>3;
        int bitpack_size = glyph->height*pitch1;

#ifdef GLYPH_TARGET_KNOWS_MONO_RLE7
        int rle_size = 0;

        if (rend->index)
              rle_size = _gk_make_RLE7( ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer,
                         glyph->width, glyph->height, ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch);

        if (rle_size>0 && rle_size<=bitpack_size)
        {
            glyph->bmp = (unsigned char*)_gk_malloc(rle_size);
            if (!glyph->bmp) { _gk_free(glyph); return 0; }
            memcpy(glyph->bmp,rle_buffer,rle_size);
            glyph->bmpsize = rle_size;
        }
        else
#endif  /* GLYPH_TARGET_KNOWS_MONO_RLE7 */
        {
            glyph->bmp = (unsigned char*)_gk_malloc(bitpack_size+1);
            if (!glyph->bmp) { _gk_free(glyph); return 0; }
            glyph->bmp[0] = GLYPH_MONO_BITPACK;
            if ( ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch == pitch1 )
                memcpy( glyph->bmp+1, ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer, bitpack_size );
            else
            {
                unsigned char *d = glyph->bmp+1;
                int y = 0;
                for (; y<glyph->height; y++,d+=pitch1)
                    memcpy( d, ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer + y * ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch, pitch1 );
            }
            glyph->bmpsize = bitpack_size+1;
        }
#else  /* GLYPH_TARGET_KNOWS_MONO_BITPACK */
        {
            int y = 0;
            unsigned char* b;

            glyph->bmp = (unsigned char*)_gk_malloc(bmp_size+1);
            if (!glyph->bmp) { _gk_free(glyph); return 0; }
            glyph->bmp[0] = GLYPH_UNCOMPRESSED;
            glyph->bmpsize = bmp_size+1;
            b = glyph->bmp + 1;

            for (; y<glyph->height; y++)
            {
                int x = 0;
                unsigned char* a = ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer + y * ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch;
                while (x<glyph->width)
                {
                    if (x < glyph->width) { *b++ = *a&0x80 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x40 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x20 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x10 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x08 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x04 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x02 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x01 ? 255 : 0; x++; }
                    a++;
                }
            }
        }
#endif  /* GLYPH_TARGET_KNOWS_MONO_BITPACK */
    }
Esempio n. 25
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 | font->hinting);
	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( TTF_HANDLE_STYLE_BOLD(font) ) {
			cached->maxx += font->glyph_overhang;
		}
		if( TTF_HANDLE_STYLE_ITALIC(font) ) {
			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;
		FT_Glyph bitmap_glyph = NULL;

		/* Handle the italic style */
		if( TTF_HANDLE_STYLE_ITALIC(font) ) {
			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 as outline */
		if( (font->outline > 0) && glyph->format != FT_GLYPH_FORMAT_BITMAP ) {
			FT_Stroker stroker;
			FT_Get_Glyph( glyph, &bitmap_glyph );
			error = FT_Stroker_New( library, &stroker );
			if( error ) {
				return error;
			}
			FT_Stroker_Set( stroker, font->outline * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 ); 
			FT_Glyph_Stroke( &bitmap_glyph, stroker, 1 /* delete the original glyph */ );
			FT_Stroker_Done( stroker );
			/* Render the glyph */
			error = FT_Glyph_To_Bitmap( &bitmap_glyph, mono ? ft_render_mode_mono : ft_render_mode_normal, 0, 1 );
			if( error ) {
				FT_Done_Glyph( bitmap_glyph );
				return error;
			}
			src = &((FT_BitmapGlyph)bitmap_glyph)->bitmap;
		} else {
			/* Render the glyph */
			error = FT_Render_Glyph( glyph, mono ? ft_render_mode_mono : ft_render_mode_normal );
			if( error ) {
				return error;
			}
			src = &glyph->bitmap;
		}
		/* Copy over information to cache */
		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 ( src->pixel_mode == FT_PIXEL_MODE_MONO ) {
			dst->pitch *= 8;
		} else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY2 ) {
			dst->pitch *= 4;
		} else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY4 ) {
			dst->pitch *= 2;
		}

		/* Adjust for bold and italic text */
		if( TTF_HANDLE_STYLE_BOLD(font) ) {
			int bump = font->glyph_overhang;
			dst->pitch += bump;
			dst->width += bump;
		}
		if( TTF_HANDLE_STYLE_ITALIC(font) ) {
			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 ( src->pixel_mode == FT_PIXEL_MODE_MONO ) {
						for ( j = 0; j < src->width; j += 8 ) {
							unsigned char c = *srcp++;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
						}
					}  else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY2 ) {
						for ( j = 0; j < src->width; j += 4 ) {
							unsigned char c = *srcp++;
							*dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
							c <<= 2;
							*dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
							c <<= 2;
							*dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
							c <<= 2;
							*dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
						}
					} else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY4 ) {
						for ( j = 0; j < src->width; j += 2 ) {
							unsigned char c = *srcp++;
							*dstp++ = (((c&0xF0) >> 4) >= 0x8) ? 1 : 0;
							c <<= 4;
							*dstp++ = (((c&0xF0) >> 4) >= 0x8) ? 1 : 0;
						}
					} else {
						for ( j = 0; j < src->width; j++ ) {
Esempio n. 26
0
    Glyph::Glyph(FT_Library &library, FontFace &fontFace, int c, int outlineWidth, bool hinting) :
    mFont(fontFace)
    {
        mChar = c;
        
        FT_Face &face = fontFace.GetFTFace();

        int flags = FT_LOAD_DEFAULT;
        if (!hinting)
        {
            flags = FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING;
        }
        
        FT_Error error = FT_Load_Char(face, c, flags);
        if (error) {
            return;
        }
        
        mGlyphIndex = FT_Get_Char_Index(face, c);
        
        // Load The Glyph For Our Character.
        if(FT_Load_Glyph( face, mGlyphIndex, flags ))
            throw std::runtime_error("FT_Load_Glyph failed");
        
        // Move The Face's Glyph Into A Glyph Object.
        FT_Glyph glyph;
        if(FT_Get_Glyph( face->glyph, &glyph ))
            throw std::runtime_error("FT_Get_Glyph failed");
        
        FT_Stroker stroker;
        FT_Stroker_New(library, &stroker);
        FT_Stroker_Set(stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
        FT_Glyph_StrokeBorder(&glyph, stroker, false, true);
        
        FT_OutlineGlyph olglyph = reinterpret_cast<FT_OutlineGlyph>(glyph);
        
        FT_Outline outline = olglyph->outline;
        
        RenderSpans(library, &outline);
        
        FT_Stroker_Done(stroker);
        
        // Get metrics
        FT_Glyph_Metrics metrics = face->glyph->metrics;
        mAdvance.x = metrics.horiAdvance * kOneOver64;
        mAdvance.y = metrics.vertAdvance * kOneOver64;
        
        mBearing.x = metrics.horiBearingX * kOneOver64;
        mBearing.y = metrics.horiBearingY * kOneOver64;
        
        mSize.x = glm::round(metrics.width * kOneOver64);
        mSize.y = glm::round(metrics.height * kOneOver64);
        
        // Adjust for outline?
        mAdvance.x += outlineWidth;
        
        // Draw spans
        if(mSpans.size() > 0)
        {
            GlyphSpan front = mSpans.front();
            Rect bounds(front.x, front.y, front.x, front.y);
            for(int i = 0; i < mSpans.size(); i++)
            {
                bounds.Include(mSpans[i].x, mSpans[i].y + 1);
                bounds.Include(mSpans[i].x + mSpans[i].width, mSpans[i].y);
            }
            
            int width = bounds.GetWidth();
            int height = bounds.GetHeight();
            
            mDataSize.x = width;
            mDataSize.y = height;
            
            int size = width * height;
            
            mBuffer = new unsigned char[size];
            memset(mBuffer, 0, size);
            for(int i = 0; i < mSpans.size(); i++)
            {
                GlyphSpan &span = mSpans[i];
                for (int w = 0; w < span.width; ++w)
                {
                    mBuffer[(int)((height - 1 - (span.y - bounds.top)) * width
                                  + span.x - bounds.left + w)] = span.coverage;
                }
            }
        }
        FT_Done_Glyph(glyph);
    }
JNIEXPORT jobject JNICALL 
Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_getGlyphOutlineNative
 (JNIEnv *env, jobject obj __attribute__((unused)), jint glyphIndex, jlong fnt)
{
  generalpath *path;
  jobject gp;
  FT_Outline_Funcs ftCallbacks =
    {
      (FT_Outline_MoveToFunc) _moveTo,
      (FT_Outline_LineToFunc) _lineTo,
      (FT_Outline_ConicToFunc) _quadTo,
      (FT_Outline_CubicToFunc) _curveTo,
      0,
      0
    };
  PangoFcFont *font;
  FT_Face ft_face;
  FT_Glyph glyph;

  font = JLONG_TO_PTR(PangoFcFont, fnt);
  ft_face = pango_fc_font_lock_face( font );

  g_assert (ft_face != NULL);

  path = g_malloc0 (sizeof (generalpath));
  g_assert(path != NULL);
  path->env = env;

  path->px = path->py = 0.0;
  path->sx = 1.0/64.0;
  path->sy = -1.0/64.0;

  {  /* create a GeneralPath instance */
    jclass cls;
    jmethodID method;
    
    cls = (*env)->FindClass (env, "java/awt/geom/GeneralPath");
    method = (*env)->GetMethodID (env, cls, "<init>", "()V");
    gp = path->obj = (*env)->NewObject (env, cls, method);
  }
	      
  if(FT_Load_Glyph(ft_face,
		   (FT_UInt)(glyphIndex),
		   FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP) != 0)
    {
      pango_fc_font_unlock_face( font );
      g_free(path); 
      return NULL;
    }

  FT_Get_Glyph( ft_face->glyph, &glyph );
  if (glyph->format == FT_GLYPH_FORMAT_OUTLINE)
    {
      FT_Outline_Decompose (&(((FT_OutlineGlyph)glyph)->outline),
			    &ftCallbacks, path);
    }
  else
    {
      char format[5];

      format[0] = (glyph->format & 0xFF000000) >> 24;
      format[1] = (glyph->format & 0x00FF0000) >> 16;
      format[2] = (glyph->format & 0x0000FF00) >> 8;
      format[3] = (glyph->format & 0x000000FF);
      format[4] = '\0';
      printf("WARNING: Unable to create outline for font %s %s of format %s\n",
	     ft_face->family_name, ft_face->style_name, format);
    }
  FT_Done_Glyph( glyph );
  
  pango_fc_font_unlock_face( font );

  g_free(path); 

  return gp; 
}
Esempio n. 28
0
/*
    TODO: Font rendering MUST be redesigned.
*/
Font* GuiRendererD3D11::MakeFont(const char* pPath, int height)
{
    Common::Timer timer;
    timer.Start();

    FT_Face face;
    int texWidth = 4096;
    int texHeight = 4096;

    //create pixels array
    unsigned char* pTexData = (unsigned char*)malloc(texWidth * texHeight);
    ZeroMemory(pTexData, texWidth * texHeight);

    if (FT_New_Face(mFreeTypeLibrary, pPath, 0, &face) != 0)
    {
        free(pTexData);
        // TODO
        // LOG_ERROR("Failed to load font '%s'.", pPath);
        return 0;
    }

    //FT_Set_Pixel_Sizes(face, 2*height, 2*height);
    FT_Set_Char_Size(face, 0, height * 64, 96, 96);


    Font* pFont = new Font;

    /*
    FT_Matrix Transform;
    Transform.xx = (FT_Fixed)(1.0f * 0x10000L);
    Transform.xy = (FT_Fixed)(0.0f * 0x10000L);
    Transform.yx = (FT_Fixed)(0.0f * 0x10000L);
    Transform.yy = (FT_Fixed)(1.0f * 0x10000L);
    FT_Set_Transform(face, &Transform, 0);
    */

    int Width;
    int Height;
    int OffsetX = 0;
    int OffsetY = 0;

    pFont->height = height;
    pFont->charCount = 65536;
    pFont->characters = (CharacterInfo*)malloc(sizeof(CharacterInfo) * pFont->charCount);

    int Index = 0;
    for (int ChrId = 0; ChrId < (65536); ChrId++)
    {
        // Load The Glyph For Our Character.
        unsigned int GlyphIndex = FT_Get_Char_Index(face, ChrId);
        if (GlyphIndex == 0)
        {
            pFont->characters[ChrId].exists = false;
            continue;
        }

        FT_Load_Glyph(face, GlyphIndex, FT_LOAD_DEFAULT);


        // Move The Face's Glyph Into A Glyph Object.
        FT_Glyph glyph;
        FT_Get_Glyph(face->glyph, &glyph);


        // Convert The Glyph To A Bitmap.
        FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
        FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;

        // This Reference Will Make Accessing The Bitmap Easier.
        FT_Bitmap& bitmap = bitmap_glyph->bitmap;


        Width = bitmap.width;
        Height = bitmap.rows;

        //char won't fit to texture
        if (OffsetX + Width + 2 > texWidth)
        {
            OffsetX = 0;
            OffsetY += 2 * height;
        }

        for (int y = 0; y < Height; y++)
        {
            for (int x = 0; x < Width; x++)
            {
                unsigned char Value = bitmap.buffer[x + Width * y];

                int PxOffset = (y + OffsetY) * texWidth + x + OffsetX;
                pTexData[PxOffset] = Value;
            }
        }


        pFont->characters[ChrId].exists = true;
        pFont->characters[ChrId].top = (short)bitmap_glyph->top;
        pFont->characters[ChrId].left = (short)bitmap_glyph->left;
        pFont->characters[ChrId].height = (short)Height;
        pFont->characters[ChrId].width = (short)Width;
        pFont->characters[ChrId].u = (short)OffsetX;
        pFont->characters[ChrId].v = (short)OffsetY;
        pFont->characters[ChrId].spacing = (short)(face->glyph->advance.x >> 6) + 1;
        FT_Done_Glyph(glyph);

        OffsetX += pFont->characters[ChrId].width + 1;
        Index++;
    }

    //close font
    FT_Done_Face(face);

    OffsetY += 2 * height; // Used texture height
    texHeight = CeilToPowerOf2(OffsetY);


    Common::Image fontImage;
    fontImage.SetData(pTexData, texWidth, texHeight, Common::ImageFormat::A_UBYTE);
//  pFont->texture = pRenderer->CreateTexture(&fontImage, false);
    pFont->texture = new RendererTextureD3D11;
    pFont->texture->FromImage(fontImage);


    pFont->texHeight = texHeight;
    pFont->texWidth = texWidth;

    free(pTexData);

    // TODO
    // LOG_SUCCESS("Font '%s', size %i loaded in %.3lf seconds.", pPath, height, timer.Stop());
    return pFont;
}
Esempio n. 29
0
bool TrueTypeFont::bakeGlyphDistance(CodePoint _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer)
{
	BX_CHECK(m_font != NULL, "TrueTypeFont not initialized");

	_glyphInfo.glyphIndex = FT_Get_Char_Index(m_font->face, _codePoint);

	FT_Int32 loadMode = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
	FT_Render_Mode renderMode = FT_RENDER_MODE_NORMAL;

	FT_GlyphSlot slot = m_font->face->glyph;
	FT_Error error = FT_Load_Glyph(m_font->face, _glyphInfo.glyphIndex, loadMode);
	if (error)
	{
		return false;
	}

	FT_Glyph glyph;
	error = FT_Get_Glyph(slot, &glyph);
	if (error)
	{
		return false;
	}

	error = FT_Glyph_To_Bitmap(&glyph, renderMode, 0, 1);
	if (error)
	{
		return false;
	}

	FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;

	int32_t ww = bitmap->bitmap.width;
	int32_t hh = bitmap->bitmap.rows;

	glyphInfoInit(_glyphInfo, bitmap, slot, _outBuffer, 1);

	FT_Done_Glyph(glyph);

	if (ww * hh > 0)
	{
		uint32_t dw = 6;
		uint32_t dh = 6;

		uint32_t nw = ww + dw * 2;
		uint32_t nh = hh + dh * 2;
		BX_CHECK(nw * nh < 128 * 128, "Buffer overflow (size %d)", nw * nh);

		uint32_t buffSize = nw * nh * sizeof(uint8_t);

		uint8_t* alphaImg = (uint8_t*)malloc(buffSize);
		memset(alphaImg, 0, nw * nh * sizeof(uint8_t) );

		//copy the original buffer to the temp one
		for (uint32_t ii = dh; ii < nh - dh; ++ii)
		{
			memcpy(alphaImg + ii * nw + dw, _outBuffer + (ii - dh) * ww, ww);
		}

		makeDistanceMap(alphaImg, _outBuffer, nw, nh);
		free(alphaImg);

		_glyphInfo.offset_x -= (float)dw;
		_glyphInfo.offset_y -= (float)dh;
		_glyphInfo.width = (float)nw;
		_glyphInfo.height = (float)nh;
	}

	return true;
}
Esempio n. 30
0
/*
 * Function    : libaroma_font_glyph_draw
 * Return Value: byte
 * Descriptions: draw glyph into canvas
 */
byte libaroma_font_glyph_draw(
  LIBAROMA_CANVASP dest,
  LIBAROMA_GLYPH aglyph_param,
  int x,
  int y,
  word color,
  byte flags,
  byte opacity
) {
  _LIBAROMA_FONT_SLOT_CACHEP aglyph =
    (_LIBAROMA_FONT_SLOT_CACHEP) aglyph_param;
  if (!aglyph) {
    return 0;
  }
  if (aglyph->glyph==NULL) {
    return 0;
  }
  if (dest == NULL) {
    dest = libaroma_fb()->canvas;
  }
  /* thread safe lock */
  _libaroma_font_lock(1);
  
  /* copy & render */
  FT_Glyph fglyph=NULL;
  fglyph=NULL;
  int cnt=0;
  if (FT_Glyph_Copy(aglyph->glyph, &fglyph)!=0){
    _libaroma_font_lock(0);
    return 0;
  }
  if (cnt>0){
    printf("[FT] FC: %i %i\n",cnt,aglyph->codepoint);
  }
  /* italic transform */
  if (flags & _LIBAROMA_TEXTCHUNK_ITALIC) {
    FT_Matrix matrix;
    matrix.xx = 0x10000L;
    matrix.xy = 0x5000L;
    matrix.yx = 0;
    matrix.yy = 0x10000L;
    FT_Glyph_Transform(fglyph, &matrix, NULL);
  }
  
  /* embolden */
  if (flags & _LIBAROMA_TEXTCHUNK_BOLD) {
    FT_Outline_Embolden(
      &((FT_OutlineGlyph) fglyph)->outline,
      aglyph->size * 2
    );
  }
  
  /* convert glyph to bitmap glyph */
  if (FT_Glyph_To_Bitmap(&fglyph, _LIBAROMA_FONT_RENDER_FLAG, 0, 1)!=0){
    /* release glyph */
    printf("[FT] FR:%i\n",aglyph->codepoint);
    FT_Done_Glyph(fglyph);
    _libaroma_font_lock(0);
    return 0;
  }
    
  /* as bitmap glyph */
  FT_BitmapGlyph bit = (FT_BitmapGlyph) fglyph;
  
  /* prepare locations */
  /*int yy;*/
  typeof(bit->bitmap.rows) yy;
  int xpos = x + bit->left;
  int xstart = 0;
  
  if (xpos < 0) {
    xstart = 0 - xpos;
    xpos = 0;
  }
  
  /* loop */
#ifndef LIBAROMA_CONFIG_NOFONT_SUBPIXEL
  int draw_w  = (bit->bitmap.width / 3) - xstart;
  if (draw_w + xpos > dest->w) {
    draw_w = dest->w - xpos;
  }
  if (draw_w > 0) {
    wordp tmp_dst = NULL;
    if (opacity != 0xff) {
      tmp_dst = (wordp) malloc(draw_w * 2);
    }
    for (yy = 0; yy < bit->bitmap.rows; yy++) {
      /* drawing positions */
      int yglp = (yy - bit->top);
      int ypos = (y + yglp) * dest->l;
      
      /* check position */
      if ((ypos+draw_w>(dest->l*dest->h)) || (ypos<0)) {
        continue;
      }
      
      /* source * destination pointers */
      int ysrc = yy * bit->bitmap.pitch;
      bytep src_line  = bit->bitmap.buffer + ysrc + (xstart * 3);
      wordp dest_line = dest->data + ypos + xpos;
      
      /* draw line */
      if (opacity == 0xff) {
        libaroma_alpha_multi_line(
          draw_w, dest_line, dest_line, color, src_line);
      }
      else {
        libaroma_alpha_multi_line(
          draw_w, tmp_dst, dest_line, color, src_line);
        libaroma_alpha_const(
          draw_w, dest_line, dest_line, tmp_dst, opacity);
      }
    }
    if (tmp_dst) {
      free(tmp_dst);
    }
  }
#else
  int draw_w  = bit->bitmap.width - xstart;
  if (draw_w + xpos > dest->w) {
    draw_w = dest->w - xpos;
  }
  if (draw_w > 0) {
    wordp tmp_dst = NULL;
    if (opacity != 0xff) {
      tmp_dst = (wordp) malloc(draw_w * 2);
    }
    /* line */
    for (yy = 0; yy < bit->bitmap.rows; yy++) {
      /* drawing positions */
      int yglp = (yy - bit->top);
      int ypos = (y + yglp) * dest->l;
      /* check position */
      if ((ypos+draw_w>(dest->l*dest->h)) || (ypos<0)) {
        continue;
      }
      /* source & destination pointers */
      int ysrc = yy * bit->bitmap.pitch;
      bytep src_line  = bit->bitmap.buffer + ysrc + xstart;
      wordp dest_line = dest->data + ypos + xpos;
      /* draw line */
      if (opacity == 0xff) {
        libaroma_alpha_mono(
          draw_w, dest_line, dest_line, color, src_line);
      }
      else {
        libaroma_alpha_mono(
          draw_w, tmp_dst, dest_line, color, src_line);
        libaroma_alpha_const(
          draw_w, dest_line, dest_line, tmp_dst, opacity);
      }
    }
    if (tmp_dst) {
      free(tmp_dst);
    }
  }
  
#endif
  /* release glyph */
  FT_Done_Glyph(fglyph);
  _libaroma_font_lock(0);
  return 1;
} /* End of libaroma_font_glyph_draw */