void SkScalerContext_FreeType_Base::emboldenOutline(FT_Face face, FT_Outline* outline)
{
    FT_Pos strength;
    strength = FT_MulFix(face->units_per_EM, face->size->metrics.y_scale)
               / 24;
    FT_Outline_Embolden(outline, strength);
}
Exemple #2
0
void FT_BOLD(FT_GlyphSlot slot)
{
    FT_Face     face = slot->face;
    FT_Pos      amount;

    if(slot->format != FT_GLYPH_FORMAT_OUTLINE)
      return;

    /* some reasonable strength */
    amount = FT_MulFix(face->units_per_EM,
                       face->size->metrics.y_scale ) / 18;
	(void)FT_Outline_Embolden( &slot->outline, amount);

    if ( slot->advance.x )
      slot->advance.x += amount;

    if ( slot->advance.y )
      slot->advance.y += amount;

    slot->metrics.width        += amount;
    slot->metrics.height       += amount;
    slot->metrics.horiBearingY += amount;
    slot->metrics.horiAdvance  += amount;
    slot->metrics.vertBearingX -= amount / 2;
    slot->metrics.vertBearingY += amount;
    slot->metrics.vertAdvance  += amount;
}
Exemple #3
0
  FT_GlyphSlot_Embolden( FT_GlyphSlot  slot )
  {
    FT_Library  library = slot->library;
    FT_Face     face    = FT_SLOT_FACE( slot );
    FT_Error    error;
    FT_Pos      xstr, ystr;


    if ( slot->format != FT_GLYPH_FORMAT_OUTLINE &&
         slot->format != FT_GLYPH_FORMAT_BITMAP )
      return;

    /* some reasonable strength */
    xstr = FT_MulFix( face->units_per_EM,
                      face->size->metrics.y_scale ) / 35;
    ystr = xstr;

    if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
    {
      error = FT_Outline_Embolden( &slot->outline, xstr );
      /* ignore error */

      /* this is more than enough for most glyphs; if you need accurate */
      /* values, you have to call FT_Outline_Get_CBox                   */
      xstr = xstr * 2;
      ystr = xstr;
    }
    else if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
    {
      xstr = FT_PIX_FLOOR( xstr );
      if ( xstr == 0 )
        xstr = 1 << 6;
      ystr = FT_PIX_FLOOR( ystr );

      error = FT_GlyphSlot_Own_Bitmap( slot );
      if ( error )
        return;

      error = FT_Bitmap_Embolden( library, &slot->bitmap, xstr, ystr );
      if ( error )
        return;
    }

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

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

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

    if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
      slot->bitmap_top += ystr >> 6;
  }
Exemple #4
0
const bool GDI2FT_RENDERER::generate_outline_glyph( FT_Glyph* glyph, WORD glyph_index, const FTC_Scaler scaler, FT_F26Dot6 embolden, bool is_italic ) const
/* --------------------------------------------------------------------------------
-------------------------------------------------------------------------------- */
{
	FT_Glyph cached_glyph;

	{
		GDI2FT_MUTEX mutex( GDI2FT_MUTEX::MUTEX_FREETYPE );

		if( FTC_ImageCache_LookupScaler( ft_glyph_cache, scaler, FT_LOAD_NO_BITMAP | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_CROP_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_TARGET_LIGHT, glyph_index, &cached_glyph, NULL ) != 0 )
			return NULL;
	}

	if( cached_glyph->format != FT_GLYPH_FORMAT_OUTLINE )
		return NULL;

	const bool oblique = ( ( context->outline_metrics->otmTextMetrics.tmItalic != 0 ) && !is_italic );

	if( oblique || embolden )
	{
		FT_Glyph_Copy( cached_glyph, glyph );
		FT_Outline* glyph_outline = &( reinterpret_cast<FT_OutlineGlyph>( *glyph )->outline );

		if( oblique )
		{
			FT_Matrix oblique_mat = { static_cast<FT_Pos>( 65536 ), static_cast<FT_Pos>( 19661 ), 0, static_cast<FT_Pos>( 65536 ) };
			FT_Outline_Transform( glyph_outline, &oblique_mat );
		}

		if( embolden )
			FT_Outline_Embolden( glyph_outline, embolden );

		return true;
	}
	else
		*glyph = cached_glyph;

	return false;
}
/*
 * Class:     FreetypeFont
 * Method:    loadGlyph0
 * Signature: (JI)V
 */
JNIEXPORT void JNICALL Java_sage_FreetypeFont_loadGlyph0
  (JNIEnv *env, jobject jo, jlong fontPtr, jint glyphCode)
{
	//FT_Face face = (FT_Face) facePtr;
	FTDataStruct* fontData = (FTDataStruct*)(intptr_t) fontPtr;
	FT_Activate_Size(fontData->sizePtr);
	int error = FT_Load_Glyph(fontData->facePtr, glyphCode, FT_LOAD_FORCE_AUTOHINT);
	if ((fontData->style & FT_STYLE_FLAG_BOLD) != 0)
	{
		// Apply bold effect
		if (fontData->facePtr->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
		{
			/* some reasonable strength */
			FT_Pos strength = FT_MulFix(fontData->facePtr->units_per_EM,
				fontData->facePtr->size->metrics.y_scale ) / 42;

			FT_BBox bbox_before, bbox_after;
			// The bounding box code was what XBMC was using to do this calculation; but the
			// examples in the freetype library use the *4 math below which then doesn't clip
			// the text when we render it.
//			FT_Outline_Get_CBox(&fontData->facePtr->glyph->outline, &bbox_before);
			FT_Outline_Embolden(&fontData->facePtr->glyph->outline, strength);  // ignore error
//			FT_Outline_Get_CBox(&fontData->facePtr->glyph->outline, &bbox_after);

//			FT_Pos dx = bbox_after.xMax - bbox_before.xMax;
//			FT_Pos dy = bbox_after.yMax - bbox_before.yMax;
FT_Pos dx = strength * 4;
FT_Pos dy = dx;
			if (fontData->facePtr->glyph->advance.x)
				fontData->facePtr->glyph->advance.x += dx;

			if (fontData->facePtr->glyph->advance.y)
				fontData->facePtr->glyph->advance.y += dy;

			fontData->facePtr->glyph->metrics.width        += dx;
			fontData->facePtr->glyph->metrics.height       += dy;
			fontData->facePtr->glyph->metrics.horiBearingY += dy;
			fontData->facePtr->glyph->metrics.horiAdvance  += dx;
			fontData->facePtr->glyph->metrics.vertBearingX -= dx / 2;
			fontData->facePtr->glyph->metrics.vertBearingY += dy;
			fontData->facePtr->glyph->metrics.vertAdvance  += dy;
		}
	}
	if ((fontData->style & FT_STYLE_FLAG_ITALIC) != 0)
	{
		// Apply italics effect
		if (fontData->facePtr->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
		{
			/* For italic, simply apply a shear transform, with an angle */
			/* of about 12 degrees.                                      */

			FT_Matrix    transform;
			transform.xx = 0x10000L;
			transform.yx = 0x00000L;

			transform.xy = 0x06000L;
			transform.yy = 0x10000L;

			FT_BBox bbox_before, bbox_after;
			FT_Outline_Get_CBox(&fontData->facePtr->glyph->outline, &bbox_before);
			FT_Outline_Transform(&fontData->facePtr->glyph->outline, &transform);
			FT_Outline_Get_CBox(&fontData->facePtr->glyph->outline, &bbox_after);

			FT_Pos dx = bbox_after.xMax - bbox_before.xMax;
			FT_Pos dy = bbox_after.yMax - bbox_before.yMax;

			fontData->facePtr->glyph->metrics.width        += dx;
			fontData->facePtr->glyph->metrics.height       += dy;
		}
	}
}
Exemple #6
0
bool Font::insertGlyph(Char character) {
	
	if(!m_size) {
		insertPlaceholderGlyph(character);
		return false;
	}
	
	FT_UInt glyphIndex = FT_Get_Char_Index(m_size->face, character);
	if(!glyphIndex) {
		insertPlaceholderGlyph(character);
		return false;
	}
	
	FT_Int32 flags = FT_LOAD_TARGET_LIGHT;
	if(m_info.weight != 0) {
		flags |= FT_LOAD_FORCE_AUTOHINT;
	}
	if(FT_Load_Glyph(m_size->face, glyphIndex, flags)) {
		insertPlaceholderGlyph(character);
		return false;
	}
	
	FT_GlyphSlot ftGlyph = m_size->face->glyph;
	
	if(m_info.weight != 0 && ftGlyph->format == FT_GLYPH_FORMAT_OUTLINE) {
		FT_Pos strength = FT_MulFix(m_size->face->units_per_EM, m_size->metrics.y_scale) / 24 * m_info.weight / 4;
		FT_Outline_Embolden(&ftGlyph->outline, strength);
	}
	
	if(FT_Render_Glyph(ftGlyph, FT_RENDER_MODE_NORMAL)) {
		insertPlaceholderGlyph(character);
		return false;
	}
	
	// Fill in info for this glyph.
	Glyph & glyph = m_glyphs[character];
	glyph.index = glyphIndex;
	glyph.size.x = ftGlyph->bitmap.width;
	glyph.size.y = ftGlyph->bitmap.rows;
	glyph.advance.x = float(ftGlyph->linearHoriAdvance) / 65536.f;
	glyph.advance.y = float(ftGlyph->linearVertAdvance) / 65536.f;
	glyph.lsb_delta = ftGlyph->lsb_delta;
	glyph.rsb_delta = ftGlyph->rsb_delta;
	glyph.draw_offset.x = ftGlyph->bitmap_left;
	glyph.draw_offset.y = ftGlyph->bitmap_top - ftGlyph->bitmap.rows;
	glyph.uv_start = Vec2f(0.f);
	glyph.uv_end = Vec2f(0.f);
	glyph.texture = 0;
	
	// Some glyphs like spaces have a size of 0...
	if(glyph.size.x != 0 && glyph.size.y != 0) {
		
		Image imgGlyph;
		imgGlyph.create(size_t(glyph.size.x), size_t(glyph.size.y), Image::Format_A8);
		
		FT_Bitmap & srcBitmap = ftGlyph->bitmap;
		arx_assert(srcBitmap.pitch >= 0);
		arx_assert(unsigned(srcBitmap.pitch) == unsigned(srcBitmap.width));
		
		// Copy pixels
		unsigned char * src = srcBitmap.buffer;
		unsigned char * dst = imgGlyph.getData();
		memcpy(dst, src, glyph.size.x * glyph.size.y);
		
		Vec2i offset;
		if(!m_textures->insertImage(imgGlyph, glyph.texture, offset)) {
			LogWarning << "Could not upload glyph for character U+" << std::hex << character
			           << " (" << util::encode<util::UTF8>(character) << ") in font "
			           << m_info.name;
			insertPlaceholderGlyph(character);
			return false;
		}
		
		// Compute UV mapping for each glyph.
		const float textureSize = float(m_textures->getTextureSize());
		glyph.uv_start = Vec2f(offset) / Vec2f(textureSize);
		glyph.uv_end = Vec2f(offset + glyph.size) / Vec2f(textureSize);
		
	}
	
	return true;
}
/**
 * Renders or Measures some Text
 *
 * @param aContext      void context
 * @param aBitmap       pointer to bitmap ( if not provided will just measure )
 * @param aBitmapWidth  width of the provided bitmap
 * @param aBitmapHeight height of the provided bitmap
 * @param aHarfBuzz     Harfbuzz structure containing glyph indices
 * @param aIndex        start with this character index
 * @param aCount        render / measure aCount characters
 * @param aPen_x        pointer to pen position that will be updated ( optional )
 * @param aPen_y        pointer to pen position that will be updated ( optional )
 * @param aBBox         pointer to Bounding Box that will be updated ( optional )
 * @param resetBox      if non-zero´Bounding Box will be reset before accumulating
 * @param isArabic      if non-zero will treat as right to left
 * @param outlineStage  0 = draw ouside, 1 = draw inside of synth outline style
 */
 static int PalFont_RenderHarfBuzz( void         *aContext,
                                   unsigned int *aBitmap,
                                   int           aBitmapWidth,
                                   int           aBitmapHeight,
                                   HarfBuzz_t   *aHarfBuzz,
                                   int           aIndex,
                                   int           aLength,
                                   int          *aPen_x,
                                   int          *aPen_y,
                                   PalFont_BBox_t*aBBox,
                                   int           resetBox,
                                   int           isArabic,
                                   int           outlineStage ) {


    printf("PalFont_RenderHarfBuzz: context is %p\n", aContext);
   ft_Context_t  *ftContext = FT_CONTEXT( aContext );
   FT_GlyphSlot   slot;
   PalFont_BBox_t theBBox;
   unsigned int   i, j = outlineStage, k;
   int            thePen_x        =  0;
   int            thePen_y        =  0;
   FT_UInt        aGlyphIndex     =  0;
   FT_UInt        aPrevGlyphIndex =  0;

   if ( ftContext == NULL ) {
      return -1;
   }

   if ( aPen_x != NULL ) {
     thePen_x = *aPen_x;
   }

   if ( aPen_y != NULL ) {
     thePen_y = *aPen_y;
   }

   slot = ftContext->m_face->glyph;

   if ( resetBox != 0 ) {
      /* make an invalid bounding box to start with */
      theBBox.xMin = INT_MAX;
      theBBox.yMin = INT_MAX;
      theBBox.xMax = INT_MIN;
      theBBox.yMax = INT_MIN;
   }

   for ( i = 0; i < aHarfBuzz->n_Chars;
         thePen_x += ( int )( ( ( double )ftContext->m_Matrix.xx *
                                ( double )slot->advance.x +
                                ( double )ftContext->m_Matrix.xy *
                                ( double )slot->advance.y ) / 65536.0 ),
         thePen_y += ( int )( ( ( double )ftContext->m_Matrix.yy *
                                ( double )slot->advance.y +
                                ( double )ftContext->m_Matrix.yx *
                                ( double )slot->advance.x ) / 65536.0 ),
         aPrevGlyphIndex = aGlyphIndex,
         i++ ) {

      FT_Glyph   aGlyph;
      int        y;
      int        x;

      k = isArabic ? ( aHarfBuzz->n_Chars - i - 1 ) : i;

      aGlyphIndex = aHarfBuzz->out_glyphs[ k ];

      /* apply kerning if there is any */
      if ( aPrevGlyphIndex != 0 && aGlyphIndex != 0 ) {
         FT_Vector delta;

         /* ignore errors */
         if ( FT_Get_Kerning( ftContext->m_face,
                              aPrevGlyphIndex,
                              aGlyphIndex,
                              FT_KERNING_DEFAULT,
                              &delta ) == 0 ) {
            thePen_x += ( int )( ( ( double )ftContext->m_Matrix.xx *
                                   ( double )delta.x ) / ( 65536.0 ) );
         }
      }

      /* load glyph image into the slot (erase previous one) */
      if ( FT_Load_Glyph( ftContext->m_face,
                           aGlyphIndex,
                           FT_LOAD_DEFAULT ) != 0 ) {
         continue; /* ignore errors */
      }

      // if we are synthesising italic then shear outline
      if ( ftContext->m_Synth & SynthItalic ) {
         FT_Matrix m;
         m.xx = 65536;
         m.yy = 65536;
         m.xy = 19660;
         m.yx = 0;
         FT_Outline_Transform( &slot->outline, &m );
      }

      /* if we are doing first pass of two color then fatten */
      if ( ( ftContext->m_Synth & SynthTwoColor ) && j == 0 ) {
         if ( FT_Outline_Embolden( &slot->outline,
                                    ftContext->m_StrokeWidth << 2 ) != 0 ) {
            continue;
         }
      }

      // if we are doing second pass of two color then translate
      if ( ( ftContext->m_Synth & SynthTwoColor ) && j == 1 ) {
         FT_Outline_Translate( &slot->outline,
                                ftContext->m_StrokeWidth * 2,
                                ftContext->m_StrokeWidth * 2 );
      }

      /* if we are synthesising bold then perform fattening operation */
      if ( ftContext->m_Synth & SynthBold ) {
         if ( FT_Outline_Embolden( &slot->outline,
                                    ftContext->m_Boldness << 1 ) != 0 ) {
            continue;
         }
      }

      /* if we are synthesising stroke font then stroke it */
      if ( ftContext->m_Synth & SynthStroke ) {
         if ( ft_OutlineStroke( ftContext->m_library,
                           &slot->outline, ftContext->m_StrokeWidth ) != 0 ) {
            continue;
         }
      }

      FT_Outline_Transform( &slot->outline, &ftContext->m_Matrix );

      /* if bounding box is supplied then
         accumulate the glyphs bounding boxes */
      if ( aBBox != NULL )  {

         FT_BBox theCBox;
         FT_Outline_Get_CBox( &slot->outline, &theCBox );

         theCBox.xMin += thePen_x;
         theCBox.xMax += thePen_x;
         theCBox.yMin += thePen_y;
         theCBox.yMax += thePen_y;

         if ( theCBox.xMin < theBBox.xMin ) {
            theBBox.xMin = theCBox.xMin;
         }
         if ( theCBox.yMin < theBBox.yMin ) {
            theBBox.yMin = theCBox.yMin;
         }
         if ( theCBox.xMax > theBBox.xMax ) {
            theBBox.xMax = theCBox.xMax;
         }
         if ( theCBox.yMax > theBBox.yMax ) {
            theBBox.yMax = theCBox.yMax;
         }
      }

      /* if bitmap is supplied then draw into it */
      if ( aBitmap == NULL ) {
         continue;
      }

      /* convert to an anti-aliased bitmap */
      if ( FT_Render_Glyph( slot, FT_RENDER_MODE_NORMAL ) != 0 )
         continue;

      /* render the bitmap...  */
      for ( y = 0; y < slot->bitmap.rows; y++ ) {
         for ( x = 0; x < slot->bitmap.width; x++ ) {
            unsigned int by = (-(thePen_y>>6)-slot->bitmap_top+y+aBitmapHeight);
            unsigned int bx = (thePen_x>>6)+slot->bitmap_left+x;
            if ( bx < aBitmapWidth && by < aBitmapHeight ) {
               unsigned int *pixel = &aBitmap[ by * aBitmapWidth + bx ];
               *pixel = blend( *pixel,
               j ? ftContext->m_fontColor : ftContext->m_fontColorTwo,
               slot->bitmap.buffer[y*slot->bitmap.pitch+x],
               j ? ftContext->m_Alpha1 : ftContext->m_Alpha2 );
            }
         }
      }
   }

   if ( aBBox != NULL ) {
      *aBBox = theBBox;
   }
   if ( aPen_x != NULL ) {
      *aPen_x = thePen_x;
   }
   if ( aPen_y != NULL ) {
      *aPen_y = thePen_y;
   }
   return 0;
}
				bool ExtractGlyph(unsigned int characterSize, char32_t character, UInt32 style, FontGlyph* dst) override
				{
					#ifdef NAZARA_DEBUG
					if (!dst)
					{
						NazaraError("Glyph destination cannot be null");
						return false;
					}
					#endif

					SetCharacterSize(characterSize);

					if (FT_Load_Char(m_face, character, FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL) != 0)
					{
						NazaraError("Failed to load character");
						return false;
					}

					FT_GlyphSlot& glyph = m_face->glyph;

					const FT_Pos boldStrength = 2 << 6;

					bool embolden = (style & TextStyle_Bold);

					dst->advance = (embolden) ? boldStrength >> 6 : 0;

					if (embolden && glyph->format == FT_GLYPH_FORMAT_OUTLINE)
					{
						// http://www.freetype.org/freetype2/docs/reference/ft2-outline_processing.html#FT_Outline_Embolden
						FT_Outline_Embolden(&glyph->outline, boldStrength);
						embolden = false;
					}

					// http://www.freetype.org/freetype2/docs/reference/ft2-glyph_management.html#FT_Glyph_To_Bitmap
					// Conversion du glyphe vers le format bitmap
					// Cette fonction ne fait rien dans le cas où le glyphe est déjà un bitmap
					if (FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL) != 0)
					{
						NazaraError("Failed to convert glyph to bitmap");
						return false;
					}

					// Dans le cas où nous voulons des caractères gras mais que nous n'avons pas pu agir plus tôt
					// nous demandons à FreeType d'agir directement sur le bitmap généré
					if (embolden)
					{
						// http://www.freetype.org/freetype2/docs/reference/ft2-bitmap_handling.html#FT_Bitmap_Embolden
						// "If you want to embolden the bitmap owned by a FT_GlyphSlot_Rec, you should call FT_GlyphSlot_Own_Bitmap on the slot first"
						FT_GlyphSlot_Own_Bitmap(glyph);
						FT_Bitmap_Embolden(s_library, &glyph->bitmap, boldStrength, boldStrength);
					}

					dst->advance += glyph->metrics.horiAdvance >> 6;
					dst->aabb.x = glyph->metrics.horiBearingX >> 6;
					dst->aabb.y = -(glyph->metrics.horiBearingY >> 6); // Inversion du repère
					dst->aabb.width = glyph->metrics.width >> 6;
					dst->aabb.height = glyph->metrics.height >> 6;

					unsigned int width = glyph->bitmap.width;
					unsigned int height = glyph->bitmap.rows;

					if (width > 0 && height > 0)
					{
						dst->image.Create(ImageType_2D, PixelFormatType_A8, width, height);
						UInt8* pixels = dst->image.GetPixels();

						const UInt8* data = glyph->bitmap.buffer;

						// Selon la documentation FreeType, le glyphe peut être encodé en format A8 (huit bits d'alpha par pixel)
						// ou au format A1 (un bit d'alpha par pixel).
						// Cependant dans un cas comme dans l'autre, il nous faut gérer le pitch (les données peuvent ne pas être contigues)
						// ainsi que le padding dans le cas du format A1 (Chaque ligne prends un nombre fixe d'octets)
						if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
						{
							// Format A1
							for (unsigned int y = 0; y < height; ++y)
							{
								for (unsigned int x = 0; x < width; ++x)
									*pixels++ = (data[x/8] & ((1 << (7 - x%8)) ? 255 : 0));

								data += glyph->bitmap.pitch;
							}
						}
						else
						{
							// Format A8
							if (glyph->bitmap.pitch == static_cast<int>(width*sizeof(UInt8))) // Pouvons-nous copier directement ?
								dst->image.Update(glyph->bitmap.buffer);
							else
							{
								for (unsigned int y = 0; y < height; ++y)
								{
									std::memcpy(pixels, data, width*sizeof(UInt8));
									data += glyph->bitmap.pitch;
									pixels += width*sizeof(UInt8);
								}
							}
						}
					}
					else
						dst->image.Destroy(); // On s'assure que l'image ne contient alors rien

					return true;
				}
FT_Error ft_OutlineStroke( FT_Library   library,
                           FT_Outline  *Outline,
                           int          Thickness )
{
  FT_Error   err = 0;
  FT_Outline OutlineReversed;
  FT_Outline OutlineFattened;
  FT_Outline OutlineStroke;

  if ( Outline == NULL ) {
     goto failure;
  }

  err = FT_Outline_New( library,
                        Outline->n_points,
                        Outline->n_contours,
                        &OutlineReversed );
  if ( err != 0 ) {
     goto failure;
  }

  err = FT_Outline_New( library,
                        Outline->n_points,
                        Outline->n_contours,
                        &OutlineFattened );
  if ( err != 0 ) {
     goto failure;
  }

  err = FT_Outline_Copy( Outline, &OutlineReversed );
  if ( err != 0 ) {
     goto failure;
  }

  err = FT_Outline_Copy( Outline, &OutlineFattened );
  if ( err != 0 ) {
     goto failure;
  }

  err = FT_Outline_New( library,
                        Outline->n_points   * 2,
                        Outline->n_contours * 2,
                        &OutlineStroke );
  if ( err != 0 ) {
     goto failure;
  }

  /* Perform fattening operation */
  err = FT_Outline_Embolden( &OutlineFattened, Thickness << 1 );
  if ( err != 0 ) {
     goto failure;
  }

  /* Perform reversal operation */
  ft_OutlineReverse( Outline,
                     &OutlineReversed );

  FT_Outline_Translate( &OutlineReversed, Thickness, Thickness );

  /* Merge outlines */
  ft_OutlineMerge( &OutlineFattened,
                   &OutlineReversed,
                   &OutlineStroke );

  /* delete temporary and input outline */
  err = FT_Outline_Done( library, &OutlineReversed );
  if ( err != 0 ) {
     goto failure;
  }

  err = FT_Outline_Done( library, &OutlineFattened );
  if ( err != 0 ) {
     goto failure;
  }

  err = FT_Outline_Done( library, Outline );
  if ( err != 0 ) {
     goto failure;
  }

  /* finally copy the outline - its not clear from ft docs if this
     does the right thing but i _think_ its correct */
  memcpy( Outline, &OutlineStroke, sizeof( FT_Outline ) );

  return 0;

failure:

   return err;
}
Exemple #10
0
void FontRenderer::rasterize() {
    clear_bitmaps();
    if (!m_ft_face) {
        return;
    }


    qDebug() << " begin rasterize_font ";



    if (m_config->italic()!=0) {
        FT_Matrix matrix;
        const float angle = (-M_PI*m_config->italic()) / 180.0f;
        matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
        matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
        matrix.yx = (FT_Fixed)( 0/*sin( angle )*/ * 0x10000L );
        matrix.yy = (FT_Fixed)( 1/*cos( angle )*/ * 0x10000L );
        FT_Set_Transform(m_ft_face,&matrix,0);
    } else {
        FT_Set_Transform(m_ft_face,0,0);
    }


    /// fill metrics
    if (FT_IS_SCALABLE(m_ft_face)) {
        m_rendered.metrics.ascender = m_ft_face->size->metrics.ascender / 64;
        m_rendered.metrics.descender = m_ft_face->size->metrics.descender/ 64;
        m_rendered.metrics.height = m_ft_face->size->metrics.height/ 64;
    } else {
        m_rendered.metrics.ascender = m_ft_face->ascender;
        m_rendered.metrics.descender = m_ft_face->descender;
        m_rendered.metrics.height = m_ft_face->height;
    }


    bool use_kerning = FT_HAS_KERNING( m_ft_face );

    const ushort* chars = m_config->characters().utf16();
    size_t amount = 0;
    while (chars[amount]!=0) amount++;
    int error = 0;
    for (size_t i=0;i<amount;i++) {
        int glyph_index = FT_Get_Char_Index( m_ft_face, chars[i] );
        if (glyph_index==0 && !m_config->renderMissing())
            continue;

        FT_Int32 flags = FT_LOAD_DEFAULT;
        if (!m_config->antialiased()) {
            flags = flags | FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO;
        } else {
            flags = flags | FT_LOAD_TARGET_NORMAL;
        }
        switch (m_config->hinting()) {
        case  FontConfig::HintingDisable:
            flags = flags | FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT;
            break;
        case  FontConfig::HintingForceFreetypeAuto:
            flags = flags | FT_LOAD_FORCE_AUTOHINT;
            break;
        case  FontConfig::HintingDisableFreetypeAuto:
            flags = flags | FT_LOAD_NO_AUTOHINT;
            break;
        default:
            break;
        }

        error = FT_Load_Glyph( m_ft_face, glyph_index, flags );
        if ( error )
           continue;
        if (m_config->bold()!=0) {
            FT_Pos strength = m_config->size()*m_config->bold();
            if ( m_ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
                FT_Outline_Embolden( &m_ft_face->glyph->outline, strength );
        }
        if (m_ft_face->glyph->format!=FT_GLYPH_FORMAT_BITMAP) {
            error = FT_Render_Glyph( m_ft_face->glyph,
               m_config->antialiased() ? FT_RENDER_MODE_NORMAL:FT_RENDER_MODE_MONO );
        }
        if ( error )
           continue;
        if (append_bitmap(chars[i])) {
            if (use_kerning)
                append_kerning(chars[i],chars,amount);
        }
    }
    imagesChanged(m_chars);
    imagesChanged();
}
bool gfx_font_adapter::prepare_glyph(unsigned int code)
{
    if (m_impl->font) {
        m_impl->cur_glyph_index = FT_Get_Char_Index(m_impl->font, code);

        int error = FT_Load_Glyph(m_impl->font, m_impl->cur_glyph_index,
                                 m_impl->hinting ? FT_LOAD_DEFAULT : FT_LOAD_NO_HINTING);

        bool is_sys_bitmap = false;
        if (m_impl->font->glyph->format == FT_GLYPH_FORMAT_BITMAP)
            is_sys_bitmap = true;

        if (error == 0) {
            if (m_impl->antialias && !is_sys_bitmap) {
                if (m_impl->weight == 500) {
                    int strength = 1 << 5;
                    FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength);
                } else if (m_impl->weight == 700) {
                    int strength = 1 << 6;
                    FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength);
                } else if (m_impl->weight == 900) {
                    int strength = 1 << 7;
                    FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength);
                }
                // outline text
                m_impl->cur_data_type = glyph_type_outline;
                m_impl->cur_font_path.remove_all();

                if (decompose_ft_outline(m_impl->font->glyph->outline,
                            m_impl->flip_y, m_impl->matrix, m_impl->cur_font_path))
                {
                    m_impl->cur_bound_rect = get_bounding_rect(m_impl->cur_font_path);
                    m_impl->cur_data_size = m_impl->cur_font_path.total_byte_size()+sizeof(unsigned int);//count data
                    m_impl->cur_advance_x = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.x));
                    m_impl->cur_advance_y = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.y));
                    m_impl->matrix.transform(&m_impl->cur_advance_x, &m_impl->cur_advance_y);
                    return true;
                }
            } else {
                m_impl->cur_data_type = glyph_type_mono;
                if (is_sys_bitmap || !FT_IS_SCALABLE(m_impl->font) || m_impl->matrix.is_identity()) {
                    gfx_scanline_bin sl;
                    error = FT_Render_Glyph(m_impl->font->glyph, FT_RENDER_MODE_MONO);
                    if (error == 0) {
                        decompose_ft_bitmap_mono(m_impl->font->glyph->bitmap,
                           m_impl->font->glyph->bitmap_left, m_impl->flip_y ? -m_impl->font->glyph->bitmap_top :
                           m_impl->font->glyph->bitmap_top, m_impl->flip_y, sl, m_impl->cur_font_scanlines_bin);

                        m_impl->cur_bound_rect = rect(m_impl->cur_font_scanlines_bin.min_x(),
                                m_impl->cur_font_scanlines_bin.min_y(),
                                m_impl->cur_font_scanlines_bin.max_x() + 1,
                                m_impl->cur_font_scanlines_bin.max_y() + 1);
                        m_impl->cur_data_size = m_impl->cur_font_scanlines_bin.byte_size();
                        m_impl->cur_advance_x = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.x));
                        m_impl->cur_advance_y = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.y));
                        return true;
                    }
                } else {
                    if (m_impl->weight == 500) {
                        int strength = 1 << 5;
                        FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength);
                    } else if (m_impl->weight == 700) {
                        int strength = 1 << 6;
                        FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength);
                    } else if (m_impl->weight == 900) {
                        int strength = 1 << 7;
                        FT_Outline_Embolden(&(m_impl->font->glyph->outline), strength);
                    }

                    m_impl->cur_font_path.remove_all();
                    if (decompose_ft_outline(m_impl->font->glyph->outline,
                                m_impl->flip_y, m_impl->matrix, m_impl->cur_font_path))
                    {
                        gfx_rasterizer_scanline_aa<> rasterizer;
                        picasso::conv_curve curves(m_impl->cur_font_path);
                        curves.approximation_scale(4.0);
                        rasterizer.add_path(curves);

                        gfx_scanline_bin sl;
                        m_impl->cur_font_scanlines_bin.prepare(); // Remove all
                        gfx_render_scanlines(rasterizer, sl, m_impl->cur_font_scanlines_bin);
                        m_impl->cur_bound_rect = rect(m_impl->cur_font_scanlines_bin.min_x(),
                                m_impl->cur_font_scanlines_bin.min_y(),
                                m_impl->cur_font_scanlines_bin.max_x() + 1,
                                m_impl->cur_font_scanlines_bin.max_y() + 1);
                        m_impl->cur_data_size = m_impl->cur_font_scanlines_bin.byte_size();
                        m_impl->cur_advance_x = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.x));
                        m_impl->cur_advance_y = FLT_TO_SCALAR(int26p6_to_flt(m_impl->font->glyph->advance.y));
                        m_impl->matrix.transform(&m_impl->cur_advance_x, &m_impl->cur_advance_y);
                        return true;
                    }
                }
            }
        }
    }
    return false;
}
Exemple #12
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 */
Exemple #13
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;
}
Exemple #14
0
static void loadglyph(font_t *f, glui32 cid)
{
    FT_Vector v;
    int err;
    glui32 gid;
    int x;
    bitmap_t glyphs[GLI_SUBPIX];
    int adv;

    gid = FT_Get_Char_Index(f->face, cid);
    if (gid == 0)
        gid = FT_Get_Char_Index(f->face, '?');

    for (x = 0; x < GLI_SUBPIX; x++)
    {
        v.x = (x * 64) / GLI_SUBPIX;
        v.y = 0;

        FT_Set_Transform(f->face, 0, &v);

        err = FT_Load_Glyph(f->face, gid,
                FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
        if (err)
            winabort("FT_Load_Glyph");

        if (f->make_bold)
            FT_Outline_Embolden(&f->face->glyph->outline, FT_MulFix(f->face->units_per_EM, f->face->size->metrics.y_scale) / 24);

        if (f->make_oblique)
            FT_Outline_Transform(&f->face->glyph->outline, &ftmat);

        if (gli_conf_lcd)
            err = FT_Render_Glyph(f->face->glyph, FT_RENDER_MODE_LCD);
        else
            err = FT_Render_Glyph(f->face->glyph, FT_RENDER_MODE_LIGHT);
        if (err)
            winabort("FT_Render_Glyph");

        adv = (f->face->glyph->advance.x * GLI_SUBPIX + 32) / 64;

        glyphs[x].lsb = f->face->glyph->bitmap_left;
        glyphs[x].top = f->face->glyph->bitmap_top;
        glyphs[x].w = f->face->glyph->bitmap.width;
        glyphs[x].h = f->face->glyph->bitmap.rows;
        glyphs[x].pitch = f->face->glyph->bitmap.pitch;
        glyphs[x].data =
            malloc(glyphs[x].pitch * glyphs[x].h);
                if (gli_conf_lcd)
                    gammacopy_lcd(glyphs[x].data,
                            f->face->glyph->bitmap.buffer,
                            glyphs[x].w, glyphs[x].h, glyphs[x].pitch);
                else
                    gammacopy(glyphs[x].data,
                            f->face->glyph->bitmap.buffer,
                            glyphs[x].pitch * glyphs[x].h);
    }

    if (cid < 256)
    {
        f->lowloaded[cid/8] |= (1 << (cid%8));
        f->lowadvs[cid] = adv;
        memcpy(f->lowglyphs[cid], glyphs, sizeof glyphs);
    }
    else
    {
        int idx = findhighglyph(cid, f->highentries, f->num_highentries);
        if (idx < 0)
        {
            idx = ~idx;

            /* make room if needed */
            if (f->alloced_highentries == f->num_highentries)
            {
                fentry_t *newentries;
                int newsize = f->alloced_highentries * 2;
                if (!newsize)
                    newsize = 2;
                newentries = malloc(newsize * sizeof(fentry_t));
                if (!newentries)
                    return;
                if (f->highentries)
                {
                    memcpy(newentries, f->highentries, f->num_highentries * sizeof(fentry_t));
                    free(f->highentries);
                }
                f->highentries = newentries;
                f->alloced_highentries = newsize;
            }

            /* insert new glyph */
            memmove(&f->highentries[idx+1], &f->highentries[idx], (f->num_highentries - idx) * sizeof(fentry_t));
            f->highentries[idx].cid = cid;
            f->highentries[idx].adv = adv;
            memcpy(f->highentries[idx].glyph, glyphs, sizeof glyphs);
            f->num_highentries++;
        }
    }
}
Exemple #15
0
int
_PGFT_LoadGlyph(FontGlyph *glyph, PGFT_char character,
                const FontRenderMode *mode, void *internal)
{
    static FT_Vector delta = {0, 0};

    FT_Render_Mode rmode = (mode->render_flags & FT_RFLAG_ANTIALIAS ?
                            FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
    FT_Vector strong_delta = {0, 0};
    FT_Glyph image = 0;

    FT_Glyph_Metrics *ft_metrics;
    TextContext *context = (TextContext *)internal;

    FT_UInt32 load_flags;
    FT_UInt gindex;

    FT_Fixed rotation_angle = mode->rotation_angle;
    /* FT_Matrix transform; */
    FT_Vector h_bearing_rotated;
    FT_Vector v_bearing_rotated;
    FT_Vector h_advance_rotated;
    FT_Vector v_advance_rotated;

    FT_Error error = 0;

    /*
     * Calculate the corresponding glyph index for the char
     */
    gindex = FTC_CMapCache_Lookup(context->charmap, context->id,
                                  -1, (FT_UInt32)character);

    glyph->glyph_index = gindex;

    /*
     * Get loading information
     */
    load_flags = get_load_flags(mode);

    /*
     * Load the glyph into the glyph slot
     */
    if (FT_Load_Glyph(context->font, glyph->glyph_index, (FT_Int)load_flags) ||
            FT_Get_Glyph(context->font->glyph, &image))
        goto cleanup;

    /*
     * Perform any outline transformations
     */
    if (mode->style & FT_STYLE_STRONG) {
        FT_UShort x_ppem = context->font->size->metrics.x_ppem;
        FT_Fixed bold_str;
        FT_BBox before;
        FT_BBox after;

        bold_str = FX16_CEIL_TO_FX6(mode->strength * x_ppem);
        FT_Outline_Get_CBox(&((FT_OutlineGlyph)image)->outline, &before);
        if (FT_Outline_Embolden(&((FT_OutlineGlyph)image)->outline, bold_str))
            goto cleanup;
        FT_Outline_Get_CBox(&((FT_OutlineGlyph)image)->outline, &after);
        strong_delta.x += ((after.xMax - after.xMin) -
                           (before.xMax - before.xMin));
        strong_delta.y += ((after.yMax - after.yMin) -
                           (before.yMax - before.yMin));
    }

    if (context->do_transform) {
        if (FT_Glyph_Transform(image, &context->transform, &delta)) {
            goto cleanup;
        }
    }

    /*
     * Finished with outline transformations, now replace with a bitmap
     */
    error = FT_Glyph_To_Bitmap(&image, rmode, 0, 1);
    if (error) {
        goto cleanup;
    }

    if (mode->style & FT_STYLE_WIDE) {
        FT_Bitmap *bitmap = &((FT_BitmapGlyph)image)->bitmap;
        int w = bitmap->width;
        FT_UShort x_ppem = context->font->size->metrics.x_ppem;
        FT_Pos x_strength;

        x_strength = FX16_CEIL_TO_FX6(mode->strength * x_ppem);

        /* FT_Bitmap_Embolden returns an error for a zero width bitmap */
        if (w > 0) {
            error = FT_Bitmap_Embolden(context->lib, bitmap,
                                       x_strength, (FT_Pos)0);
            if (error) {
                goto cleanup;
            }
            strong_delta.x += INT_TO_FX6(bitmap->width - w);
        }
        else {
            strong_delta.x += x_strength;
        }
    }

    /* Fill the glyph */
    ft_metrics = &context->font->glyph->metrics;

    h_advance_rotated.x = ft_metrics->horiAdvance + strong_delta.x;
    h_advance_rotated.y = 0;
    v_advance_rotated.x = 0;
    v_advance_rotated.y = ft_metrics->vertAdvance + strong_delta.y;
    if (rotation_angle != 0) {
        FT_Angle counter_rotation = INT_TO_FX6(360) - rotation_angle;

        FT_Vector_Rotate(&h_advance_rotated, rotation_angle);
        FT_Vector_Rotate(&v_advance_rotated, counter_rotation);
    }

    glyph->image = (FT_BitmapGlyph)image;
    glyph->width = INT_TO_FX6(glyph->image->bitmap.width);
    glyph->height = INT_TO_FX6(glyph->image->bitmap.rows);
    h_bearing_rotated.x = INT_TO_FX6(glyph->image->left);
    h_bearing_rotated.y = INT_TO_FX6(glyph->image->top);
    fill_metrics(&glyph->h_metrics,
                 ft_metrics->horiBearingX,
                 ft_metrics->horiBearingY,
                 &h_bearing_rotated, &h_advance_rotated);

    if (rotation_angle == 0) {
        v_bearing_rotated.x = ft_metrics->vertBearingX - strong_delta.x / 2;
        v_bearing_rotated.y = ft_metrics->vertBearingY;
    }
    else {
        /*
         * Adjust the vertical metrics.
         */
        FT_Vector v_origin;

        v_origin.x = (glyph->h_metrics.bearing_x -
                      ft_metrics->vertBearingX + strong_delta.x / 2);
        v_origin.y = (glyph->h_metrics.bearing_y +
                      ft_metrics->vertBearingY);
        FT_Vector_Rotate(&v_origin, rotation_angle);
        v_bearing_rotated.x = glyph->h_metrics.bearing_rotated.x - v_origin.x;
        v_bearing_rotated.y = v_origin.y - glyph->h_metrics.bearing_rotated.y;
    }
    fill_metrics(&glyph->v_metrics,
                 ft_metrics->vertBearingX,
                 ft_metrics->vertBearingY,
                 &v_bearing_rotated, &v_advance_rotated);

    return 0;

    /*
     * Cleanup on error
     */
cleanup:
    if (image) {
        FT_Done_Glyph(image);
    }

    return -1;
}
Exemple #16
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;
}
Exemple #17
0
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;
}
Exemple #18
0
// ----------------------------------------------------------------------------
void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
{
    assert(gi.glyph_index > 0);
    assert(gi.font_number < m_face_ttf->getTotalFaces());
    FT_Face cur_face = m_face_ttf->getFace(gi.font_number);
    FT_GlyphSlot slot = cur_face->glyph;

    // Faces may be shared across regular and bold,
    // so reset dpi each time
    font_manager->checkFTError(FT_Set_Pixel_Sizes(cur_face, 0, getDPI()),
        "setting DPI");

    font_manager->checkFTError(FT_Load_Glyph(cur_face, gi.glyph_index,
        FT_LOAD_DEFAULT), "loading a glyph");

    if (dynamic_cast<BoldFace*>(this))
    {
        // Embolden the outline of the glyph
        FT_Outline_Embolden(&(slot->outline), getDPI() * 2);
    }

    font_manager->checkFTError(FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL),
        "render a glyph to bitmap");

    // Convert to an anti-aliased bitmap
    FT_Bitmap bits = slot->bitmap;

    core::dimension2du d(bits.width + 1, bits.rows + 1);
    core::dimension2du texture_size;
    texture_size = d.getOptimalSize(!(irr_driver->getVideoDriver()
        ->queryFeature(video::EVDF_TEXTURE_NPOT)), !(irr_driver
        ->getVideoDriver()->queryFeature(video::EVDF_TEXTURE_NSQUARE)),
        true, 0);

    if ((m_used_width + texture_size.Width > getGlyphPageSize() &&
        m_used_height + m_temp_height + texture_size.Height >
        getGlyphPageSize())                                     ||
        m_used_height + texture_size.Height > getGlyphPageSize())
    {
        // Current glyph page is full:
        // Save the old glyph page
        video::ITexture* page_texture = irr_driver->getVideoDriver()
            ->addTexture("Glyph_page", m_page);
        m_spritebank->setTexture(m_spritebank->getTextureCount() - 1,
            page_texture);
        irr_driver->getVideoDriver()->removeTexture(page_texture);
        assert(page_texture->getReferenceCount() == 1);

        // Clear and add a new one
        createNewGlyphPage();
    }

    video::IImage* glyph = NULL;
    switch (bits.pixel_mode)
    {
        case FT_PIXEL_MODE_GRAY:
        {
            // Create our blank image.
            glyph = irr_driver->getVideoDriver()
                ->createImage(video::ECF_A8R8G8B8, texture_size);
            glyph->fill(video::SColor(0, 255, 255, 255));

            // Load the grayscale data in.
            const float gray_count = static_cast<float>(bits.num_grays);
            const unsigned int image_pitch =
                glyph->getPitch() / sizeof(unsigned int);
            unsigned int* image_data = (unsigned int*)glyph->lock();
            unsigned char* glyph_data = bits.buffer;

            for (unsigned int y = 0; y < (unsigned int)bits.rows; y++)
            {
                unsigned char* row = glyph_data;
                for (unsigned int x = 0; x < (unsigned)bits.width; x++)
                {
                    image_data[y * image_pitch + x] |=
                        static_cast<unsigned int>(255.0f *
                        (static_cast<float>(*row++) / gray_count)) << 24;
                }
                glyph_data += bits.pitch;
            }
            glyph->unlock();
            break;
        }
        default:
            assert(false);
    }
    if (!glyph)
        Log::fatal("FontWithFace", "Failed to load a glyph");

    // Done creating a single glyph, now copy to the glyph page...
    // Determine the linebreak location
    if (m_used_width + texture_size.Width > getGlyphPageSize())
    {
        m_used_width  = 0;
        m_used_height += m_temp_height;
        m_temp_height = 0;
    }

    // Copy to the full glyph page
    glyph->copyTo(m_page, core::position2di(m_used_width, m_used_height));

    // Store the rectangle of current glyph
    gui::SGUISpriteFrame f;
    gui::SGUISprite s;
    core::rect<s32> rectangle(m_used_width, m_used_height,
        m_used_width + bits.width, m_used_height + bits.rows);
    f.rectNumber = m_spritebank->getPositions().size();
    f.textureNumber = m_spritebank->getTextureCount() - 1;

    // Add frame to sprite
    s.Frames.push_back(f);
    s.frameTime = 0;
    m_spritebank->getPositions().push_back(rectangle);
    m_spritebank->getSprites().push_back(s);

    // Save glyph metrics
    FontArea a;
    a.advance_x = cur_face->glyph->advance.x / BEARING;
    a.bearing_x = cur_face->glyph->metrics.horiBearingX / BEARING;
    const int cur_height = (cur_face->glyph->metrics.height / BEARING);
    const int cur_offset_y = cur_height -
        (cur_face->glyph->metrics.horiBearingY / BEARING);
    a.offset_y = m_glyph_max_height - cur_height + cur_offset_y;
    a.offset_y_bt = -cur_offset_y;
    a.spriteno = f.rectNumber;
    m_character_area_map[c] = a;

    // Clean the temporary glyph
    glyph->drop();
    glyph = NULL;

    // Store used area
    m_used_width += texture_size.Width;
    if (m_temp_height < texture_size.Height)
        m_temp_height = texture_size.Height;
}   // insertGlyph
Exemple #19
0
void CFont2D::CharToImage(const wchar_t * Chars)
{
	//	wchar_t InputChar;
//	MultiByteToWideChar(CP_ACP,0,Chars,byteNum,&InputChar,1);
	if(FT_Load_Glyph( face, FT_Get_Char_Index( face, Chars[0] ), FT_LOAD_DEFAULT ))
		return;
	FT_Outline_Embolden( &(face->glyph->outline), 30 );
	FT_Glyph glyph;
    if(FT_Get_Glyph( face->glyph, &glyph ))
		return;
	FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1 );
    FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
	FT_Bitmap& bitmap=bitmap_glyph->bitmap;

	if(bitmap.width>=OnefontW)
		OneCharWidth[CharNum]=1.0f;
	else
		OneCharWidth[CharNum]=float(bitmap.width)/float(OnefontW);
	if(Chars[0]==L' ')
		OneCharWidth[CharNum]=0.5f;

	CharNum=CharNum+1;

	int Ymove=0;
	if(Chars[0]<0x80)
		Ymove=bitmap.rows/6;
	if(Chars[0]==L'-')
		Ymove=OnefontH/2-bitmap.rows*2;
	if(Chars[0]==L'.')
		Ymove=bitmap.rows/2;

	for(int j=Ymove; j <OnefontH;j++) {
		for(int i=0; i < OnefontW; i++){
			OnefontData[i+(j-Ymove)*OnefontW] = (i>=bitmap.width || j<(OnefontH-bitmap.rows)) ? 0 : bitmap.buffer[i + bitmap.width*(j-OnefontH+bitmap.rows)];
		}
	}
	for(int j=OnefontH-Ymove; j <OnefontH;j++) {
		for(int i=0; i < OnefontW; i++){
			OnefontData[i+(j)*OnefontW] = 0;
		}
	}
	glBindTexture(GL_TEXTURE_2D, TexID);
	glTexSubImage2D(
		GL_TEXTURE_2D,
		0,
		FontPosX,
		FontPosY,
		OnefontW,
		OnefontH,
		GL_ALPHA,
		GL_UNSIGNED_BYTE,
		OnefontData);

	FontPosX=FontPosX+OnefontW;
	if(FontPosX>=FontTexW)
	{
		FontPosX=0;
		FontPosY=FontPosY+OnefontH;
		if(FontPosY>=FontTexH)
			FontPosY=FontTexH;
	}
	FT_Done_Glyph(glyph);
}
Exemple #20
0
static PyObject*
Py_Outline_decompose(Py_Outline* self, PyObject* args, PyObject* kwds)
{
    /* TODO: Also implement this as an iterator */

    DecomposeData data;
    PyObject *obj;
    const FT_Outline_Funcs funcs = {
        .move_to = Py_Outline_moveto_func,
        .line_to = Py_Outline_lineto_func,
        .conic_to = Py_Outline_conicto_func,
        .cubic_to = Py_Outline_cubicto_func,

        .shift = 0,
        .delta = 0
    };
    int error;

    const char* keywords[] = {"obj", "shift", "delta", NULL};

    if (!PyArg_ParseTupleAndKeywords(
            args, kwds, "O|ii:decompose", (char **)keywords,
            &obj, &funcs.shift, &funcs.delta)) {
        return NULL;
    }

    if (!PyObject_HasAttrString(obj, "move_to")) {
        PyErr_SetString(PyExc_AttributeError, "obj has no move_to method");
        return NULL;
    }
    if (!PyObject_HasAttrString(obj, "line_to")) {
        PyErr_SetString(PyExc_AttributeError, "obj has no line_to method");
        return NULL;
    }
    if (!PyObject_HasAttrString(obj, "cubic_to")) {
        PyErr_SetString(PyExc_AttributeError, "obj has no cubic_to method");
        return NULL;
    }
    data.has_conic_to = PyObject_HasAttrString(obj, "conic_to");
    data.callback = obj;
    data.last_x = 0;
    data.last_y = 0;

    error = FT_Outline_Decompose(&self->x, &funcs, &data);
    if (PyErr_Occurred()) {
        return NULL;
    } else if (ftpy_exc(error)) {
        return NULL;
    }

    Py_RETURN_NONE;
};


static PyObject*
Py_Outline_embolden(Py_Outline* self, PyObject* args, PyObject* kwds)
{
    double strength;

    const char* keywords[] = {"strength", NULL};

    if (!PyArg_ParseTupleAndKeywords(
            args, kwds, "d:embolden", (char **)keywords,
            &strength)) {
        return NULL;
    }

    if (ftpy_exc(
            FT_Outline_Embolden(&self->x, TO_F26DOT6(strength)))) {
        return NULL;
    }

    Py_RETURN_NONE;
};
Exemple #21
0
int DrawGlyph(
	_In_ wchar_t c,
	_In_ int pixel_size,
	_Out_ _Notnull_ int* pitch,
	_Out_ _Notnull_ int* rows,
	_Out_ _Notnull_ int* advance,
	_Out_ _Notnull_ int* horiBearingY,
	_Inout_ _Notnull_ unsigned char** ppBitmap
	)
{
	FT_Error error;
	FT_UInt glyph_index;

	glyph_index = FT_Get_Char_Index(face, c);

	error = FT_Set_Pixel_Sizes(face, 0, pixel_size);
	if (error)
	{
		return error;
	}

	error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
	if (error)
	{
		return error;
	}

	if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
	{
		FT_Pos strength = 30;
		error = FT_Outline_Embolden(&face->glyph->outline, strength);
		if (error)
		{
			//cl_debug_output("Font Embolden failed.");
            DebugBreak();
		}
	}

	/*
	FT_Matrix matrix;
	matrix.xx = 0x07FFFL;
	matrix.xy = 0;
	matrix.yx = 0;
	matrix.yy = 0x10000L;
	FT_Set_Transform(face, &matrix, 0);
	*/

	error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
	if (error)
	{
		return error;
	}

	*ppBitmap = (unsigned char*)malloc(face->glyph->bitmap.rows * face->glyph->bitmap.pitch);

	memcpy(*ppBitmap, face->glyph->bitmap.buffer,
		face->glyph->bitmap.rows * face->glyph->bitmap.pitch);

	*pitch = face->glyph->bitmap.pitch;
	*rows = face->glyph->bitmap.rows;
	*advance = face->glyph->advance.x / 64;
	*horiBearingY = face->glyph->metrics.horiBearingY / 64;

	return error;
}