Exemplo n.º 1
1
void
WriteGlyphAsTGA(FT_Library &library,
                const std::string &fileName,
                wchar_t ch,
                FT_Face &face,
                int size,
                const Pixel32 &fontCol,
                const Pixel32 outlineCol,
                float outlineWidth)
{
	// Set the size to use.
	if (FT_Set_Char_Size(face, size << 6, size << 6, 90, 90) == 0)
	{
		// Load the glyph we are looking for.
		FT_UInt gindex = FT_Get_Char_Index(face, ch);
		if (FT_Load_Glyph(face, gindex, FT_LOAD_NO_BITMAP) == 0)
		{
			// Need an outline for this to work.
			if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
			{
				// Render the basic glyph to a span list.
				Spans spans;
				RenderSpans(library, &face->glyph->outline, &spans);

				// Next we need the spans for the outline.
				Spans outlineSpans;

				// Set up a stroker.
				FT_Stroker stroker;
				FT_Stroker_New(library, &stroker);
				FT_Stroker_Set(stroker,
					       (int)(outlineWidth * 64),
					       FT_STROKER_LINECAP_ROUND,
					       FT_STROKER_LINEJOIN_ROUND,
					       0);

				FT_Glyph glyph;
				if (FT_Get_Glyph(face->glyph, &glyph) == 0)
				{
					FT_Glyph_StrokeBorder(&glyph, stroker, 0, 1);
					// Again, this needs to be an outline to work.
					if (glyph->format == FT_GLYPH_FORMAT_OUTLINE)
					{
						// Render the outline spans to the span list
						FT_Outline *o =
						  &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
						RenderSpans(library, o, &outlineSpans);
					}

					// Clean up afterwards.
					FT_Stroker_Done(stroker);
					FT_Done_Glyph(glyph);

					// Now we need to put it all together.
					if (!spans.empty())
					{
						// Figure out what the bounding rect is for both the span lists.
						Rect rect(spans.front().x,
							  spans.front().y,
							  spans.front().x,
							  spans.front().y);
						for (Spans::iterator s = spans.begin();
						     s != spans.end(); ++s)
						{
							rect.Include(Vec2(s->x, s->y));
							rect.Include(Vec2(s->x + s->width - 1, s->y));
						}
						for (Spans::iterator s = outlineSpans.begin();
						     s != outlineSpans.end(); ++s)
						{
							rect.Include(Vec2(s->x, s->y));
							rect.Include(Vec2(s->x + s->width - 1, s->y));
						}

#if 0
						// This is unused in this test but you would need this to draw
						// more than one glyph.
						float bearingX = face->glyph->metrics.horiBearingX >> 6;
						float bearingY = face->glyph->metrics.horiBearingY >> 6;
						float advance = face->glyph->advance.x >> 6;
#endif

						// Get some metrics of our image.
						int imgWidth = rect.Width(),
						  imgHeight = rect.Height(),
						  imgSize = imgWidth * imgHeight;

						// Allocate data for our image and clear it out to transparent.
						Pixel32 *pxl = new Pixel32[imgSize];
						memset(pxl, 0, sizeof(Pixel32) * imgSize);

						// Loop over the outline spans and just draw them into the
						// image.
						for (Spans::iterator s = outlineSpans.begin();
						     s != outlineSpans.end(); ++s)
						  for (int w = 0; w < s->width; ++w)
						    pxl[(int)((imgHeight - 1 - (s->y - rect.ymin)) * imgWidth
							      + s->x - rect.xmin + w)] =
						      Pixel32(outlineCol.r, outlineCol.g, outlineCol.b,
							      s->coverage);

						// Then loop over the regular glyph spans and blend them into
						// the image.
						for (Spans::iterator s = spans.begin();
						     s != spans.end(); ++s)
						  for (int w = 0; w < s->width; ++w)
						  {
							  Pixel32 &dst =
							    pxl[(int)((imgHeight - 1 - (s->y - rect.ymin)) * imgWidth
								      + s->x - rect.xmin + w)];
							  Pixel32 src = Pixel32(fontCol.r, fontCol.g, fontCol.b,
										s->coverage);
							  dst.r = (int)(dst.r + ((src.r - dst.r) * src.a) / 255.0f);
							  dst.g = (int)(dst.g + ((src.g - dst.g) * src.a) / 255.0f);
							  dst.b = (int)(dst.b + ((src.b - dst.b) * src.a) / 255.0f);
							  dst.a = MIN(255, dst.a + src.a);
						  }

						// Dump the image to disk.
						WriteTGA(fileName, pxl, imgWidth, imgHeight);

						delete [] pxl;
					}
				}
Exemplo n.º 2
0
void stroker::init(double radius)
{
    FT_Stroker_Set(s_, static_cast<FT_Fixed>(radius * (1<<6)),
                   FT_STROKER_LINECAP_ROUND,
                   FT_STROKER_LINEJOIN_ROUND,
                   0);
}
Exemplo n.º 3
0
inline FT_Error fontRenderClass::getGlyphImage(FTC_Image_Desc *font, FT_ULong glyph_index, FT_Glyph *glyph, FT_Glyph *borderglyph, int bordersize)
#endif
{
	FT_Glyph image;
	FT_Error err = FTC_ImageCache_Lookup(imageCache, font, glyph_index, &image, NULL);
	if (err) return err;

	if (glyph)
	{
		err = FT_Glyph_Copy(image, glyph);
		if (err) return err;
	}

	if (borderglyph && bordersize)
	{
		err = FT_Glyph_Copy(image, borderglyph);
		if (err) return err;
		if (bordersize != strokerRadius)
		{
			strokerRadius = bordersize;
			FT_Stroker_Set(stroker, strokerRadius, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
		}
		err = FT_Glyph_Stroke(borderglyph, stroker, 1);
	}
	return err;
}
Exemplo n.º 4
0
/**
 * \brief Change border width
 *
 * \param render_priv renderer state object
 * \param info glyph state object
 */
void change_border(ASS_Renderer *render_priv, double border_x, double border_y)
{
    int bord = 64 * border_x * render_priv->border_scale;

    if (bord > 0 && border_x == border_y) {
        if (!render_priv->state.stroker) {
            int error;
            error =
                FT_Stroker_New(render_priv->ftlibrary,
                               &render_priv->state.stroker);
            if (error) {
                ass_msg(render_priv->library, MSGL_V,
                        "failed to get stroker");
                render_priv->state.stroker = 0;
            }
            render_priv->state.stroker_radius = -1.0;
        }
        if (render_priv->state.stroker && render_priv->state.stroker_radius != bord) {
            FT_Stroker_Set(render_priv->state.stroker, bord,
                           FT_STROKER_LINECAP_ROUND,
                           FT_STROKER_LINEJOIN_ROUND, 0);
            render_priv->state.stroker_radius = bord;
        }
    } else {
        FT_Stroker_Done(render_priv->state.stroker);
        render_priv->state.stroker = 0;
    }
}
Exemplo n.º 5
0
	void Glyph::SetOutline(FT_Library& library, int outlineThickness)
	{
		_error = FT_Stroker_New(library, &_stroker);
		if (_error)
			return;

		FT_Stroker_Set(_stroker, outlineThickness * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);

		_error = FT_Glyph_StrokeBorder(&_glyph, _stroker, false, true);
		if (_error)
			return;


		FT_Raster_Params params;
		memset(&params, 0, sizeof(params));

		params.target = 0;
		params.flags = FT_RASTER_FLAG_DIRECT | FT_RASTER_FLAG_AA;
		params.user = this;
		params.gray_spans = Glyph::SpanCallback;

		FT_OutlineGlyph outlineGlyph = reinterpret_cast<FT_OutlineGlyph>(_glyph);

		_error = FT_Outline_Render(library, &outlineGlyph->outline, &params);
		if (_error)
			return;
	}
JNIEXPORT void JNICALL Java_com_badlogic_gdx_graphics_g2d_freetype_FreeType_00024Stroker_set(JNIEnv* env, jclass clazz, jlong stroker, jint radius, jint lineCap, jint lineJoin, jint miterLimit) {


//@line:789

			FT_Stroker_Set((FT_Stroker)stroker, radius, (FT_Stroker_LineCap)lineCap, (FT_Stroker_LineJoin)lineJoin, miterLimit);
		

}
Exemplo n.º 7
0
void SubtitleRenderer::
initialize_fonts(const std::string& font_path, float font_size) {
  ENFORCE(!FT_Init_FreeType(&ft_library_));
  ENFORCE2(!FT_New_Face(ft_library_, font_path.c_str(), 0, &ft_face_),
           "Unable to open font");
  ENFORCE(!FT_Set_Pixel_Sizes(ft_face_, 0, font_size*screen_height_));

  auto get_bbox = [this](char32_t cp) {
    auto glyph_index = FT_Get_Char_Index(ft_face_, cp);
    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);};
    FT_BBox bbox;
    FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox);
    return bbox;
  };

  constexpr float padding_factor = 0.05f;
  int y_min = get_bbox('g').yMin;
  int y_max = get_bbox('M').yMax;
  y_max += -y_min*0.7f;
  line_height_ = y_max - y_min;
  const int v_padding = line_height_*padding_factor + 0.5f;
  line_height_ += v_padding*2;
  box_offset_ = y_min-v_padding;
  box_h_padding_ = line_height_/5.0f + 0.5f;


  constexpr float border_thickness = 0.045f;
  ENFORCE(!FT_Stroker_New(ft_library_, &ft_stroker_));
  FT_Stroker_Set(ft_stroker_,
                 line_height_*border_thickness*64.0f,
                 FT_STROKER_LINECAP_ROUND,
                 FT_STROKER_LINEJOIN_ROUND,
                 0);

  vgSeti(VG_FILTER_FORMAT_LINEAR, VG_TRUE);
  assert(!vgGetError());

  vgSeti(VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_NONANTIALIASED);
  assert(!vgGetError());

  auto create_vg_font = [](VGFont& font) {
    font = vgCreateFont(128);
    ENFORCE(font);
  };

  create_vg_font(vg_font_);
  create_vg_font(vg_font_border_);
}
Exemplo n.º 8
0
void SubtitleRenderer::
initialize_fonts(const std::string& font_path,
                 const std::string& italic_font_path,
                 unsigned int font_size) {
  ENFORCE(!FT_Init_FreeType(&ft_library_));
  ENFORCE2(!FT_New_Face(ft_library_, font_path.c_str(), 0, &ft_face_),
           "Unable to open font");
  ENFORCE2(!FT_New_Face(ft_library_, italic_font_path.c_str(), 0, &ft_face_italic_),
           "Unable to open italic font");
  ENFORCE(!FT_Set_Pixel_Sizes(ft_face_, 0, font_size));
  ENFORCE(!FT_Set_Pixel_Sizes(ft_face_italic_, 0, font_size));

  auto get_bbox = [this](char32_t cp) {
    auto glyph_index = FT_Get_Char_Index(ft_face_, cp);
    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);};
    FT_BBox bbox;
    FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox);
    return bbox;
  };

  constexpr float padding_factor = 0.05f;
  int y_min = get_bbox('g').yMin;
  int y_max = get_bbox('M').yMax;
  y_max += -y_min*0.7f;
  line_height_ = y_max - y_min;
  const int v_padding = line_height_*padding_factor + 0.5f;
  line_height_ += v_padding*2;
  box_offset_ = y_min-v_padding;
  box_h_padding_ = line_height_/5.0f + 0.5f;


  constexpr float border_thickness = 0.044f;
  ENFORCE(!FT_Stroker_New(ft_library_, &ft_stroker_));
  FT_Stroker_Set(ft_stroker_,
                 line_height_*border_thickness*64.0f,
                 FT_STROKER_LINECAP_ROUND,
                 FT_STROKER_LINEJOIN_ROUND,
                 0);
}
Exemplo n.º 9
0
/**
 * \brief Change border width
 * negative value resets border to style value
 */
void change_border(ASS_Renderer *render_priv, double border_x,
                   double border_y)
{
    int bord;
    if (!render_priv->state.font)
        return;

    if (border_x < 0 && border_y < 0) {
        if (render_priv->state.style->BorderStyle == 1 ||
            render_priv->state.style->BorderStyle == 3)
            border_x = border_y = render_priv->state.style->Outline;
        else
            border_x = border_y = 1.;
    }

    render_priv->state.border_x = border_x;
    render_priv->state.border_y = border_y;

    bord = 64 * border_x * render_priv->border_scale;
    if (bord > 0 && border_x == border_y) {
        if (!render_priv->state.stroker) {
            int error;
            error =
                FT_Stroker_New(render_priv->ftlibrary,
                               &render_priv->state.stroker);
            if (error) {
                ass_msg(render_priv->library, MSGL_V,
                        "failed to get stroker");
                render_priv->state.stroker = 0;
            }
        }
        if (render_priv->state.stroker)
            FT_Stroker_Set(render_priv->state.stroker, bord,
                           FT_STROKER_LINECAP_ROUND,
                           FT_STROKER_LINEJOIN_ROUND, 0);
    } else {
        FT_Stroker_Done(render_priv->state.stroker);
        render_priv->state.stroker = 0;
    }
}
Exemplo n.º 10
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;
  }
Exemplo n.º 11
0
static av_cold int init(AVFilterContext *ctx)
{
    int err;
    DrawTextContext *s = ctx->priv;
    Glyph *glyph;

    if (!s->fontfile && !CONFIG_LIBFONTCONFIG) {
        av_log(ctx, AV_LOG_ERROR, "No font filename provided\n");
        return AVERROR(EINVAL);
    }

    if (s->textfile) {
        if (s->text) {
            av_log(ctx, AV_LOG_ERROR,
                   "Both text and text file provided. Please provide only one\n");
            return AVERROR(EINVAL);
        }
        if ((err = load_textfile(ctx)) < 0)
            return err;
    }

    if (s->reload && !s->textfile)
        av_log(ctx, AV_LOG_WARNING, "No file to reload\n");

    if (s->tc_opt_string) {
        int ret = av_timecode_init_from_string(&s->tc, s->tc_rate,
                                               s->tc_opt_string, ctx);
        if (ret < 0)
            return ret;
        if (s->tc24hmax)
            s->tc.flags |= AV_TIMECODE_FLAG_24HOURSMAX;
        if (!s->text)
            s->text = av_strdup("");
    }

    if (!s->text) {
        av_log(ctx, AV_LOG_ERROR,
               "Either text, a valid file or a timecode must be provided\n");
        return AVERROR(EINVAL);
    }

#if CONFIG_LIBFRIBIDI
    if (s->text_shaping)
        if ((err = shape_text(ctx)) < 0)
            return err;
#endif

    if ((err = FT_Init_FreeType(&(s->library)))) {
        av_log(ctx, AV_LOG_ERROR,
               "Could not load FreeType: %s\n", FT_ERRMSG(err));
        return AVERROR(EINVAL);
    }

    err = load_font(ctx);
    if (err)
        return err;
    if (!s->fontsize)
        s->fontsize = 16;
    if ((err = FT_Set_Pixel_Sizes(s->face, 0, s->fontsize))) {
        av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n",
               s->fontsize, FT_ERRMSG(err));
        return AVERROR(EINVAL);
    }

    if (s->borderw) {
        if (FT_Stroker_New(s->library, &s->stroker)) {
            av_log(ctx, AV_LOG_ERROR, "Coult not init FT stroker\n");
            return AVERROR_EXTERNAL;
        }
        FT_Stroker_Set(s->stroker, s->borderw << 6, FT_STROKER_LINECAP_ROUND,
                       FT_STROKER_LINEJOIN_ROUND, 0);
    }

    s->use_kerning = FT_HAS_KERNING(s->face);

    /* load the fallback glyph with code 0 */
    load_glyph(ctx, NULL, 0);

    /* set the tabsize in pixels */
    if ((err = load_glyph(ctx, &glyph, ' ')) < 0) {
        av_log(ctx, AV_LOG_ERROR, "Could not set tabsize.\n");
        return err;
    }
    s->tabsize *= glyph->advance;

    if (s->exp_mode == EXP_STRFTIME &&
        (strchr(s->text, '%') || strchr(s->text, '\\')))
        av_log(ctx, AV_LOG_WARNING, "expansion=strftime is deprecated.\n");

    av_bprint_init(&s->expanded_text, 0, AV_BPRINT_SIZE_UNLIMITED);
    av_bprint_init(&s->expanded_fontcolor, 0, AV_BPRINT_SIZE_UNLIMITED);

    return 0;
}
Exemplo n.º 12
0
Arquivo: stroker.cpp Projeto: det/Twil
void Stroker::SetOptions(
    FT_Fixed radius, FT_Stroker_LineCap line_cap,
    FT_Stroker_LineJoin line_join, FT_Fixed miter_limit)
{
    FT_Stroker_Set(id_, radius, line_cap, line_join, miter_limit);
}
Exemplo n.º 13
0
bool CGUIFontTTFBase::Load(const std::string& strFilename, float height, float aspect, float lineSpacing, bool border)
{
  // we now know that this object is unique - only the GUIFont objects are non-unique, so no need
  // for reference tracking these fonts
  m_face = g_freeTypeLibrary.GetFont(strFilename, height, aspect, m_fontFileInMemory);

  if (!m_face)
    return false;

  /*
   the values used are described below

      XBMC coords                                     Freetype coords

                0  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _  bbox.yMax, ascender
                        A                 \
                       A A                |
                      A   A               |
                      AAAAA  pppp   cellAscender
                      A   A  p   p        |
                      A   A  p   p        |
   m_cellBaseLine  _ _A_ _A_ pppp_ _ _ _ _/_ _ _ _ _  0, base line.
                             p            \
                             p      cellDescender
     m_cellHeight  _ _ _ _ _ p _ _ _ _ _ _/_ _ _ _ _  bbox.yMin, descender

   */
  int cellDescender = std::min<int>(m_face->bbox.yMin, m_face->descender);
  int cellAscender  = std::max<int>(m_face->bbox.yMax, m_face->ascender);

  if (border)
  {
    /*
     add on the strength of any border - the non-bordered font needs
     aligning with the bordered font by utilising GetTextBaseLine()
     */
    FT_Pos strength = FT_MulFix( m_face->units_per_EM, m_face->size->metrics.y_scale) / 12;
    if (strength < 128)
      strength = 128;

    cellDescender -= strength;
    cellAscender  += strength;

    m_stroker = g_freeTypeLibrary.GetStroker();
    if (m_stroker)
      FT_Stroker_Set(m_stroker, strength, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
  }

  // scale to pixel sizing, rounding so that maximal extent is obtained
  float scaler  = height / m_face->units_per_EM;
  cellDescender = MathUtils::round_int(cellDescender * scaler - 0.5f);   // round down
  cellAscender  = MathUtils::round_int(cellAscender  * scaler + 0.5f);   // round up

  m_cellBaseLine = cellAscender;
  m_cellHeight   = cellAscender - cellDescender;

  m_height = height;

  delete(m_texture);
  m_texture = NULL;
  delete[] m_char;
  m_char = NULL;

  m_maxChars = 0;
  m_numChars = 0;

  m_strFilename = strFilename;

  m_textureHeight = 0;
  m_textureWidth = ((m_cellHeight * CHARS_PER_TEXTURE_LINE) & ~63) + 64;

  m_textureWidth = CBaseTexture::PadPow2(m_textureWidth);

  if (m_textureWidth > g_Windowing.GetMaxTextureSize())
    m_textureWidth = g_Windowing.GetMaxTextureSize();
  m_textureScaleX = 1.0f / m_textureWidth;

  // set the posX and posY so that our texture will be created on first character write.
  m_posX = m_textureWidth;
  m_posY = -(int)GetTextureLineHeight();

  // cache the ellipses width
  Character *ellipse = GetCharacter(L'.');
  if (ellipse) m_ellipsesWidth = ellipse->advance;

  return true;
}
Exemplo n.º 14
0
Arquivo: Font.cpp Projeto: 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;
}
Exemplo n.º 15
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;
}
Exemplo n.º 16
0
    // ----------------------------------------------- texture_font_load_glyphs ---
    size_t
    texture_font_load_glyphs( texture_font_t * self,
                              const wchar_t * charcodes )
    {
        size_t i, j, 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;
        FT_Int32 flags = 0;
        int ft_glyph_top = 0;
        int ft_glyph_left = 0;

        ivec4 region;
        size_t missed = 0;
        char pass;

        assert( self );
        assert( charcodes );


        width  = self->atlas->width;
        height = self->atlas->height;
        depth  = self->atlas->depth;

        if (!texture_font_get_face(self, &library, &face))
            return wcslen(charcodes);

        /* Load each glyph */
        for( i = 0; i < wcslen(charcodes); ++i ) {
            pass = 0;
            /* Check if charcode has been already loaded */
            for( j = 0; j < self->glyphs->size; ++j ) {
                glyph = *(texture_glyph_t **) vector_get( self->glyphs, j );
                // If charcode is -1, we don't care about outline type or thickness
                // if( (glyph->charcode == charcodes[i])) {
                if( (glyph->charcode == charcodes[i]) &&
                    ((charcodes[i] == (wchar_t)(-1) ) ||
                     ((glyph->outline_type == self->outline_type) &&
                      (glyph->outline_thickness == self->outline_thickness)) ))
                {
                    pass = 1;
                    break;
                }
            }

            if(pass)
                continue;

            flags = 0;
            ft_glyph_top = 0;
            ft_glyph_left = 0;
            glyph_index = FT_Get_Char_Index( face, charcodes[i] );
            // WARNING: We use texture-atlas depth to guess if user wants
            //          LCD subpixel rendering

            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 )
            {
                FT_Done_Face( face );
                FT_Done_FreeType( library );
                throw wcslen(charcodes)-i;
            }


            if( self->outline_type == 0 )
            {
                slot            = face->glyph;
                ft_bitmap       = slot->bitmap;
                ft_glyph_top    = slot->bitmap_top;
                ft_glyph_left   = slot->bitmap_left;
            }
            else
            {
                FT_Stroker stroker;
                FT_BitmapGlyph ft_bitmap_glyph;
                error = FT_Stroker_New( library, &stroker );
                if( error )
                {
                    FT_Done_Face( face );
                    FT_Stroker_Done( stroker );
                    FT_Done_FreeType( library );
					throw;
                }
                FT_Stroker_Set(stroker,
                                (int)(self->outline_thickness * HRES),
                                FT_STROKER_LINECAP_ROUND,
                                FT_STROKER_LINEJOIN_ROUND,
                                0);
                error = FT_Get_Glyph( face->glyph, &ft_glyph);
                if( error )
                {
                    FT_Done_Face( face );
                    FT_Stroker_Done( stroker );
                    FT_Done_FreeType( library );
					throw;
                }

                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 )
                {
                    FT_Done_Face( face );
                    FT_Stroker_Done( stroker );
                    FT_Done_FreeType( library );
					throw;
                }

                if( depth == 1)
                {
                    error = FT_Glyph_To_Bitmap( &ft_glyph, FT_RENDER_MODE_NORMAL, 0, 1);
                    if( error )
                    {
                        FT_Done_Face( face );
                        FT_Stroker_Done( stroker );
                        FT_Done_FreeType( library );
						throw;
                    }
                }
                else
                {
                    error = FT_Glyph_To_Bitmap( &ft_glyph, FT_RENDER_MODE_LCD, 0, 1);
                    if( error )
                    {
                        FT_Done_Face( face );
                        FT_Stroker_Done( stroker );
                        FT_Done_FreeType( library );
						throw;
                    }
                }
                ft_bitmap_glyph = (FT_BitmapGlyph) ft_glyph;
                ft_bitmap       = ft_bitmap_glyph->bitmap;
                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 / HRESf;
            glyph->advance_y = slot->advance.y / HRESf;

            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;
    }
Exemplo n.º 17
0
void EMSCRIPTEN_KEEPALIVE c_Stroker_set(long stroker, int radius, int lineCap, int lineJoin, int miterLimit) {
    FT_Stroker_Set((FT_Stroker)stroker, radius, (FT_Stroker_LineCap)lineCap, (FT_Stroker_LineJoin)lineJoin, miterLimit);
}
Exemplo n.º 18
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++ ) {
Exemplo n.º 19
0
const CFontGlyph *CFreetypeFontFace::PrepareChar(wchar_t character, bool& bGlyphRestFlag)
{
    bGlyphRestFlag = false;
    m_glyphMapLocker.lock();
    auto itr = m_glyphMap.find(character);
    CFreetypeFontGlyph *pGlyph = itr != m_glyphMap.end() ? down_cast<CFreetypeFontGlyph *>(itr->second) : nullptr;
    m_glyphMapLocker.unlock();

    if (!pGlyph)
    {
        float outlineWidth = GetBorderWeight() * GetScaleFactor();
        ApplyFTSize();
        FT_Face pFontFace = m_pFont->GetFontFace();
        BEATS_ASSERT(pFontFace != NULL);
        bool bFindCharacterGlyph = FT_Get_Char_Index(pFontFace, character) != 0;
        BEYONDENGINE_UNUSED_PARAM(bFindCharacterGlyph);
        BEATS_ASSERT(bFindCharacterGlyph, _T("Character %d can't be found in all font face!"), character);
        FT_Error err = FT_Load_Char(pFontFace, character, FT_LOAD_NO_BITMAP);
        BEYONDENGINE_UNUSED_PARAM(err);
        BEATS_ASSERT(!err);

        FT_GlyphSlot pGlyphSlot = pFontFace->glyph;
        BEATS_ASSERT(pGlyphSlot != NULL);
        int32_t nBorderAdvanceX = pGlyphSlot->metrics.horiAdvance >> FT_SHIFT_NUM;
        int32_t nBorderAdvanceY = m_nLineHeight + (uint32_t)ceil(outlineWidth * 2.0f);
        int32_t nFontAdvanceX = nBorderAdvanceX;
        int32_t nFontHeight = 0;
        int32_t nBorderOriginWidth = 0;
        int32_t nFontOriginWidth = 0;
        int32_t nBorderHeight = 0;
        FT_BBox borderBox;
        FT_BBox fontBox;
        int32_t x = 0, y = 0;
        if (pGlyphSlot->format == FT_GLYPH_FORMAT_OUTLINE)
        {
            FT_Library ftLib = CFont::GetLibrary();
            // Set up a stroker.
            FT_Stroker stroker;
            FT_Stroker_New(ftLib, &stroker);
            FT_Stroker_Set(stroker, (int32_t)(outlineWidth * 64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
            FT_Glyph pOutlineGlyph, pInnerGlyph;
            if (FT_Get_Glyph(pGlyphSlot, &pOutlineGlyph) == 0 && FT_Get_Glyph(pGlyphSlot, &pInnerGlyph) == 0)
            {
                FT_Glyph_StrokeBorder(&pOutlineGlyph, stroker, 0, 1);
                BEATS_ASSERT(pOutlineGlyph->format == FT_GLYPH_FORMAT_OUTLINE && pInnerGlyph->format == FT_GLYPH_FORMAT_OUTLINE);
                FT_Outline *pOutLine = &reinterpret_cast<FT_OutlineGlyph>(pOutlineGlyph)->outline;
                FT_Glyph_Get_CBox(pOutlineGlyph, FT_GLYPH_BBOX_GRIDFIT, &borderBox);
                FT_Glyph_Get_CBox(pInnerGlyph, FT_GLYPH_BBOX_GRIDFIT, &fontBox);

                nBorderOriginWidth = (borderBox.xMax - borderBox.xMin) >> FT_SHIFT_NUM;

                nFontOriginWidth = (fontBox.xMax - fontBox.xMin) >> FT_SHIFT_NUM;
                int32_t nBorderWidth = nextMOE(nBorderOriginWidth); // Because our GL_UNPACK_ALIGNMENT should be 8 here.
                nBorderHeight = (borderBox.yMax - borderBox.yMin) >> FT_SHIFT_NUM;
                nFontHeight = (fontBox.yMax - fontBox.yMin) >> FT_SHIFT_NUM;
                x = pGlyphSlot->metrics.horiBearingX >> FT_SHIFT_NUM;
                y = pGlyphSlot->metrics.horiBearingY >> FT_SHIFT_NUM;
                if(nBorderAdvanceX < x + nBorderOriginWidth) // It is true for most of the time, because border size always greater than nAdvanceX
                {
                    nBorderAdvanceX = x + nBorderOriginWidth;
                }
                if (nFontAdvanceX < x + nFontOriginWidth)
                {
                    nFontAdvanceX = nFontOriginWidth; 
                }
                if(m_uCurrX + x + nBorderWidth > PAGE_WIDTH)
                {
                    m_uCurrX = 0;
                    m_uCurrY += (nBorderAdvanceY + m_nBorderSpace);
                    if (m_uCurrY + nBorderAdvanceY > PAGE_HEIGHT)
                    {
                        BEATS_WARNING(false, "Freetype texture buffer overflow for %d glyphs, we will rebuild this texture buffer.", (uint32_t)m_glyphMap.size());
                        ResetGlyphs();
                        bGlyphRestFlag = true;
                        return nullptr;
                    }
                }

                int32_t nDataSize = nBorderWidth * nBorderHeight;
                float fBorderOffsetY = 1.0f; // Makes it look like a shadow.
                unsigned char* pBorderData = RenderFontDataToBmp(nBorderWidth, nBorderHeight, -borderBox.xMin, (int32_t)(-borderBox.yMin * fBorderOffsetY), pOutLine);

                FT_Outline *pInnerOutLine = &reinterpret_cast<FT_OutlineGlyph>(pInnerGlyph)->outline;
                unsigned char* pFontData = RenderFontDataToBmp(nBorderWidth, nBorderHeight, -borderBox.xMin, -borderBox.yMin, pInnerOutLine);

                unsigned char* pAllData = new unsigned char[nDataSize * 2];
                for (int32_t i = 0; i < nDataSize; ++i)
                {
                    pAllData[i * 2] = pBorderData[i];
                    pAllData[i * 2 + 1] = pFontData[i];
                }

                BEATS_ASSERT(m_pTexture.Get() != nullptr);
                GLint nX = MAX((int32_t)m_uCurrX + x, 0);
                GLint nY = MAX((int32_t)m_uCurrY + (m_nAscender - y), 0);
                SFontUpdateImageInfo* pImageInfo = new SFontUpdateImageInfo;
                pImageInfo->m_pTexture = m_pTexture;
                pImageInfo->m_nWidth = nBorderWidth;
                pImageInfo->m_nHeight = nBorderHeight;
                pImageInfo->m_x = nX;
                pImageInfo->m_y = nY;
                pImageInfo->m_pData = pAllData;
                m_fontUpdateImageCacheMutex.lock();
                m_fontUpdateImageCache.push_back(pImageInfo);
                m_fontUpdateImageCacheMutex.unlock();

                // Clean up afterwards.
                FT_Stroker_Done(stroker);
                FT_Done_Glyph(pOutlineGlyph);
                FT_Done_Glyph(pInnerGlyph);
                BEATS_SAFE_DELETE_ARRAY(pBorderData);
                BEATS_SAFE_DELETE_ARRAY(pFontData);
            }
Exemplo n.º 20
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;

    region.x=1;
    region.y=1;

#ifdef RENDERSTRING
    stringwidth=0;
    stringheight=0;
    stringshift=0;
#endif

    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;

#ifdef RENDERSTRING
        static size_t maxh=0;
        if (charcodes[i]==13) { stringshift+=maxh+1; region.x=1; }
        if (h>maxh) maxh=h;
        //region.y=stringshift+maxh-h+1+(h-ft_glyph_top);
        region.y=stringshift+maxh-ft_glyph_top+1;
       // if (stringshift+h+h-ft_glyph_top+1>stringheight) stringheight=stringshift+h+h-ft_glyph_top+1;
        if (region.y+h>stringheight) stringheight=region.y+h;
        if (region.x+w>stringwidth) stringwidth=region.x+w;
//        if (region.y>=height) { missed++; continue; }
//        if (region.x+w>=width) {missed++; continue; }
       // if (h+h-ft_glyph_top+1>=height) { missed++; continue; }
       // if (h+h-ft_glyph_top+2>=height) { missed++; continue; }
//        if (region.y+maxh>=height) { missed++; continue; }
#else
        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;
        }
#endif
        w = w - 1;
        h = h - 1;
        x = region.x;
        y = region.y;
        if (charcodes[i]!=13) {

#ifdef RENDERSTRING
     if (!(x<width)||!((x+w)<=width)||!(y<height)||!((y+h)<=height)) { missed++; continue; }
#endif

          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;

#ifdef RENDERSTRING
        if (charcodes[i]!=13) region.x+=(int)glyph->advance_x;
#endif

        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;
}
Exemplo n.º 21
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);
    }
Exemplo n.º 22
0
/*
 * Load the glyphs of a paragraph. When shaping with HarfBuzz the glyph indices
 * have already been determined at this point, as well as the advance values.
 */
static int LoadGlyphs( filter_t *p_filter, paragraph_t *p_paragraph,
                       bool b_use_glyph_indices, bool b_overwrite_advance )
{
    if( p_paragraph->i_size <= 0 || p_paragraph->i_runs_count <= 0 )
    {
        msg_Err( p_filter, "LoadGlyphs() invalid parameters. "
                 "Paragraph size: %d. Runs count %d", p_paragraph->i_size,
                 p_paragraph->i_runs_count );
        return VLC_EGENERIC;
    }

    filter_sys_t *p_sys = p_filter->p_sys;

    for( int i = 0; i < p_paragraph->i_runs_count; ++i )
    {
        run_desc_t *p_run = p_paragraph->p_runs + i;
        text_style_t *p_style = p_run->p_style;

        FT_Face p_face = 0;
        if( !p_run->p_face )
        {
            p_face = LoadFace( p_filter, p_style );
            if( !p_face )
            {
                p_face = p_sys->p_face;
                p_style = &p_sys->style;
                p_run->p_style = p_style;
            }
            p_run->p_face = p_face;
        }
        else
            p_face = p_run->p_face;

        if( p_sys->p_stroker )
        {
            double f_outline_thickness =
                var_InheritInteger( p_filter, "freetype-outline-thickness" ) / 100.0;
            f_outline_thickness = VLC_CLIP( f_outline_thickness, 0.0, 0.5 );
            int i_radius = ( p_style->i_font_size << 6 ) * f_outline_thickness;
            FT_Stroker_Set( p_sys->p_stroker,
                            i_radius,
                            FT_STROKER_LINECAP_ROUND,
                            FT_STROKER_LINEJOIN_ROUND, 0 );
        }

        for( int j = p_run->i_start_offset; j < p_run->i_end_offset; ++j )
        {
            int i_glyph_index;
            if( b_use_glyph_indices )
                i_glyph_index = p_paragraph->pi_glyph_indices[ j ];
            else
                i_glyph_index =
                    FT_Get_Char_Index( p_face, p_paragraph->p_code_points[ j ] );

            glyph_bitmaps_t *p_bitmaps = p_paragraph->p_glyph_bitmaps + j;

            if( FT_Load_Glyph( p_face, i_glyph_index,
                               FT_LOAD_NO_BITMAP | FT_LOAD_DEFAULT )
             && FT_Load_Glyph( p_face, i_glyph_index, FT_LOAD_DEFAULT ) )
            {
                p_bitmaps->p_glyph = 0;
                p_bitmaps->p_outline = 0;
                p_bitmaps->p_shadow = 0;
                p_bitmaps->i_x_advance = 0;
                p_bitmaps->i_y_advance = 0;
                continue;
            }

            if( ( p_style->i_style_flags & STYLE_BOLD )
                  && !( p_face->style_flags & FT_STYLE_FLAG_BOLD ) )
                FT_GlyphSlot_Embolden( p_face->glyph );
            if( ( p_style->i_style_flags & STYLE_ITALIC )
                  && !( p_face->style_flags & FT_STYLE_FLAG_ITALIC ) )
                FT_GlyphSlot_Oblique( p_face->glyph );

            if( FT_Get_Glyph( p_face->glyph, &p_bitmaps->p_glyph ) )
            {
                p_bitmaps->p_glyph = 0;
                p_bitmaps->p_outline = 0;
                p_bitmaps->p_shadow = 0;
                p_bitmaps->i_x_advance = 0;
                p_bitmaps->i_y_advance = 0;
                continue;
            }

            if( p_filter->p_sys->p_stroker )
            {
                p_bitmaps->p_outline = p_bitmaps->p_glyph;
                if( FT_Glyph_StrokeBorder( &p_bitmaps->p_outline,
                                           p_filter->p_sys->p_stroker, 0, 0 ) )
                    p_bitmaps->p_outline = 0;
            }

            if( p_filter->p_sys->style.i_shadow_alpha > 0 )
                p_bitmaps->p_shadow = p_bitmaps->p_outline ?
                                      p_bitmaps->p_outline : p_bitmaps->p_glyph;

            if( b_overwrite_advance )
            {
                p_bitmaps->i_x_advance = p_face->glyph->advance.x;
                p_bitmaps->i_y_advance = p_face->glyph->advance.y;
            }
        }
    }
    return VLC_SUCCESS;
}
Exemplo n.º 23
0
int createFont(FT_Face fontFace, FT_UInt size)
{
	initFreeTypeLibrary();

	VGfloat glyphOrigin[2];
	VGfloat escapement[2];

	FT_Stroker fontStroker;
	int error = FT_Stroker_New(freeTypeLibrary, &fontStroker);
	if (error) {
		logInfo(LOG_FREETYPE, "Error FT_Stroker_New.(error=%d)\n", error);
		return -1;
	}

	FT_Stroker_Set(fontStroker,
		 2*64.0f,  // Need to get the right value based on size.
		 FT_STROKER_LINECAP_ROUND,
		 FT_STROKER_LINEJOIN_ROUND,
		 0);

	VGFont tmpFont;
	struct fontListItem *tmpFontListItem = fontExists(fontFace, size);
	if (tmpFontListItem == NULL) {
		tmpFont = vgCreateFont(fontFace->num_glyphs);
		if (tmpFont == VG_INVALID_HANDLE) {
			logInfo(LOG_FREETYPE, "Error could not create vgCreateFont.\n");
			return -1;
		}

		tmpFontListItem = malloc(sizeof(struct fontListItem));
		tmpFontListItem->fontFace = fontFace;
		tmpFontListItem->size = size;
		tmpFontListItem->font = tmpFont;
		addToFontList(tmpFontListItem);
	}
	else {
		return 0;
	}

	error = FT_Set_Char_Size( fontFace, /* handle to face object */
					0, /* char_width in 1/64th of points */
					size*64, /* char_height in 1/64th of points */
					72, /* horizontal device resolution */
					72 ); /* vertical device resolution */

	if (error) {
		logInfo(LOG_FREETYPE, "Error FT_Set_Char_Size.(error=%d)\n", error);
		return -1;
	}

	int index;
	int counter = 0;
	FT_UInt charIndex;
	VGImage image = VG_INVALID_HANDLE;
	VGImage softenedImage;
	VGfloat blustStdDev;
	int padding;
	int image_width;
	int image_height;
	VGErrorCode vg_error;
	FT_Glyph glyph;

	logInfo(LOG_FREETYPE, "This font contains %ld glyphs.\n", fontFace->num_glyphs);

	for (index = 32; (index < 256) && (counter < fontFace->num_glyphs); index++) {
		counter++;
		charIndex = FT_Get_Char_Index(fontFace, index);

		logInfo(LOG_FREETYPE, "index=0x%x, charIndex=0x%x\n", index, charIndex);

		escapement[0] = 0;
		escapement[1] = 0;

		if (charIndex == 0) {
			vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement);
			logInfo(LOG_FREETYPE, "charindex== 0\n");
			continue;
		}

		error = FT_Load_Glyph(fontFace, charIndex, FT_LOAD_NO_HINTING);
		if (error) {
			vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement);
			logInfo(LOG_FREETYPE, "Error FT_Load_Glyph (error:%d)\n", error);
			continue;
		}

		error = FT_Get_Glyph(fontFace->glyph, &glyph);
		if (error) {
			vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement);
			logInfo(LOG_FREETYPE, "Error FT_Get_Glyph (error:%d)\n", error);
			continue;
		}

/*
		error = FT_Glyph_StrokeBorder(&glyph, fontStroker, 0, 1);
		if (error) {
			FT_Done_Glyph(glyph);
			vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement);
			logInfo(LOG_FREETYPE, "Error FT_Glyph_StrokeBorder (error:%d)\n", error);
			continue;
		}
*/

		error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, NULL, 1);
		if (error) {
			FT_Done_Glyph(glyph);
			vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement);
			logInfo(LOG_FREETYPE, "Error FT_Glyph_To_Bitmap (error:%d)\n", error);
			continue;
		}

		FT_BitmapGlyph bitGlyph = (FT_BitmapGlyph)glyph;
		FT_Bitmap bitmap = bitGlyph->bitmap;

		if (bitmap.width > 0 && bitmap.rows > 0) {
			blustStdDev = 0.6;
			padding = (3*blustStdDev + 0.5);
			image_width = bitmap.width + padding*2;
			image_height = bitmap.rows + padding*2;

			image = vgCreateImage(VG_A_8, image_width, image_height, VG_IMAGE_QUALITY_NONANTIALIASED);
			if (image == VG_INVALID_HANDLE) {
				FT_Done_Glyph(glyph);
				vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement);
				logInfo(LOG_FREETYPE, "vgCreateImage (error:%d)\n", vgGetError());
				continue;
			}

			if (bitmap.pitch > 0) {
				vgImageSubData(image,
					 bitmap.buffer + bitmap.pitch*(bitmap.rows-1),
					 -bitmap.pitch,
					 VG_A_8,
					 padding,
					 padding,
					 bitmap.width,
					 bitmap.rows);
			} else {
				vgImageSubData(image,
					 bitmap.buffer,
					 bitmap.pitch,
					 VG_A_8,
					 padding,
					 padding,
					 bitmap.width,
					 bitmap.rows);
			}
			vg_error = vgGetError();
			if (vg_error) {
				vgDestroyImage(image);
				FT_Done_Glyph(glyph);
				vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement);
				showVGErrorStr(vg_error, "vgImageSubData");
				continue;
			}

			softenedImage = vgCreateImage(VG_A_8,
							image_width,
							image_height,
							VG_IMAGE_QUALITY_NONANTIALIASED);
			if (softenedImage == VG_INVALID_HANDLE) {
				vgDestroyImage(image);
				FT_Done_Glyph(glyph);
				vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement);
				logInfo(LOG_FREETYPE, "vgCreateImage (error:%d)\n", vgGetError());
				continue;
			}

			// Even out hard and soft edges
			vgGaussianBlur(softenedImage, image, blustStdDev, blustStdDev, VG_TILE_FILL);
			vg_error = vgGetError();
			if (vg_error) {
				vgDestroyImage(softenedImage);
				vgDestroyImage(image);
				FT_Done_Glyph(glyph);
				vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement);
				showVGErrorStr(vg_error, "vgGaussianBlur");
				continue;
			}

			vgDestroyImage(image);
			image = softenedImage;

			glyphOrigin[0] = (VGfloat)(padding - bitGlyph->left);
			glyphOrigin[1] = (VGfloat)(padding + bitmap.rows - bitGlyph->top - 1);

		}
		else {
			logInfo(LOG_FREETYPE, "Error bitmap.width = %d, bitmap.rows = %d\n", bitmap.width, bitmap.rows);
		}

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

		vgSetGlyphToImage(tmpFont, index, image, glyphOrigin, escapement);
		vg_error = vgGetError();
		if (vg_error) {
			vgDestroyImage(softenedImage);
			vgDestroyImage(image);
			FT_Done_Glyph(glyph);
			vgSetGlyphToImage(tmpFont, index, VG_INVALID_HANDLE, escapement, escapement);
			showVGErrorStr(vg_error, "vgSetGlyphToImage");
			continue;
		}
		logInfo(LOG_FREETYPE, "Create glyph %d.\n", index);

		FT_Done_Glyph(glyph);

		if (image != VG_INVALID_HANDLE) {
			vgDestroyImage(image);
		}
	}

	return 0;
}