Example #1
0
int
test_get_cbox( btimer_t*  timer,
               FT_Face    face,
               void*      user_data )
{
  FT_Glyph  glyph;
  FT_BBox   bbox;
  int       i, done = 0;


  FT_UNUSED( user_data );

  for ( i = 0; i < face->num_glyphs; i++ )
  {
    if ( FT_Load_Glyph( face, i, load_flags ) )
      continue;

    if ( FT_Get_Glyph( face->glyph, &glyph ) )
      continue;

    TIMER_START( timer );
    FT_Glyph_Get_CBox( glyph, FT_GLYPH_BBOX_PIXELS, &bbox );
    TIMER_STOP( timer );

    FT_Done_Glyph( glyph );
    done++;
  }

  return done;
}
Example #2
0
Glyph::Glyph( const FT_Face& face, const FT_Glyph& glyph, size_t ind) :
  glyphInd(ind) {
  _VERBOSE("Glyph::Glyph");
  
  FT_BBox bbox;
  FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_subpixels, &bbox );
  
  setattr("width",        Py::Int( face->glyph->metrics.width) );
  setattr("height",       Py::Int( face->glyph->metrics.height) );
  setattr("horiBearingX", Py::Int( face->glyph->metrics.horiBearingX) );
  setattr("horiBearingY", Py::Int( face->glyph->metrics.horiBearingY) );
  setattr("horiAdvance",  Py::Int( face->glyph->metrics.horiAdvance) );
  setattr("vertBearingX", Py::Int( face->glyph->metrics.vertBearingX) );
  
  setattr("vertBearingY", Py::Int( face->glyph->metrics.vertBearingY) );
  setattr("vertAdvance",  Py::Int( face->glyph->metrics.vertAdvance) );
  
  Py::Tuple abbox(4);

  abbox[0] = Py::Int(bbox.xMin);
  abbox[1] = Py::Int(bbox.yMin);
  abbox[2] = Py::Int(bbox.xMax);
  abbox[3] = Py::Int(bbox.yMax);
  setattr("bbox", abbox);
}
Example #3
0
static FT_Error freetype2_get_glyph_size(PFontFreetype pf,
						 FT_Face face,
						 int glyph_index,
						 int *padvance,
						 int *pascent,
						 int *pdescent)
{
	FT_Error error;
		error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
		if (error)
			return error;

		if (padvance)
			*padvance = ROUND_26_6_TO_INT(face->glyph->advance.x);
		if (pascent || pdescent)
		{
			FT_Glyph glyph;
			FT_BBox bbox;

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

			FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &bbox);

			FT_Done_Glyph(glyph);

			if (pascent)
				*pascent = bbox.yMax;
			if (pdescent)
				*pdescent = -bbox.yMin;
		}

		return 0;
}
Example #4
0
File: font.hpp Project: duzy/ds.ge
 bound_box bbox() const {//in 1/64th units
   FT_BBox bb;
   //FT_Glyph_Get_CBox( image, FT_GLYPH_BBOX_GRIDFIT, &bb );
   //FT_Glyph_Get_CBox( image, FT_GLYPH_BBOX_TRUNCATE, &bb );
   FT_Glyph_Get_CBox( image, FT_GLYPH_BBOX_PIXELS, &bb );
   return bound_box(bb);
 }
Example #5
0
bool font_face::glyph_dimensions(glyph_info & glyph) const
{
    FT_Vector pen;
    pen.x = 0;
    pen.y = 0;
    FT_Set_Transform(face_, 0, &pen);

    if (FT_Load_Glyph(face_, glyph.glyph_index, FT_LOAD_NO_HINTING))
    {
        MAPNIK_LOG_ERROR(font_face) << "FT_Load_Glyph failed";
        return false;
    }
    FT_Glyph image;
    if (FT_Get_Glyph(face_->glyph, &image))
    {
        MAPNIK_LOG_ERROR(font_face) << "FT_Get_Glyph failed";
        return false;
    }
    FT_BBox glyph_bbox;
    FT_Glyph_Get_CBox(image, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);
    FT_Done_Glyph(image);
    glyph.unscaled_ymin = glyph_bbox.yMin;
    glyph.unscaled_ymax = glyph_bbox.yMax;
    glyph.unscaled_advance = face_->glyph->advance.x;
    glyph.unscaled_line_height = face_->size->metrics.height;
    glyph.unscaled_ascender = unscaled_ascender_;
    return true;
}
//http://www.freetype.org/freetype2/docs/tutorial/step2.html
FT_Error measure_string(FT_Face face, std::string text, int size, Vector2i* size_out)
{
   int pos_x = 0;
   bool use_kerning = FT_HAS_KERNING(face) ? true : false;
   FT_UInt prev_glyph_index = 0;

   FT_BBox text_bb;
   text_bb.xMax = 0;
   text_bb.xMin = 0;
   text_bb.yMax = 0;
   text_bb.yMin = 0;
   FT_Error error;

   error = FT_Set_Char_Size(face, 0, size * 64, 72, 72);

   for(unsigned int i = 0; i < text.length(); i++)
   {
      FT_UInt glyph_index = FT_Get_Char_Index(face, text.c_str()[i]);

      if(use_kerning && prev_glyph_index)
      {
         FT_Vector delta;
         FT_Get_Kerning(face, prev_glyph_index, glyph_index, FT_KERNING_DEFAULT, &delta);
         pos_x += delta.x >> 6;
      }
      prev_glyph_index = glyph_index;

      if(error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) != FT_Err_Ok)
      {
         Log::Error(__FILE__, "Unable to load glyph %d", glyph_index);
         return error;
      }

      FT_Glyph glyph;
      if(error = FT_Get_Glyph(face->glyph, &glyph) != FT_Err_Ok)
      {
         Log::Error(__FILE__, "Unable to get glyph %d", glyph_index);
      }

      FT_BBox bb;
      FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &bb);
      bb.xMax += pos_x;
      bb.xMin += pos_x;


      pos_x += glyph->advance.x >> 16;

      //Grow overall bounding box
      if(bb.xMax > text_bb.xMax)
         text_bb.xMax = bb.xMax;
      if(bb.yMax > text_bb.yMax)
         text_bb.yMax = bb.yMax;
      if(bb.xMin < text_bb.xMin)
         text_bb.xMin = bb.xMin;
      if(bb.yMin < text_bb.yMin)
         text_bb.yMin = bb.yMin;

      FT_Done_Glyph(glyph);
   }
Example #7
0
void CBitmapFont::generateGlyph(U32 ch){
	S32 pad = 3;
	FT_GlyphSlot  slot = mFace->glyph;
	FT_Glyph glyph;
    FT_UInt glyph_index;

	glyph_index = FT_Get_Char_Index( mFace, (FT_ULong)ch );

	FT_Load_Glyph( mFace, glyph_index, FT_LOAD_DEFAULT);
	FT_Get_Glyph( slot, &glyph);

	FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, 0 ,1);

	FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;
	FT_Bitmap* source = &bitmap->bitmap;


	S32 srcWidth = source->width;
	S32 srcHeight = source->rows;
	S32 srcPitch = source->pitch;

	S32 dstWidth = srcWidth;
	S32 dstHeight = srcHeight;
	S32 dstPitch = srcPitch;

	FT_BBox bbox;
	FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_pixels, &bbox);

	unsigned char *src = source->buffer;

	if(pen.x + srcWidth >= mTextureSize){
		pen.x = 0;
		pen.y += (getFontSize() * 64.0f / dpi) + pad;
	}

	glBindTexture(GL_TEXTURE_2D, curTex);checkGLError();
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);checkGLError();
	glTexSubImage2D(GL_TEXTURE_2D, 0, 
		pen.x, pen.y,
		srcWidth, srcHeight,
		GL_ALPHA, GL_UNSIGNED_BYTE, src); checkGLError();

	CTexCoord start(pen);
	start /= mTextureSize;
	CTexCoord end(pen.x + srcWidth, pen.y + srcHeight);
	end /= mTextureSize;
	//CVector2 pos(slot->bitmap_left, slot->bitmap_top);
	CVector2 pos(bitmap->left, srcHeight - bitmap->top);
	CVector2 size(srcWidth, srcHeight);
	CVector2 advance(slot->advance.x >> 6, slot->advance.y >> 6);
	
	mGlyphs[glyph_index] = new CBitmapGlyph(curTex, start, end, pos, size, advance);

	pen.x += srcWidth + pad;

	FT_Done_Glyph(glyph);
}
Example #8
0
void drawText(const char *string,float startx,float starty)
{
   float PosArray[20][2];
   float TexArray[20][2];
   float ScaArray[20][2];

   int count = 0;
  
   glUniform1i(TextUniform,1);
   glUniform2f(TextScaleUniform,width,height);
   glUniform2f(ScaleUniform,0.005,0.005);
   
   while(*string && count < 20)
   {
      FT_BBox bbox;

      FT_Glyph_Get_CBox( (FT_Glyph) glyphs[*string -32], FT_GLYPH_BBOX_PIXELS, &bbox );

      PosArray[count][0] = startx;
      PosArray[count][1] = starty + (int) bbox.yMin/200.0;

      TexArray[count][0] = glyphsPos[*string -32].x;
      TexArray[count][1] = glyphsPos[*string -32].y;
      
      ScaArray[count][0] = glyphs[*string -32]->bitmap.width;
      ScaArray[count][1] = glyphs[*string -32]->bitmap.rows;

      startx += ((FT_Glyph) glyphs[*string -32])->advance.x/(65532.0) * 0.005;
      
      string++, count++;
   }

   glDisableVertexAttribArray(0);
   glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
   glBufferSubData(GL_ARRAY_BUFFER,0,20 * 2 * sizeof(GLfloat),PosArray);
   glVertexAttribPointer((GLuint) 0,2,GL_FLOAT,GL_FALSE,0,0);
   glEnableVertexAttribArray(0);
  
   glDisableVertexAttribArray(1);
   glBindBuffer(GL_ARRAY_BUFFER,vbo[1]);
   glBufferSubData(GL_ARRAY_BUFFER,0,20 * 2 * sizeof(GLfloat),TexArray);
   glVertexAttribPointer((GLuint) 1,2,GL_FLOAT,GL_FALSE,0,0);
   glEnableVertexAttribArray(1);

   glDisableVertexAttribArray(2);
   glBindBuffer(GL_ARRAY_BUFFER,vbo[2]);
   glBufferSubData(GL_ARRAY_BUFFER,0,20 * 2* sizeof(GLfloat),ScaArray);
   glVertexAttribPointer((GLuint) 2,2,GL_FLOAT,GL_FALSE,0,0);
   glEnableVertexAttribArray(2);
   
   glDrawElements(GL_POINTS,count,GL_UNSIGNED_BYTE,0);
   
   glUniform1i(TextUniform,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_);
}
Example #10
0
/**
 * Load glyphs corresponding to the UTF-32 codepoint code.
 */
static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code)
{
    DrawTextContext *s = ctx->priv;
    Glyph *glyph;
    struct AVTreeNode *node = NULL;
    int ret;

    /* load glyph into s->face->glyph */
    if (FT_Load_Char(s->face, code, s->ft_load_flags))
        return AVERROR(EINVAL);

    /* save glyph */
    if (!(glyph = av_mallocz(sizeof(*glyph))) ||
        !(glyph->glyph = av_mallocz(sizeof(*glyph->glyph)))) {
        ret = AVERROR(ENOMEM);
        goto error;
    }
    glyph->code  = code;

    if (FT_Get_Glyph(s->face->glyph, glyph->glyph)) {
        ret = AVERROR(EINVAL);
        goto error;
    }

    glyph->bitmap      = s->face->glyph->bitmap;
    glyph->bitmap_left = s->face->glyph->bitmap_left;
    glyph->bitmap_top  = s->face->glyph->bitmap_top;
    glyph->advance     = s->face->glyph->advance.x >> 6;

    /* measure text height to calculate text_height (or the maximum text height) */
    FT_Glyph_Get_CBox(*glyph->glyph, ft_glyph_bbox_pixels, &glyph->bbox);

    /* cache the newly created glyph */
    if (!(node = av_tree_node_alloc())) {
        ret = AVERROR(ENOMEM);
        goto error;
    }
    av_tree_insert(&s->glyphs, glyph, glyph_cmp, &node);

    if (glyph_ptr)
        *glyph_ptr = glyph;
    return 0;

error:
    if (glyph)
        av_freep(&glyph->glyph);
    av_freep(&glyph);
    av_freep(&node);
    return ret;
}
static int check_glyph_area(ASS_Library *library, FT_Glyph glyph)
{
    FT_BBox bbox;
    long long dx, dy;
    FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox);
    dx = bbox.xMax - bbox.xMin;
    dy = bbox.yMax - bbox.yMin;
    if (dx * dy > 8000000) {
        ass_msg(library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx",
               (int) dx, (int) dy);
        return 1;
    } else
        return 0;
}
Example #12
0
Py::Object
FT2Font::draw_glyphs_to_bitmap(const Py::Tuple & args) {
  _VERBOSE("FT2Font::draw_glyphs_to_bitmap");
  args.verify_length(0);
  
  FT_BBox string_bbox = compute_string_bbox();
  
  image.width   = (string_bbox.xMax-string_bbox.xMin) / 64+2;
  image.height  = (string_bbox.yMax-string_bbox.yMin) / 64+2;
  
  image.offsetx = (int)(string_bbox.xMin/64.0);
  if (angle==0)  
    image.offsety = -image.height;
  else
    image.offsety = (int)(-string_bbox.yMax/64.0);
  
  size_t numBytes = image.width*image.height;
  delete [] image.buffer;
  image.buffer = new unsigned char [numBytes];
  for (size_t n=0; n<numBytes; n++) 
    image.buffer[n] = 0;
  
  for ( size_t n = 0; n < glyphs.size(); n++ )
    {
      FT_BBox bbox;
      
      FT_Glyph_Get_CBox(glyphs[n], ft_glyph_bbox_pixels, &bbox);
      
      error = FT_Glyph_To_Bitmap(&glyphs[n],
				 ft_render_mode_normal,
				 0,
				 //&pos[n],
				 1  //destroy image; 
				 );
      if (error)
	throw Py::RuntimeError("Could not convert glyph to bitmap");
      
      FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[n];
      /* now, draw to our target surface (convert position) */
      
      //bitmap left and top in pixel, string bbox in subpixel
      
      draw_bitmap( &bitmap->bitmap, 
		   bitmap->left-string_bbox.xMin/64,
		   string_bbox.yMax/64-bitmap->top+1
		   );
    }
  return Py::Object();
}
Example #13
0
font_face_set::dimension_t font_face_set::character_dimensions(const unsigned c)
{
    std::map<unsigned, dimension_t>::const_iterator itr;
    itr = dimension_cache_.find(c);
    if (itr != dimension_cache_.end()) {
        return itr->second;
    }

    FT_Matrix matrix;
    FT_Vector pen;
    FT_Error  error;

    pen.x = 0;
    pen.y = 0;

    FT_BBox glyph_bbox;
    FT_Glyph image;

    glyph_ptr glyph = get_glyph(c);
    FT_Face face = glyph->get_face()->get_face();

    matrix.xx = (FT_Fixed)( 1 * 0x10000L );
    matrix.xy = (FT_Fixed)( 0 * 0x10000L );
    matrix.yx = (FT_Fixed)( 0 * 0x10000L );
    matrix.yy = (FT_Fixed)( 1 * 0x10000L );

    FT_Set_Transform(face, &matrix, &pen);

    error = FT_Load_Glyph (face, glyph->get_index(), FT_LOAD_NO_HINTING);
    if ( error )
        return dimension_t(0, 0, 0);

    error = FT_Get_Glyph(face->glyph, &image);
    if ( error )
        return dimension_t(0, 0, 0);

    FT_Glyph_Get_CBox(image, ft_glyph_bbox_pixels, &glyph_bbox);
    FT_Done_Glyph(image);

    unsigned tempx = face->glyph->advance.x >> 6;

    //std::clog << "glyph: " << glyph_index << " x: " << tempx << " y: " << tempy << std::endl;
    dimension_t dim(tempx, glyph_bbox.yMax, glyph_bbox.yMin);
    //dimension_cache_[c] = dim; would need an default constructor for dimension_t
    dimension_cache_.insert(std::pair<unsigned, dimension_t>(c, dim));
    return dim;
}
Example #14
0
char_info font_face_set::character_dimensions(const unsigned c)
{
    //Check if char is already in cache
    std::map<unsigned, char_info>::const_iterator itr;
    itr = dimension_cache_.find(c);
    if (itr != dimension_cache_.end()) {
        return itr->second;
    }

    FT_Matrix matrix;
    FT_Vector pen;
    FT_Error  error;

    pen.x = 0;
    pen.y = 0;

    FT_BBox glyph_bbox;
    FT_Glyph image;

    glyph_ptr glyph = get_glyph(c);
    FT_Face face = glyph->get_face()->get_face();

    matrix.xx = (FT_Fixed)( 1 * 0x10000L );
    matrix.xy = (FT_Fixed)( 0 * 0x10000L );
    matrix.yx = (FT_Fixed)( 0 * 0x10000L );
    matrix.yy = (FT_Fixed)( 1 * 0x10000L );

    FT_Set_Transform(face, &matrix, &pen);

    error = FT_Load_Glyph (face, glyph->get_index(), FT_LOAD_NO_HINTING);
    if ( error )
        return char_info();

    error = FT_Get_Glyph(face->glyph, &image);
    if ( error )
        return char_info();

    FT_Glyph_Get_CBox(image, ft_glyph_bbox_pixels, &glyph_bbox);
    FT_Done_Glyph(image);

    unsigned tempx = face->glyph->advance.x >> 6;

    char_info dim(c, tempx, glyph_bbox.yMax, glyph_bbox.yMin, face->size->metrics.height/64.0 /* >> 6 */);
    dimension_cache_.insert(std::pair<unsigned, char_info>(c, dim));
    return dim;
}
Example #15
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);
}
Example #16
0
void ComputeStringBox( FT_BBox& Box, FT_Glyph* GlyphList,FT_Vector* PosList, const int GlyphCount )
{
	/* initialize string bbox to "empty" values */
	Box.xMin = Box.yMin =  32000;
	Box.xMax = Box.yMax = -32000;

	/* for each glyph image, compute its bounding box, */
	/* translate it, and grow the string bbox          */
	for ( int n = 0; n < GlyphCount; n++ )
	{
		FT_BBox  GlyphBox;

		FT_Glyph_Get_CBox( GlyphList[n], ft_glyph_bbox_pixels, &GlyphBox );

		GlyphBox.xMin += PosList[n].x;
		GlyphBox.xMax += PosList[n].x;
		GlyphBox.yMin += PosList[n].y;
		GlyphBox.yMax += PosList[n].y;

		if ( GlyphBox.xMin < Box.xMin )
			Box.xMin = GlyphBox.xMin;

		if ( GlyphBox.yMin < Box.yMin )
			Box.yMin = GlyphBox.yMin;

		if ( GlyphBox.xMax > Box.xMax )
			Box.xMax = GlyphBox.xMax;

		if ( GlyphBox.yMax > Box.yMax )
			Box.yMax = GlyphBox.yMax;
	}

	/* check that we really grew the string bbox */
	if ( Box.xMin > Box.xMax )
	{
		Box.xMin = 0;
		Box.yMin = 0;
		Box.xMax = 0;
		Box.yMax = 0;
	}
};
Example #17
0
void
XeTeXFontInst_FT2::getGlyphBounds(LEGlyphID gid, GlyphBBox* bbox)
{
	bbox->xMin = bbox->yMin = bbox->xMax = bbox->yMax = 0.0;

	FT_Error	err = FT_Load_Glyph(face, gid, FT_LOAD_NO_SCALE);
	if (err != 0)
		return;
    
    FT_Glyph	glyph;
    err = FT_Get_Glyph(face->glyph, &glyph);
	if (err == 0) {	    
		FT_BBox	ft_bbox;
		FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_UNSCALED, &ft_bbox);
		bbox->xMin = ft_bbox.xMin * fPointSize / fUnitsPerEM;
		bbox->yMin = ft_bbox.yMin * fPointSize / fUnitsPerEM;
		bbox->xMax = ft_bbox.xMax * fPointSize / fUnitsPerEM;
		bbox->yMax = ft_bbox.yMax * fPointSize / fUnitsPerEM;
		FT_Done_Glyph(glyph);
	}
}
Example #18
0
void
XeTeXFontInst::getGlyphBounds(GlyphID gid, GlyphBBox* bbox)
{
    bbox->xMin = bbox->yMin = bbox->xMax = bbox->yMax = 0.0;

    FT_Error error = FT_Load_Glyph(m_ftFace, gid, FT_LOAD_NO_SCALE);
    if (error)
        return;

    FT_Glyph glyph;
    error = FT_Get_Glyph(m_ftFace->glyph, &glyph);
    if (error == 0) {
        FT_BBox ft_bbox;
        FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_UNSCALED, &ft_bbox);
        bbox->xMin = unitsToPoints(ft_bbox.xMin);
        bbox->yMin = unitsToPoints(ft_bbox.yMin);
        bbox->xMax = unitsToPoints(ft_bbox.xMax);
        bbox->yMax = unitsToPoints(ft_bbox.yMax);
        FT_Done_Glyph(glyph);
    }
}
Size FontEngine_Freetype::get_size(const std::string &text, int pos)
{
	FT_UInt glyph_index;

	// Get glyph index
	glyph_index = FT_Get_Char_Index(face, text[pos]);

	// Load glyph image
	FT_Error error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT );
	if (error) return Size(0,0);

	FT_Glyph glyph;
	FT_BBox bbox;
	FT_Get_Glyph(face->glyph, &glyph);
	FT_Glyph_Get_CBox( glyph, FT_GLYPH_BBOX_PIXELS, &bbox );

	int y = bbox.yMax + bbox.yMin;	// Include the whitespace, to match the windows GetTextExtentPoint32()

	int x = int(face->glyph->advance.x / 64.0f);

	return (Size(x,y));
}
Example #20
0
static void compute_glyphstring_bbox(FT_Glyph *string, FT_Vector *pos,
		int len, FT_BBox *bbox)
{
	FT_BBox glyph_bbox;
	int i;

	bbox->xMin = bbox->yMin = 32000;
	bbox->xMax = bbox->yMax = -32000;

	for (i = 0; i < len; i++)
	{
		FT_Glyph_Get_CBox(string[i], FT_GLYPH_BBOX_GRIDFIT, &glyph_bbox);

		glyph_bbox.xMin += pos[i].x;
		glyph_bbox.xMax += pos[i].x;
		glyph_bbox.yMin += pos[i].y;
		glyph_bbox.yMax += pos[i].y;

		if (glyph_bbox.xMin < bbox->xMin)
			bbox->xMin = glyph_bbox.xMin;

		if (glyph_bbox.xMax > bbox->xMax)
			bbox->xMax = glyph_bbox.xMax;

		if (glyph_bbox.yMin < bbox->yMin)
			bbox->yMin = glyph_bbox.yMin;

		if (glyph_bbox.yMax > bbox->yMax)
			bbox->yMax = glyph_bbox.yMax;
	}

	if (bbox->xMin > bbox->xMax || bbox->yMin > bbox->yMax)
	{
		bbox->xMin = 0;
		bbox->xMax = 0;
		bbox->yMin = 0;
		bbox->yMax = 0;
	}
}
Example #21
0
void calculate_extents(box* b, hb_glyph_info_t glyph_info, hb_glyph_position_t glyph_pos, FT_Face ft_face, double point_size, hb_direction_t direction) {
  FT_Error error = FT_Load_Glyph(ft_face, glyph_info.codepoint, FT_LOAD_NO_SCALE);
  if (error) return;
  FT_Glyph glyph;
  error = FT_Get_Glyph(ft_face->glyph, &glyph);
  if (error) return;
  FT_BBox ft_bbox;
  FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_UNSCALED, &ft_bbox);
  FT_Fixed advance;
  FT_Get_Advance(ft_face, glyph_info.codepoint, FT_LOAD_NO_SCALE, &advance);
  const FT_Glyph_Metrics *ftmetrics = &ft_face->glyph->metrics;
  b->width = advance * point_size / ft_face->units_per_EM;
  if (direction == HB_DIRECTION_TTB) {
    FT_Get_Advance(ft_face, glyph_info.codepoint, FT_LOAD_NO_SCALE | FT_LOAD_VERTICAL_LAYOUT, &advance);
    b->height = advance * point_size / ft_face->units_per_EM;
    b->depth = 0;
  } else {
    b->height = ft_bbox.yMax * point_size / ft_face->units_per_EM;
    b->depth = -ft_bbox.yMin * point_size / ft_face->units_per_EM;
  }
  FT_Done_Glyph(glyph);
}
Example #22
0
FT_BBox
FT2Font::compute_string_bbox( ) {
  _VERBOSE("FT2Font::compute_string_bbox");
  
  FT_BBox bbox;
  /* initialize string bbox to "empty" values */
  bbox.xMin = bbox.yMin = 32000;
  bbox.xMax = bbox.yMax = -32000;
  
  for ( size_t n = 0; n < glyphs.size(); n++ ) {
    FT_BBox glyph_bbox;
    FT_Glyph_Get_CBox( glyphs[n], ft_glyph_bbox_subpixels, &glyph_bbox );
    if ( glyph_bbox.xMin < bbox.xMin ) bbox.xMin = glyph_bbox.xMin;
    if ( glyph_bbox.yMin < bbox.yMin ) bbox.yMin = glyph_bbox.yMin;
    if ( glyph_bbox.xMax > bbox.xMax ) bbox.xMax = glyph_bbox.xMax;
    if ( glyph_bbox.yMax > bbox.yMax ) bbox.yMax = glyph_bbox.yMax;
  } /* check that we really grew the string bbox */
  if ( bbox.xMin > bbox.xMax ) {
    bbox.xMin = 0; bbox.yMin = 0; bbox.xMax = 0; bbox.yMax = 0;
  } /* return string bbox */
  return bbox;
}
Example #23
0
// https://github.com/mapnik/mapnik/issues/2578
double font_face::get_ascender()
{
    set_unscaled_character_sizes();
    unsigned glyph_index = FT_Get_Char_Index(face_, 'X');

    FT_Vector pen;
    pen.x = 0;
    pen.y = 0;
    FT_Set_Transform(face_, 0, &pen);
    int e = 0;
    if (!(e = FT_Load_Glyph(face_, glyph_index, FT_LOAD_NO_HINTING)))
    {
        FT_Glyph image;
        if (!FT_Get_Glyph(face_->glyph, &image))
        {
            FT_BBox glyph_bbox;
            FT_Glyph_Get_CBox(image, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);
            FT_Done_Glyph(image);
            return 64.0 * (glyph_bbox.yMax - glyph_bbox.yMin);
        }
    }
    return face_->ascender;
}
Example #24
0
File: ft.cpp Project: nixz/covise
void FT::computeBBox(ft_string *string)
{
    int n;
    /* initialize string bbox to "empty" values */
    string->bbox.xMin = string->bbox.yMin = 32000;
    string->bbox.xMax = string->bbox.yMax = -32000;

    /* for each glyph image, compute its bounding box, */
    /* translate it, and grow the string bbox          */
    for (n = 0; n < string->num_glyphs; n++)
    {
        FT_BBox glyph_bbox;

        FT_Glyph_Get_CBox(string->glyphs[n].image, ft_glyph_bbox_pixels,
                          &glyph_bbox);
        if (glyph_bbox.xMin < string->bbox.xMin)
            string->bbox.xMin = glyph_bbox.xMin;

        if (glyph_bbox.yMin < string->bbox.yMin)
            string->bbox.yMin = glyph_bbox.yMin;

        if (glyph_bbox.xMax > string->bbox.xMax)
            string->bbox.xMax = glyph_bbox.xMax;

        if (glyph_bbox.yMax > string->bbox.yMax)
            string->bbox.yMax = glyph_bbox.yMax;
    }

    /* check that we really grew the string bbox */
    if (string->bbox.xMin > string->bbox.xMax)
    {
        string->bbox.xMin = 0;
        string->bbox.yMin = 0;
        string->bbox.xMax = 0;
        string->bbox.yMax = 0;
    }
}
Example #25
0
static GF_Glyph *ft_load_glyph(GF_FontReader *dr, u32 glyph_name)
{
	GF_Glyph *glyph;
	u32 glyph_idx;
	FT_BBox bbox;
	FT_OutlineGlyph outline;
	ft_outliner outl;
	FT_Outline_Funcs ft_outl_funcs;

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

	FT_Select_Charmap(ftpriv->active_face, FT_ENCODING_UNICODE);

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

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

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

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


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

	/*setup outliner*/
	ft_outl_funcs.shift = 0;
	ft_outl_funcs.delta = 0;
	ft_outl_funcs.move_to = ft_move_to;
	ft_outl_funcs.line_to = ft_line_to;
	ft_outl_funcs.conic_to = ft_conic_to;
	ft_outl_funcs.cubic_to = ft_cubic_to;
	outl.path = glyph->path;
	outl.ftpriv = ftpriv;

	/*FreeType is marvelous and gives back the right advance on space char !!!*/
	FT_Outline_Decompose(&outline->outline, &ft_outl_funcs, &outl);

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

	glyph->ID = glyph_name;
	glyph->utf_name = glyph_name;
	glyph->horiz_advance = ftpriv->active_face->glyph->metrics.horiAdvance;
	glyph->vert_advance = ftpriv->active_face->glyph->metrics.vertAdvance;
/*
	glyph->x = bbox.xMin;
	glyph->y = bbox.yMax;
*/
	glyph->width = ftpriv->active_face->glyph->metrics.width;
	glyph->height = ftpriv->active_face->glyph->metrics.height;
	FT_Done_Glyph((FT_Glyph) outline);
	return glyph;
}
Example #26
0
/**
 * Load glyphs corresponding to the UTF-32 codepoint code.
 */
static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code)
{
    DrawTextContext *s = ctx->priv;
    FT_BitmapGlyph bitmapglyph;
    Glyph *glyph;
    struct AVTreeNode *node = NULL;
    int ret;

    /* load glyph into s->face->glyph */
    if (FT_Load_Char(s->face, code, s->ft_load_flags))
        return AVERROR(EINVAL);

    glyph = av_mallocz(sizeof(*glyph));
    if (!glyph) {
        ret = AVERROR(ENOMEM);
        goto error;
    }
    glyph->code  = code;

    if (FT_Get_Glyph(s->face->glyph, &glyph->glyph)) {
        ret = AVERROR(EINVAL);
        goto error;
    }
    if (s->borderw) {
        glyph->border_glyph = glyph->glyph;
        if (FT_Glyph_StrokeBorder(&glyph->border_glyph, s->stroker, 0, 0) ||
            FT_Glyph_To_Bitmap(&glyph->border_glyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
            ret = AVERROR_EXTERNAL;
            goto error;
        }
        bitmapglyph = (FT_BitmapGlyph) glyph->border_glyph;
        glyph->border_bitmap = bitmapglyph->bitmap;
    }
    if (FT_Glyph_To_Bitmap(&glyph->glyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
        ret = AVERROR_EXTERNAL;
        goto error;
    }
    bitmapglyph = (FT_BitmapGlyph) glyph->glyph;

    glyph->bitmap      = bitmapglyph->bitmap;
    glyph->bitmap_left = bitmapglyph->left;
    glyph->bitmap_top  = bitmapglyph->top;
    glyph->advance     = s->face->glyph->advance.x >> 6;

    /* measure text height to calculate text_height (or the maximum text height) */
    FT_Glyph_Get_CBox(glyph->glyph, ft_glyph_bbox_pixels, &glyph->bbox);

    /* cache the newly created glyph */
    if (!(node = av_tree_node_alloc())) {
        ret = AVERROR(ENOMEM);
        goto error;
    }
    av_tree_insert(&s->glyphs, glyph, glyph_cmp, &node);

    if (glyph_ptr)
        *glyph_ptr = glyph;
    return 0;

error:
    if (glyph)
        av_freep(&glyph->glyph);

    av_freep(&glyph);
    av_freep(&node);
    return ret;
}
Example #27
0
SWFFONT* swf_LoadTrueTypeFont(const char*filename, char flashtype)
{
    FT_Face face;
    FT_Error error;
    const char* name = 0;
    FT_ULong charcode;
    FT_UInt gindex;
    SWFFONT* font;
    int t;
    int*glyph2glyph;
    int max_unicode = 0;
    int charmap = -1;

    if(ftlibrary == 0) {
	if(FT_Init_FreeType(&ftlibrary)) {
	    fprintf(stderr, "Couldn't init freetype library!\n");
	    exit(1);
	}
    }
    error = FT_New_Face(ftlibrary, filename, 0, &face);

    if(error || !face) {
	fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
	return 0;
    }
   
    int scale = flashtype?20:1;
    FT_Set_Pixel_Sizes (face, 16*loadfont_scale*scale, 16*loadfont_scale*scale);

    if(face->num_glyphs <= 0) {
	fprintf(stderr, "File %s contains %d glyphs\n", filename, (int)face->num_glyphs);
	return 0;
    }

    font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
    font->id = -1;
    font->version = flashtype?3:2;

    font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
    font->layout->bounds = (SRECT*)rfx_calloc(face->num_glyphs*sizeof(SRECT));
    font->style =  ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0)
	          |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
    font->encoding = FONT_ENCODING_UNICODE;
    font->glyph2ascii = (U16*)rfx_calloc(face->num_glyphs*sizeof(U16));
    font->maxascii = 0;
    font->glyph = (SWFGLYPH*)rfx_calloc(face->num_glyphs*sizeof(SWFGLYPH));
    if(FT_HAS_GLYPH_NAMES(face)) {
	font->glyphnames = (char**)rfx_calloc(face->num_glyphs*sizeof(char*));
    }
    
    font->layout->kerningcount = 0;
    
    name = face->family_name;
    if(!(name && *name))
        name = FT_Get_Postscript_Name(face);
    if(name && *name)
	font->name = (U8*)strdup(name);

    while(1) 
    {
    /*    // Map Glyphs to Unicode, version 1 (quick and dirty):
	int t;
	for(t=0;t<65536;t++) {
	    int index = FT_Get_Char_Index(face, t);
	    if(index>=0 && index<face->num_glyphs) {
		if(font->glyph2ascii[index]<0)
		    font->glyph2ascii[index] = t;
	    }
	}*/
	
	// Map Glyphs to Unicode, version 2 (much nicer):
	// (The third way would be the AGL algorithm, as proposed
	//  by Werner Lemberg on [email protected])

	charcode = FT_Get_First_Char(face, &gindex);
	while(gindex != 0)
	{
	    if(gindex >= 0 && gindex<face->num_glyphs) {
		if(!font->glyph2ascii[gindex]) {
		    font->glyph2ascii[gindex] = charcode;
		    if(charcode + 1 > font->maxascii) {
			font->maxascii = charcode + 1;
		    }
		}
	    }
	    charcode = FT_Get_Next_Char(face, charcode, &gindex);
	}

	/* if we didn't find a single encoding character, try
	   the font's charmaps instead. That usually means that
	   the encoding is no longer unicode. 
	   TODO: find a way to convert the encoding to unicode
	 */
	if(font->maxascii == 0 && charmap < face->num_charmaps - 1) {
	    charmap++;
	    FT_Set_Charmap(face, face->charmaps[charmap]);
	    font->encoding = 0;//anything but unicode FIXME
	} else 
	    break;
    }

    if(full_unicode)
	font->maxascii = 65535;
    
    font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
    
    for(t=0;t<font->maxascii;t++) {
	int g = FT_Get_Char_Index(face, t);
	if(!g || g>=face->num_glyphs)
	    g = -1;
	font->ascii2glyph[t] = g;
	if(g>=0) {
	    max_unicode = t+1;
	    if(!font->glyph2ascii[g]) {
		font->glyph2ascii[g] = t;
	    }
	}
    }
    font->maxascii = max_unicode;

    font->numchars = 0;

    glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));

    SRECT fontbbox = {0,0,0,0};

    for(t=0; t < face->num_glyphs; t++) {
	FT_Glyph glyph;
	FT_BBox bbox;
	char name[128];
	drawer_t draw;
	char hasname = 0;
	name[0]=0;
	if(FT_HAS_GLYPH_NAMES(face)) {
	    error = FT_Get_Glyph_Name(face, t, name, 127);
	    if(!error && name[0] && !strstr(name, "notdef")) {
		font->glyphnames[font->numchars] = strdup(name);
		hasname = 1;
	    }
	}
	if(!font->glyph2ascii[t] && !hasname && skip_unused) {
	    continue;
	}
	error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
	if(error) {
	    //tends to happen with some pdfs
	    fprintf(stderr, "Warning: Glyph %d has return code %d\n", t, error);
	    glyph=0;
	    if(skip_unused) 
		continue;
	} else {
	    error = FT_Get_Glyph(face->glyph, &glyph);
	    if(error) {
		fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
		glyph=0;
		if(skip_unused) 
		    continue;
	    }
	}

	if(glyph)
	    FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
	else
	    memset(&bbox, 0, sizeof(bbox));

	bbox.yMin = -bbox.yMin;
	bbox.yMax = -bbox.yMax;
	if(bbox.xMax < bbox.xMin) {
	    // swap
	    bbox.xMax ^= bbox.xMin;
	    bbox.xMin ^= bbox.xMax;
	    bbox.xMax ^= bbox.xMin;
	}
	if(bbox.yMax < bbox.yMin) {
	    // swap
	    bbox.yMax ^= bbox.yMin;
	    bbox.yMin ^= bbox.yMax;
	    bbox.yMax ^= bbox.yMin;
	}

	swf_Shape01DrawerInit(&draw, 0);

	//error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
	if(glyph)
	    error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
	else
	    error = 0;
	draw.finish(&draw);
	
	if(error) {
	    fprintf(stderr, "Couldn't decompose glyph %d\n", t);
	    draw.dealloc(&draw);
	    continue;
	}

#if 0
	if(bbox.xMin > 0) {
	    font->glyph[font->numchars].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
	} else {
	    font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
	}
#else
	if(glyph)
	    font->glyph[font->numchars].advance = glyph->advance.x*20/65536;
	else
	    font->glyph[font->numchars].advance = 0;
#endif
	
	SRECT b = swf_ShapeDrawerGetBBox(&draw);

	//font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
	//font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
	//font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
	//font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;

	font->layout->bounds[font->numchars] = b;
	font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw);

	swf_ExpandRect2(&fontbbox, &font->layout->bounds[font->numchars]);

	draw.dealloc(&draw);

	if(glyph)
	    FT_Done_Glyph(glyph);
	font->glyph2ascii[font->numchars] = font->glyph2ascii[t];
	glyph2glyph[t] = font->numchars;
	font->numchars++;
    }
    
    //font->layout->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
    //font->layout->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
    //font->layout->leading = font->layout->ascent + font->layout->descent;

    if(-fontbbox.ymin < 0)
        font->layout->ascent = 0;
    else
	font->layout->ascent = -fontbbox.ymin;

    if(fontbbox.ymax < 0)
        font->layout->descent = 0;
    else
	font->layout->descent = fontbbox.ymax;

    int leading = fontbbox.ymax - fontbbox.ymin;
    font->layout->leading = leading>0x7fff?0x7fff:leading;

    /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will 
	       have more memory allocated than just font->numchars, but only the first font->numchars 
	       are used/valid */

    for(t=0;t<font->maxascii;t++) {
	if(font->ascii2glyph[t]>=0) {
	    font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
	}
    }
    rfx_free(glyph2glyph);

    FT_Done_Face(face);
    FT_Done_FreeType(ftlibrary);ftlibrary=0;

    return font;
}
Example #28
0
static int LayoutLine( filter_t *p_filter,
                       paragraph_t *p_paragraph,
                       int i_start_offset, int i_end_offset,
                       line_desc_t **pp_line )
{
    if( p_paragraph->i_size <= 0 || p_paragraph->i_runs_count <= 0
     || i_start_offset >= i_end_offset
     || i_start_offset < 0 || i_start_offset >= p_paragraph->i_size
     || i_end_offset <= 0  || i_end_offset > p_paragraph->i_size )
    {
        msg_Err( p_filter,
                 "LayoutLine() invalid parameters. "
                 "Paragraph size: %d. Runs count: %d. "
                 "Start offset: %d. End offset: %d",
                 p_paragraph->i_size, p_paragraph->i_runs_count,
                 i_start_offset, i_end_offset );
        return VLC_EGENERIC;
    }

    line_desc_t *p_line = NewLine( i_end_offset - i_start_offset );

    if( !p_line )
        return VLC_ENOMEM;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    *pp_line = p_line;
    return VLC_SUCCESS;
}

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

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

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

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

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

            break;
        }

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

                i_line_start = i + 1;
                continue;
            }

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

            i_last_space = i;
            i_last_space_width = i_width;
        }

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

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

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

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

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

    *pp_lines = p_first_line;
    return VLC_SUCCESS;

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

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

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

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

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

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

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

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

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

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

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

            FreeParagraph( p_paragraph );
            p_paragraph = 0;

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

            i_paragraph_start = i + 1;
        }
    }

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

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

        i_base_line += i_max_height;
    }

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

error:
    if( p_first_line ) FreeLines( p_first_line );
    if( p_paragraph ) FreeParagraph( p_paragraph );
    return VLC_EGENERIC;
}
Example #29
0
box2d<double> text_renderer<T>::prepare_glyphs(text_path *path)
{
    //clear glyphs
    glyphs_.clear();

    FT_Matrix matrix;
    FT_Vector pen;
    FT_Error  error;

    FT_BBox bbox;
    bbox.xMin = bbox.yMin = 32000;  // Initialize these so we can tell if we
    bbox.xMax = bbox.yMax = -32000; // properly grew the bbox later

    for (int i = 0; i < path->num_nodes(); i++)
    {
        char_info_ptr c;
        double x, y, angle;

        path->vertex(&c, &x, &y, &angle);

        // TODO Enable when we have support for setting verbosity
        // MAPNIK_LOG_DEBUG(font_engine_freetype) << "text_renderer: prepare_glyphs="
        //                                        << c << "," << x << "," << y << "," << angle;

        FT_BBox glyph_bbox;
        FT_Glyph image;

        pen.x = int(x * 64);
        pen.y = int(y * 64);

        face_set_ptr faces = font_manager_.get_face_set(c->format->face_name, c->format->fontset);
        faces->set_character_sizes(c->format->text_size);

        glyph_ptr glyph = faces->get_glyph(unsigned(c->c));
        FT_Face face = glyph->get_face()->get_face();

        matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
        matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
        matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
        matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );

        FT_Set_Transform(face, &matrix, &pen);

        error = FT_Load_Glyph(face, glyph->get_index(), FT_LOAD_NO_HINTING);
        if ( error )
            continue;

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

        FT_Glyph_Get_CBox(image,ft_glyph_bbox_pixels, &glyph_bbox);
        if (glyph_bbox.xMin < bbox.xMin)
            bbox.xMin = glyph_bbox.xMin;
        if (glyph_bbox.yMin < bbox.yMin)
            bbox.yMin = glyph_bbox.yMin;
        if (glyph_bbox.xMax > bbox.xMax)
            bbox.xMax = glyph_bbox.xMax;
        if (glyph_bbox.yMax > bbox.yMax)
            bbox.yMax = glyph_bbox.yMax;

        // Check if we properly grew the bbox
        if ( bbox.xMin > bbox.xMax )
        {
            bbox.xMin = 0;
            bbox.yMin = 0;
            bbox.xMax = 0;
            bbox.yMax = 0;
        }

        // take ownership of the glyph
        glyphs_.push_back(new glyph_t(image, c->format));
    }

    return box2d<double>(bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax);
}
Example #30
0
static int
glnames(
	GLYPH *glyph_list
)
{
#define MAX_NAMELEN	1024

#ifdef XP_PSTEXT
	char          buf[1024];
	long          i;
    FT_Error      error;

#ifdef XP_ONLY_BLOCKS
    extern unsigned long xp_font_block_offset;
    extern FTFontPtr     xp_xtf;
    int                  bc; /* block counter */
    
    
    /* FixMe: This code should use PsOut_Get_FreeType_Glyph_Name() instead of
     * duplicating the code
     */
    for( bc = xp_font_block_offset ; bc < (xp_font_block_offset+256) ; bc++ ) {
        /* Remap X11 font index to FreeType font index */
        i = FTRemap(face, &xp_xtf->mapping, bc);
        
        if( i >= face->num_glyphs )
          continue;
#else
	for(i=0; i < face->num_glyphs; i++) {
#endif /* XP_ONLY_BLOCKS */
        if( FT_Has_PS_Glyph_Names(face) ) {
          error = FT_Get_Glyph_Name(face, i, buf, MAX_NAMELEN);
        }
        else
        {
          error = -1;
        }
    
		if( error ) {
          /* Check for unicode mapping
           * See Adobe document "Unicode and Glyph Names"
           * (http://partners.adobe.com/asn/tech/type/unicodegn.jsp)
           */
          if( (xp_xtf->mapping.mapping->type == FONT_ENCODING_UNICODE) &&
              (i < 0xFFFE) )
          {
            sprintf(buf, "uni%04lx", i);
          }
          else
          {
            sprintf(buf, "ch%02lx", i);
          }
		}
		glyph_list[i].name = strdup(buf);
		if(ISDBG(FT)) fprintf(stderr, "%d has name %s\n", i, buf);
		if (glyph_list[i].name == NULL) {
			fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
			exit(255);
		}
	}

	return 0;
#else
	char bf[1024];
	long i;

	if( ! FT_HAS_GLYPH_NAMES(face) ) {
		WARNING_1 fprintf(stderr, "Font has no glyph names\n");
		return 1;
	}

	for(i=0; i < face->num_glyphs; i++) {
		if( FT_Get_Glyph_Name(face, i, bf, MAX_NAMELEN) || bf[0]==0 ) {
			sprintf(bf, "_g_%d", i);
			WARNING_2 fprintf(stderr,
				"Glyph No. %d has no postscript name, becomes %s\n", i, bf);
		}
		glyph_list[i].name = strdup(bf);
		if(ISDBG(FT)) fprintf(stderr, "%d has name %s\n", i, bf);
		if (glyph_list[i].name == NULL) {
			fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
			exit(255);
		}
	}

	return 0;
#endif /* XP_PSTEXT */
}

/*
 * Get the metrics of the glyphs.
 */

static void
glmetrics(
	GLYPH *glyph_list
)
{
	GLYPH          *g;
	int i;
	FT_Glyph_Metrics *met;
	FT_BBox bbox;
	FT_Glyph gly;

#ifdef XP_ONLY_BLOCKS
    extern unsigned long xp_font_block_offset;
    extern FTFontPtr     xp_xtf;
    int                  bc; /* block counter */
    
    for( bc = xp_font_block_offset ; bc < (xp_font_block_offset+256) ; bc++ ) {
        /* Remap X11 font index to FreeType font index */
        i = FTRemap(face, &xp_xtf->mapping, bc);
        
        if( i >= face->num_glyphs )
          continue;
        
#else
	for(i=0; i < face->num_glyphs; i++) {
#endif /* XP_ONLY_BLOCKS */
		g = &(glyph_list[i]);

		if( FT_Load_Glyph(face, i, FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE) ) {
			fprintf(stderr, "Can't load glyph %s, skipped\n", g->name);
			continue;
		}

		met = &face->glyph->metrics;

		if(FT_HAS_HORIZONTAL(face)) {
			g->width = met->horiAdvance;
			g->lsb = met->horiBearingX;
		} else {
			WARNING_2 fprintf(stderr, "Glyph %s has no horizontal metrics, guessed them\n", g->name);
			g->width = met->width;
			g->lsb = 0;
		}

		if( FT_Get_Glyph(face->glyph, &gly) ) {
			fprintf(stderr, "Can't access glyph %s bbox, skipped\n", g->name);
			continue;
		}

		FT_Glyph_Get_CBox(gly, ft_glyph_bbox_unscaled, &bbox);
		g->xMin = bbox.xMin;
		g->yMin = bbox.yMin;
		g->xMax = bbox.xMax;
		g->yMax = bbox.yMax;

		g->ttf_pathlen = face->glyph->outline.n_points;
	}
}

/*
 * Get the original encoding of the font. 
 * Returns 1 for if the original encoding is Unicode, 2 if the
 * original encoding is other 16-bit, 0 if 8-bit.
 */

static int
glenc(
	GLYPH *glyph_list,
	int *encoding,
	int *unimap
)
{
#ifdef XP_PSTEXT
	int                  i,
                         e;
	unsigned             code;
    extern FTFontPtr     xp_xtf;
    extern unsigned long xp_font_block_offset;
        
    enc_found = 1;
    enc_type  = 0;
    
	for(i=0; i<ENCTABSZ; i++) {
		if(encoding[i] != -1)
			continue;

        /* Remap X11 font index to FreeType font index */
        code = FTRemap(face, &xp_xtf->mapping, xp_font_block_offset+i);

		if(code == 0)
			continue; /* .notdef */

		encoding[i] = code;
	}
        
	return enc_type;
#else
	int i, e;
	unsigned code;

	if(ISDBG(FT)) 
		for(e=0; e < face->num_charmaps; e++) {
			fprintf(stderr, "found encoding pid=%d eid=%d\n", 
				face->charmaps[e]->platform_id,
				face->charmaps[e]->encoding_id);
		}

	if(enc_found)
		goto populate_map;

	enc_type = 0;

	/* first check for an explicit PID/EID */

	if(force_pid != -1) {
		for(e=0; e < face->num_charmaps; e++) {
			if(face->charmaps[e]->platform_id == force_pid
			&& face->charmaps[e]->encoding_id == force_eid) {
				WARNING_1 fprintf(stderr, "Found Encoding PID=%d/EID=%d\n", 
					force_pid, force_eid);
				if( FT_Set_Charmap(face, face->charmaps[e]) ) {
					fprintf(stderr, "**** Cannot set charmap in FreeType ****\n");
					exit(1);
				}
				enc_type = 1;
				goto populate_map;
			}
		}
		fprintf(stderr, "*** TTF encoding table PID=%d/EID=%d not found\n", 
			force_pid, force_eid);
		exit(1);
	}

	/* next check for a direct Adobe mapping */

	if(!forcemap) {
		for(e=0; e < face->num_charmaps; e++) {
			if(face->charmaps[e]->encoding == ft_encoding_adobe_custom) {
				WARNING_1 fputs("Found Adobe Custom Encoding\n", stderr);
				if( FT_Set_Charmap(face, face->charmaps[e]) ) {
					fprintf(stderr, "**** Cannot set charmap in FreeType ****\n");
					exit(1);
				}
				goto populate_map;
			}
		}
	}

	for(e=0; e < face->num_charmaps; e++) {
		if(face->charmaps[e]->platform_id == 3) {
			switch(face->charmaps[e]->encoding_id) {
			case 0:
				WARNING_1 fputs("Found Symbol Encoding\n", stderr);
				break;
			case 1:
				WARNING_1 fputs("Found Unicode Encoding\n", stderr);
				enc_type = 1;
				break;
			default:
				WARNING_1 {
					fprintf(stderr,
					"****MS Encoding ID %d not supported****\n",
						face->charmaps[e]->encoding_id);
					fputs("Treating it like Symbol encoding\n", stderr);
				}
				break;
			}
			break;
		}
	}
	if(e >= face->num_charmaps) {
		WARNING_1 fputs("No Microsoft encoding, using first encoding available\n", stderr);
		e = 0;
	}
	
	if( FT_Set_Charmap(face, face->charmaps[e]) ) {
		fprintf(stderr, "**** Cannot set charmap in FreeType ****\n");
		exit(1);
	}

populate_map:
	enc_found = 1;
	for(i=0; i<ENCTABSZ; i++) {
		if(encoding[i] != -1)
			continue;
		if(enc_type == 1 || forcemap) {
			code = unimap[i];
			if(code == (unsigned) -1)
				continue;
		} else
			code = i;

		code = FT_Get_Char_Index(face, code);
		if(0 && ISDBG(FT)) fprintf(stderr, "code of %3d is %3d\n", i, code);
		if(code == 0)
			continue; /* .notdef */
		encoding[i] = code;
	}

	return enc_type;
#endif /* XP_PSTEXT */
}