示例#1
0
文件: ftsynth.c 项目: silview/C100A
  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;
  }
示例#2
0
文件: FTFontExt.cpp 项目: CCQIU/CGE
// 让一个字体槽加粗,并且填充其他的大小属性
void New_GlyphSlot_Embolden( FT_GlyphSlot  slot, const FT_Pos str_x, const FT_Pos str_y)
{
    FT_Library library;
    FT_Face face;
    FT_Error error;

	FT_BBox newBox, oldBox;
    FT_Pos xstr = (FT_Pos)str_x;
	FT_Pos ystr = (FT_Pos)str_y;

	CC_ASSERT(slot != NULL);

	library = slot->library;
	face    = slot->face;

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

    if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) {
        FT_Outline_Get_CBox(&slot->outline , &oldBox);
        error = New_FT_Outline_Embolden( &slot->outline, xstr , ystr);
        if ( error )
            return;

        FT_Outline_Get_CBox(&slot->outline , &newBox);
        xstr = (newBox.xMax - newBox.xMin) - (oldBox.xMax - oldBox.xMin);
        ystr = (newBox.yMax - newBox.yMin) - (oldBox.yMax - oldBox.yMin);
    } 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_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;
}
示例#3
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;
				}
示例#4
0
文件: ftview.c 项目: genesi/freetype
  static FT_Error
  Render_Embolden( int  num_indices,
                   int  first_index )
  {
    int           start_x, start_y, step_y, x, y;
    int           i;
    FT_Size       size;
    FT_Face       face;
    FT_GlyphSlot  slot;

    FT_Pos  xstr, ystr;


    error = FTDemo_Get_Size( handle, &size );

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

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

    ystr = status.ptsize * status.res / 72;
    xstr = status.xbold_factor * ystr;
    ystr = status.ybold_factor * ystr;

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


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

      error = FT_Load_Glyph( face, gindex, handle->load_flags );
      if ( !error )
      {
        /* this is essentially the code of function */
        /* `FT_GlyphSlot_Embolden'                  */

        if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
        {
          error = FT_Outline_EmboldenXY( &slot->outline, xstr, ystr );
          /* ignore error */
        }
        else if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
        {
          /* round to full pixels */
          xstr &= ~63;
          ystr &= ~63;

          error = FT_GlyphSlot_Own_Bitmap( slot );
          if ( error )
            goto Next;

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

        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.horiAdvance  += xstr;
        slot->metrics.vertAdvance  += ystr;

        if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
          slot->bitmap_top += ystr >> 6;

        error = FTDemo_Draw_Slot( handle, display, slot, &x, &y );

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

          if ( Y_TOO_LONG( y, size, display ) )
            break;
        }
      }
      else
    Next:
        status.Fail++;
    }
示例#5
0
文件: Font.cpp 项目: akadjoker/waxe
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;
}
示例#6
0
void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGlyph& glyph) {
    const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
    const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);

    switch ( face->glyph->format ) {
        case FT_GLYPH_FORMAT_OUTLINE: {
            FT_Outline* outline = &face->glyph->outline;
            FT_BBox     bbox;
            FT_Bitmap   target;

            if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) {
                emboldenOutline(face, outline);
            }

            int dx = 0, dy = 0;
            if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
                dx = SkFixedToFDot6(glyph.getSubXFixed());
                dy = SkFixedToFDot6(glyph.getSubYFixed());
                // negate dy since freetype-y-goes-up and skia-y-goes-down
                dy = -dy;
            }
            FT_Outline_Get_CBox(outline, &bbox);
            /*
                what we really want to do for subpixel is
                    offset(dx, dy)
                    compute_bounds
                    offset(bbox & !63)
                but that is two calls to offset, so we do the following, which
                achieves the same thing with only one offset call.
            */
            FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
                                          dy - ((bbox.yMin + dy) & ~63));

            if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
                FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD);
                if (fPreBlend.isApplicable()) {
                    copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert,
                                       fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                } else {
                    copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVert,
                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                }
            } else {
                target.width = glyph.fWidth;
                target.rows = glyph.fHeight;
                target.pitch = glyph.rowBytes();
                target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
                target.pixel_mode = compute_pixel_mode(
                                                (SkMask::Format)fRec.fMaskFormat);
                target.num_grays = 256;

                memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
                FT_Outline_Get_Bitmap(face->glyph->library, outline, &target);
            }
        } break;

        case FT_GLYPH_FORMAT_BITMAP: {
            if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) {
                FT_GlyphSlot_Own_Bitmap(face->glyph);
                FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap, kBitmapEmboldenStrength, 0);
            }
            SkASSERT_CONTINUE(glyph.fWidth == face->glyph->bitmap.width);
            SkASSERT_CONTINUE(glyph.fHeight == face->glyph->bitmap.rows);
            SkASSERT_CONTINUE(glyph.fTop == -face->glyph->bitmap_top);
            SkASSERT_CONTINUE(glyph.fLeft == face->glyph->bitmap_left);

            const uint8_t*  src = (const uint8_t*)face->glyph->bitmap.buffer;
            uint8_t*        dst = (uint8_t*)glyph.fImage;

            if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ||
                (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO &&
                 glyph.fMaskFormat == SkMask::kBW_Format)) {
                unsigned    srcRowBytes = face->glyph->bitmap.pitch;
                unsigned    dstRowBytes = glyph.rowBytes();
                unsigned    minRowBytes = SkMin32(srcRowBytes, dstRowBytes);
                unsigned    extraRowBytes = dstRowBytes - minRowBytes;

                for (int y = face->glyph->bitmap.rows - 1; y >= 0; --y) {
                    memcpy(dst, src, minRowBytes);
                    memset(dst + minRowBytes, 0, extraRowBytes);
                    src += srcRowBytes;
                    dst += dstRowBytes;
                }
            } else if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO &&
                       glyph.fMaskFormat == SkMask::kA8_Format) {
                for (int y = 0; y < face->glyph->bitmap.rows; ++y) {
                    uint8_t byte = 0;
                    int bits = 0;
                    const uint8_t* src_row = src;
                    uint8_t* dst_row = dst;

                    for (int x = 0; x < face->glyph->bitmap.width; ++x) {
                        if (!bits) {
                            byte = *src_row++;
                            bits = 8;
                        }

                        *dst_row++ = byte & 0x80 ? 0xff : 0;
                        bits--;
                        byte <<= 1;
                    }

                    src += face->glyph->bitmap.pitch;
                    dst += glyph.rowBytes();
                }
            } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
                if (fPreBlend.isApplicable()) {
                    copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert,
                                       fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                } else {
                    copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVert,
                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                }
            } else {
                SkDEBUGFAIL("unknown glyph bitmap transform needed");
            }
        } break;

    default:
        SkDEBUGFAIL("unknown glyph format");
        memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
        return;
    }

// We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
// it is optional
#if defined(SK_GAMMA_APPLY_TO_A8)
    if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) {
        uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
        unsigned rowBytes = glyph.rowBytes();

        for (int y = glyph.fHeight - 1; y >= 0; --y) {
            for (int x = glyph.fWidth - 1; x >= 0; --x) {
                dst[x] = fPreBlend.fG[dst[x]];
            }
            dst += rowBytes;
        }
    }
#endif
}
示例#7
0
static BOOL ft_get_char(void *p_priv,
  u16 char_code, rsc_fstyle_t *p_fstyle, rsc_char_info_t *p_info)
{
  RET_CODE ret = SUCCESS;
  ft_cache_t *p_vf_cache = NULL;
  u32 i = 0, ckey = 0;
  ft_priv_t *p_vf = (ft_priv_t *)p_priv;
  FT_Stroker p_stroker = {0};
  FT_Raster_Params params = {0};  
  FT_Glyph p_glyph = {0};
  spans_t spans = {0};
  FT_BBox bbox_fg = {0}, bbox_bg = {0};
  u16 w_bg = 0, w_fg = 0, h_bg = 0, h_fg = 0;
  FT_Matrix matrix = {0};
  rsc_font_t hdr_font = {{0}};
  u8 *p_font = NULL;

  MT_ASSERT(p_vf != NULL);

  if(ft_hit_cache(p_priv, char_code, p_fstyle, p_info))
  {
    p_info->ckey = p_fstyle->color ? 0 : 1;
    p_info->bpp = p_vf->bpp;
    
    return TRUE;
  }

  MT_ASSERT(p_fstyle->width <= p_vf->max_width);
  MT_ASSERT(p_fstyle->height <= p_vf->max_height);
  
  if(!rsc_get_font(p_vf->rsc_handle, p_fstyle->font_id, &hdr_font, &p_font))
  {
    return FALSE;
  }

  MT_ASSERT(hdr_font.type == FONT_VECTOR);

  if(!ft_check_char(p_priv, char_code, p_font, hdr_font.head.org_size, p_fstyle))
  {
    return FALSE;
  }

  p_vf_cache = ft_insert_cache(p_priv, char_code, p_fstyle);

  ckey = p_fstyle->color ? 0 : 1;

  MT_ASSERT(p_vf_cache != NULL);

  
  if((p_fstyle->attr & VFONT_ITALIC) != 0)
  {
    matrix.xx = 0x10000L;
    matrix.xy = 0x1000L;
    matrix.yx = 0;
    matrix.yy = 0x10000L;
    FT_Set_Transform(p_vf->p_face, &matrix, 0);  
  }
  else
  {
    FT_Set_Transform(p_vf->p_face, NULL, 0);  
  }

  ret = FT_Set_Pixel_Sizes(p_vf->p_face, p_vf_cache->char_width, p_vf_cache->char_height);
  MT_ASSERT(ret == SUCCESS);

  if(((p_fstyle->attr & VFONT_STROK) == 0) || (p_vf->is_alpha_spt == FALSE))
  {
    if(p_vf->is_alpha_spt)
    {
      ret = FT_Load_Char(p_vf->p_face, char_code, FT_LOAD_RENDER);
      p_info->is_alpha_spt = TRUE;    
    }
    else
    {
      ret = FT_Load_Char(p_vf->p_face, char_code, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
      p_info->is_alpha_spt = FALSE;
    }

    if((p_fstyle->attr & VFONT_BOLD) != 0)
    {
      FT_Bitmap_Embolden(p_vf->p_library, &p_vf->p_face->glyph->bitmap, 64, 64);    
    }
    
    MT_ASSERT(ret == SUCCESS);

    p_info->height = p_vf->p_face->glyph->bitmap.rows;
    p_info->width = p_vf->p_face->glyph->bitmap.width;
    p_info->xoffset = p_vf->p_face->glyph->bitmap_left;
    p_info->yoffset = ((p_vf->p_face->size->metrics.ascender
     - p_vf->p_face->glyph->metrics.horiBearingY) >> 6);
    p_info->pitch = p_vf->max_width * p_vf->bpp >> 3;
    p_info->alpha_pitch = p_vf->max_width;
    p_info->x_step = ((p_vf->p_face->glyph->advance.x) >> 6);
    p_info->step_width = p_vf->p_face->glyph->metrics.horiAdvance >> 6;
    //p_info->step_height = p_vf->p_face->size->metrics.y_ppem;
    p_info->step_height = p_vf->p_face->size->metrics.height >> 6;

    p_vf_cache->pitch = p_info->pitch;
    p_vf_cache->alpha_pitch = p_info->alpha_pitch;
    p_vf_cache->xoff = p_info->xoffset;
    p_vf_cache->yoff = p_info->yoffset;
    p_vf_cache->step_width = p_info->step_width;
    p_vf_cache->step_height = p_info->step_height;
    p_vf_cache->x_step = p_info->x_step;
    p_vf_cache->width = p_info->width;
    p_vf_cache->height = p_info->height;  
    p_vf_cache->color = p_fstyle->color;
    
    if(p_vf->is_alpha_spt)
    {
      for(i = 0; i < p_vf->p_face->glyph->bitmap.rows; i++)
      {
        memcpy((u8 *)p_vf_cache->p_alpha + i * p_vf->max_width,
          p_vf->p_face->glyph->bitmap.buffer + i * p_vf->p_face->glyph->bitmap.pitch,
          p_vf->p_face->glyph->bitmap.pitch);
      }

      for(i = 0; i < (p_vf->max_height * p_vf->max_width); i++)
      {
        if(p_vf->bpp == 32)
        {
          *((u32 *)(p_vf_cache->p_char) + i) = p_fstyle->color;
        }
        else if(p_vf->bpp == 16)
        {
          *((u16 *)(p_vf_cache->p_char) + i) = p_fstyle->color;
        }
        
      }    
    }
    else
    {
      if(p_vf->bpp == 32)
      {
        mono_to_u32buf(p_vf->p_face->glyph->bitmap.buffer,
          p_vf->p_face->glyph->bitmap.width, p_vf->p_face->glyph->bitmap.rows,
          p_vf->p_face->glyph->bitmap.pitch,
          p_vf_cache->p_char, p_vf->max_width * 4, p_fstyle->color, ckey);
      }
      else if(p_vf->bpp == 16)
      {
        mono_to_u16buf(p_vf->p_face->glyph->bitmap.buffer,
          p_vf->p_face->glyph->bitmap.width, p_vf->p_face->glyph->bitmap.rows,
          p_vf->p_face->glyph->bitmap.pitch,
          p_vf_cache->p_char, p_vf->max_width * 2, p_fstyle->color, ckey);
      }
    }

    p_info->p_alpha = p_vf_cache->p_alpha;
    p_info->p_char = p_vf_cache->p_char;
    p_info->p_strok_alpha = NULL;
    p_info->p_strok_char = NULL;
  }
  else if((p_fstyle->attr & VFONT_STROK) != 0)  
示例#8
0
//
// 2015-04-18  note by Paolo
//
// The original code from xcsoar was not spacing characters correctly in LK.
// I have no idea if the problem exists in xcsoar, but we had to fix it here.
// After quite some time, and frustration reading the confusing docs of FreeType,
// I came to this solution which is much more accurate.
// We use subpixels assuming we are always grid-aligned, which is true for our case.
// Kerning does work, but we must always check that we are not going below the 
// available space, to avoid overlapping previous glyph. This is necessary since
// the bitmap operations are copying, not merging, bitmaps. I have no idea how 
// Windows is doing this, apparently microsoft does not merge glyphs too.
// Hinting is required to keep vertical alignement, which may hide a bug.
// I am not sure if all of this (long and complicated) work is correct or it is instead
// a workaround for a more complex problem existing elsewhere.
// However it does work for us, against all odds.
// Update april 21st: merging instead of copying makes the kerning process working fine.
//
void
Font::Render(const TCHAR *text, const PixelSize size, void *_buffer) const
{
  assert(text != nullptr);
#ifndef _UNICODE
  assert(ValidateUTF8(text));
#endif

  uint8_t *buffer = (uint8_t *)_buffer;
  std::fill_n(buffer, BufferSize(size), 0);

  const FT_Face face = this->face;
  const FT_GlyphSlot glyph = face->glyph;

#ifdef USE_KERNING
  bool use_kerning = FT_HAS_KERNING(face);
  unsigned prev_index = 0;
#endif

  int x = 0;
#ifdef FIX_HINTING
  FT_Pos prev_rsb_delta=0;
#endif


#ifndef ENABLE_OPENGL
  const Poco::ScopedLock<Poco::Mutex> protect(freetype_mutex);
#endif


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

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

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

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

    const FT_Glyph_Metrics metrics = glyph->metrics;

#ifdef USE_KERNING
    if (use_kerning && x) {
      if (prev_index != 0) {
        FT_Vector delta;
        FT_Get_Kerning(face, prev_index, i, ft_kerning_default, &delta);
        #ifdef LIGHT_KERNING
        if (-delta.x <= metrics.horiBearingX)
            x += delta.x ;
        else
            x -= (metrics.horiBearingX + 64);
        #else
            x += delta.x;
        #endif
      }
    }
    prev_index = i;
#endif


#ifdef FIX_HINTING
    if (prev_rsb_delta - glyph->lsb_delta >= 32 )
        x -= 64;// >> 6;
    else if ( prev_rsb_delta - glyph->lsb_delta < -32 )
        x += 64;// >> 6;

    prev_rsb_delta = glyph->rsb_delta;
#endif

    error = FT_Render_Glyph(glyph, render_mode);
    if (error)
      continue;
    /* 
     *  32,  0  = Microsoft GDI weight=600 (64=32)
     */
    if (demibold) FT_Bitmap_Embolden(ft_library,&glyph->bitmap, 32,0);

    RenderGlyph((uint8_t *)buffer, size.cx, size.cy,
#ifdef USE_KERNING
        glyph, (x >> 6)+glyph->bitmap_left , ascent_height - FT_FLOOR(metrics.horiBearingY));

    x += glyph->advance.x; // equivalent to metrics.horiAdvance
#else
        glyph, (x + metrics.horiBearingX ) >> 6 , ascent_height - FT_FLOOR(metrics.horiBearingY));

    x += (metrics.width > metrics.horiAdvance ? metrics.width : metrics.horiAdvance);
#endif

  }
}
示例#9
0
文件: say_font.c 项目: Spooner/ray
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;
}
示例#10
0
文件: Font.cpp 项目: PKEuS/SFML
Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, float outlineThickness) const
{
    // The glyph to return
    Glyph glyph;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    // Delete the FT glyph
    FT_Done_Glyph(glyphDesc);

    // Done :)
    return glyph;
}
示例#11
0
void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGlyph& glyph) {
    const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
    const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);

    switch ( face->glyph->format ) {
        case FT_GLYPH_FORMAT_OUTLINE: {
            FT_Outline* outline = &face->glyph->outline;
            FT_BBox     bbox;
            FT_Bitmap   target;

            if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
                !(face->style_flags & FT_STYLE_FLAG_BOLD)) {
                emboldenOutline(face, outline);
            }

            int dx = 0, dy = 0;
            if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
                dx = SkFixedToFDot6(glyph.getSubXFixed());
                dy = SkFixedToFDot6(glyph.getSubYFixed());
                // negate dy since freetype-y-goes-up and skia-y-goes-down
                dy = -dy;
            }
            FT_Outline_Get_CBox(outline, &bbox);
            /*
                what we really want to do for subpixel is
                    offset(dx, dy)
                    compute_bounds
                    offset(bbox & !63)
                but that is two calls to offset, so we do the following, which
                achieves the same thing with only one offset call.
            */
            FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
                                          dy - ((bbox.yMin + dy) & ~63));

            if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
                FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD);
                SkMask mask;
                glyph.toMask(&mask);
                if (fPreBlend.isApplicable()) {
                    copyFT2LCD16<true>(face->glyph->bitmap, mask, doBGR,
                                       fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                } else {
                    copyFT2LCD16<false>(face->glyph->bitmap, mask, doBGR,
                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                }
            } else {
                target.width = glyph.fWidth;
                target.rows = glyph.fHeight;
                target.pitch = glyph.rowBytes();
                target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
                target.pixel_mode = compute_pixel_mode( (SkMask::Format)fRec.fMaskFormat);
                target.num_grays = 256;

                memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
                FT_Outline_Get_Bitmap(face->glyph->library, outline, &target);
            }
        } break;

        case FT_GLYPH_FORMAT_BITMAP: {
            FT_Pixel_Mode pixel_mode = static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel_mode);
            SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);

            // Assume that the other formats do not exist.
            SkASSERT(FT_PIXEL_MODE_MONO == pixel_mode ||
                     FT_PIXEL_MODE_GRAY == pixel_mode ||
                     FT_PIXEL_MODE_BGRA == pixel_mode);

            // These are the only formats this ScalerContext should request.
            SkASSERT(SkMask::kBW_Format == maskFormat ||
                     SkMask::kA8_Format == maskFormat ||
                     SkMask::kARGB32_Format == maskFormat ||
                     SkMask::kLCD16_Format == maskFormat);

            if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
                !(face->style_flags & FT_STYLE_FLAG_BOLD))
            {
                FT_GlyphSlot_Own_Bitmap(face->glyph);
                FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap,
                                   kBitmapEmboldenStrength, 0);
            }

            // If no scaling needed, directly copy glyph bitmap.
            if (glyph.fWidth == face->glyph->bitmap.width &&
                glyph.fHeight == face->glyph->bitmap.rows &&
                glyph.fTop == -face->glyph->bitmap_top &&
                glyph.fLeft == face->glyph->bitmap_left)
            {
                SkMask dstMask;
                glyph.toMask(&dstMask);
                copyFTBitmap(face->glyph->bitmap, dstMask);
                break;
            }

            // Otherwise, scale the bitmap.

            // Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB)
            SkBitmap unscaledBitmap;
            unscaledBitmap.setConfig(SkBitmapConfig_for_FTPixelMode(pixel_mode),
                                     face->glyph->bitmap.width, face->glyph->bitmap.rows);
            unscaledBitmap.allocPixels();

            SkMask unscaledBitmapAlias;
            unscaledBitmapAlias.fImage = reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels());
            unscaledBitmapAlias.fBounds.set(0, 0, unscaledBitmap.width(), unscaledBitmap.height());
            unscaledBitmapAlias.fRowBytes = unscaledBitmap.rowBytes();
            unscaledBitmapAlias.fFormat = SkMaskFormat_for_SkBitmapConfig(unscaledBitmap.config());
            copyFTBitmap(face->glyph->bitmap, unscaledBitmapAlias);

            // Wrap the glyph's mask in a bitmap, unless the glyph's mask is BW or LCD.
            // BW requires an A8 target for resizing, which can then be down sampled.
            // LCD should use a 4x A8 target, which will then be down sampled.
            // For simplicity, LCD uses A8 and is replicated.
            int bitmapRowBytes = 0;
            if (SkMask::kBW_Format != maskFormat && SkMask::kLCD16_Format != maskFormat) {
                bitmapRowBytes = glyph.rowBytes();
            }
            SkBitmap dstBitmap;
            dstBitmap.setConfig(SkBitmapConfig_for_SkMaskFormat(maskFormat),
                                glyph.fWidth, glyph.fHeight, bitmapRowBytes);
            if (SkMask::kBW_Format == maskFormat || SkMask::kLCD16_Format == maskFormat) {
                dstBitmap.allocPixels();
            } else {
                dstBitmap.setPixels(glyph.fImage);
            }

            // Scale unscaledBitmap into dstBitmap.
            SkCanvas canvas(dstBitmap);
            canvas.clear(SK_ColorTRANSPARENT);
            canvas.scale(SkIntToScalar(glyph.fWidth) / SkIntToScalar(face->glyph->bitmap.width),
                         SkIntToScalar(glyph.fHeight) / SkIntToScalar(face->glyph->bitmap.rows));
            SkPaint paint;
            paint.setFilterLevel(SkPaint::kLow_FilterLevel);
            canvas.drawBitmap(unscaledBitmap, 0, 0, &paint);

            // If the destination is BW or LCD, convert from A8.
            if (SkMask::kBW_Format == maskFormat) {
                // Copy the A8 dstBitmap into the A1 glyph.fImage.
                SkMask dstMask;
                glyph.toMask(&dstMask);
                packA8ToA1(dstMask, dstBitmap.getAddr8(0, 0), dstBitmap.rowBytes());
            } else if (SkMask::kLCD16_Format == maskFormat) {
                // Copy the A8 dstBitmap into the LCD16 glyph.fImage.
                uint8_t* src = dstBitmap.getAddr8(0, 0);
                uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
                for (int y = dstBitmap.height(); y --> 0;) {
                    for (int x = 0; x < dstBitmap.width(); ++x) {
                        dst[x] = grayToRGB16(src[x]);
                    }
                    dst = (uint16_t*)((char*)dst + glyph.rowBytes());
                    src += dstBitmap.rowBytes();
                }
            }

        } break;

        default:
            SkDEBUGFAIL("unknown glyph format");
            memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
            return;
    }

// We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
// it is optional
#if defined(SK_GAMMA_APPLY_TO_A8)
    if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) {
        uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
        unsigned rowBytes = glyph.rowBytes();

        for (int y = glyph.fHeight - 1; y >= 0; --y) {
            for (int x = glyph.fWidth - 1; x >= 0; --x) {
                dst[x] = fPreBlend.fG[dst[x]];
            }
            dst += rowBytes;
        }
    }
#endif
}
示例#12
0
文件: ft_layout.c 项目: Mrhjx2/pygame
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;
}