Example #1
0
File: ttf.cpp Project: jjardon/eos
TTFRenderer::TTFRenderer(Common::SeekableReadStream &ttfFile, int height) :
	_library(0), _face(0), _fileBuffer(0),
	_width(0), _height(0), _ascent(0), _descent(0) {

	// Initialize a library object of FreeType2
	if (FT_Init_FreeType(&_library))
		throw Common::Exception("TTFRenderer: Could not init freetype2");

	const uint32 size = ttfFile.size();
	_fileBuffer = new uint8[size];
	if (!_fileBuffer) {
		FT_Done_FreeType(_library);

		throw Common::Exception("TTFRenderer: Out of memory");
	}

	if (ttfFile.read(_fileBuffer, size) != size) {
		FT_Done_FreeType(_library);
		delete[] _fileBuffer;

		throw Common::kReadError;
	}

	if (FT_New_Memory_Face(_library, _fileBuffer, size, 0, &_face)) {
		FT_Done_FreeType(_library);
		delete[] _fileBuffer;

		throw Common::Exception("TTFRenderer: Could not load font file");
	}

	// We only support scalable fonts.
	if (!FT_IS_SCALABLE(_face)) {
		FT_Done_Face(_face);
		FT_Done_FreeType(_library);
		delete[] _fileBuffer;

		throw Common::Exception("TTFRenderer: Font is not scalable");
	}

	// Set the font height
	if (FT_Set_Char_Size(_face, 0, height * 64, 0, 0)) {
		FT_Done_Face(_face);
		FT_Done_FreeType(_library);
		delete[] _fileBuffer;

		throw Common::Exception("TTFRenderer: Setting height to %d failed", height);
	}

	FT_Fixed yScale = _face->size->metrics.y_scale;

	_ascent  = ftCeil26_6(FT_MulFix(_face->ascender, yScale));
	_descent = ftCeil26_6(FT_MulFix(_face->descender, yScale));

	_width  = ftCeil26_6(FT_MulFix(_face->max_advance_width, _face->size->metrics.x_scale));
	_height = _ascent - _descent + 1;
}
Example #2
0
bool TrueTypeFont::setSize(int height) {
	if (FT_Set_Char_Size(_sjisFont, 0, height * 64, 0, 0)) {
		warning("Could not initialize font for height %d", height);
		return false;
	}

	FT_Fixed yScale = _sjisFont->size->metrics.y_scale;
	_ascent = ftCeil26_6(FT_MulFix(_sjisFont->ascender, yScale));
	_descent = ftCeil26_6(FT_MulFix(_sjisFont->descender, yScale));

	_width = ftCeil26_6(FT_MulFix(_sjisFont->max_advance_width, _sjisFont->size->metrics.x_scale));
	_height = _ascent - _descent + 1;

	return true;
}
Example #3
0
void TTFRenderer::getFaceMetrics(int &advance, int &yOffset, int &xMin) const {
	FT_Glyph_Metrics &metrics = _face->glyph->metrics;

	xMin    = ftFloor26_6(metrics.horiBearingX);
	yOffset = _ascent - ftFloor26_6(metrics.horiBearingY);
	advance = ftCeil26_6(metrics.horiAdvance);
}
Example #4
0
File: ttf.cpp Project: jjardon/eos
void TTFRenderer::getFaceMetrics(int &advance, int &yOffset, int &xMin) const {
	FT_Glyph_Metrics &metrics = _face->glyph->metrics;

	    xMin = ftFloor26_6(metrics.horiBearingX);
	int xMax = xMin + ftCeil26_6(metrics.width);

	yOffset = _ascent - ftFloor26_6(metrics.horiBearingY);
	advance = ftCeil26_6(metrics.horiAdvance);

	// In case we got a negative xMin we adjust that, this might make some
	// characters look a bit odd, but it's the only way we can ensure no
	// invalid memory gets written to with the current font API
	if (xMin < 0) {
		xMax -= xMin;
		xMin = 0;

		if (xMax > advance)
			advance = xMax;
	}
}
Example #5
0
bool TTFFont::cacheGlyph(Glyph &glyph, FT_UInt &slot, uint chr) {
	slot = FT_Get_Char_Index(_face, chr);
	if (!slot)
		return false;

	// We use the light target and render mode to improve the looks of the
	// glyphs. It is most noticable in FreeSansBold.ttf, where otherwise the
	// 't' glyph looks like it is cut off on the right side.
	if (FT_Load_Glyph(_face, slot, (_monochrome ? FT_LOAD_TARGET_MONO : FT_LOAD_TARGET_LIGHT)))
		return false;

	if (FT_Render_Glyph(_face->glyph, (_monochrome ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_LIGHT)))
		return false;

	if (_face->glyph->format != FT_GLYPH_FORMAT_BITMAP)
		return false;

	FT_Glyph_Metrics &metrics = _face->glyph->metrics;

	glyph.xOffset = _face->glyph->bitmap_left;
	int xMax = glyph.xOffset + ftCeil26_6(metrics.width);
	glyph.yOffset = _ascent - _face->glyph->bitmap_top;

	glyph.advance = ftCeil26_6(_face->glyph->advance.x);

	// In case we got a negative xMin we adjust that, this might make some
	// characters make a bit odd, but it's the only way we can assure no
	// invalid memory writes with the current font API
	if (glyph.xOffset < 0) {
		xMax -= glyph.xOffset;
		glyph.xOffset = 0;

		if (xMax > glyph.advance)
			glyph.advance = xMax;
	}

	const FT_Bitmap &bitmap = _face->glyph->bitmap;
	glyph.image.create(bitmap.width, bitmap.rows, PixelFormat::createFormatCLUT8());

	const uint8 *src = bitmap.buffer;
	int srcPitch = bitmap.pitch;
	if (srcPitch < 0) {
		src += (bitmap.rows - 1) * srcPitch;
		srcPitch = -srcPitch;
	}

	uint8 *dst = (uint8 *)glyph.image.getBasePtr(0, 0);
	memset(dst, 0, glyph.image.h * glyph.image.pitch);

	switch (bitmap.pixel_mode) {
	case FT_PIXEL_MODE_MONO:
		for (int y = 0; y < bitmap.rows; ++y) {
			const uint8 *curSrc = src;
			uint8 mask = 0;

			for (int x = 0; x < bitmap.width; ++x) {
				if ((x % 8) == 0)
					mask = *curSrc++;

				if (mask & 0x80)
					*dst = 255;

				mask <<= 1;
				++dst;
			}

			src += srcPitch;
		}
		break;

	case FT_PIXEL_MODE_GRAY:
		for (int y = 0; y < bitmap.rows; ++y) {
			memcpy(dst, src, bitmap.width);
			dst += glyph.image.pitch;
			src += srcPitch;
		}
		break;

	default:
		warning("TTFFont::cacheGlyph: Unsupported pixel mode %d", bitmap.pixel_mode);
		return false;
	}

	return true;
}
Example #6
0
bool TTFFont::load(Common::SeekableReadStream &stream, int size, bool monochrome, const uint32 *mapping) {
	if (!g_ttf.isInitialized())
		return false;

	_size = stream.size();
	if (!_size)
		return false;

	_ttfFile = new uint8[_size];
	assert(_ttfFile);

	if (stream.read(_ttfFile, _size) != _size) {
		delete[] _ttfFile;
		_ttfFile = 0;

		return false;
	}

	if (!g_ttf.loadFont(_ttfFile, _size, _face)) {
		delete[] _ttfFile;
		_ttfFile = 0;

		return false;
	}

	// We only support scalable fonts.
	if (!FT_IS_SCALABLE(_face)) {
		delete[] _ttfFile;
		_ttfFile = 0;

		g_ttf.closeFont(_face);

		return false;
	}

	// Check whether we have kerning support
	_hasKerning = (FT_HAS_KERNING(_face) != 0);

	if (FT_Set_Char_Size(_face, 0, size * 64, 0, 0)) {
		delete[] _ttfFile;
		_ttfFile = 0;

		return false;
	}

	_monochrome = monochrome;

	FT_Fixed yScale = _face->size->metrics.y_scale;
	_ascent = ftCeil26_6(FT_MulFix(_face->ascender, yScale));
	_descent = ftCeil26_6(FT_MulFix(_face->descender, yScale));

	_width = ftCeil26_6(FT_MulFix(_face->max_advance_width, _face->size->metrics.x_scale));
	_height = _ascent - _descent + 1;

	if (!mapping) {
		// Load all ISO-8859-1 characters.
		for (uint i = 0; i < 256; ++i) {
			if (!cacheGlyph(_glyphs[i], _glyphSlots[i], i))
				_glyphSlots[i] = 0;
		}
	} else {
		for (uint i = 0; i < 256; ++i) {
			const uint32 unicode = mapping[i] & 0x7FFFFFFF;
			const bool isRequired = (mapping[i] & 0x80000000) != 0;
			// Check whether loading an important glyph fails and error out if
			// that is the case.
			if (!cacheGlyph(_glyphs[i], _glyphSlots[i], unicode)) {
				_glyphSlots[i] = 0;
				if (isRequired)
					return false;
			}
		}
	}

	_initialized = (_glyphs.size() != 0);
	return _initialized;
}
Example #7
0
bool TTFFont::cacheGlyph(Glyph &glyph, uint32 chr) const {
	FT_UInt slot = FT_Get_Char_Index(_face, chr);
	if (!slot)
		return false;

	glyph.slot = slot;

	// We use the light target and render mode to improve the looks of the
	// glyphs. It is most noticable in FreeSansBold.ttf, where otherwise the
	// 't' glyph looks like it is cut off on the right side.
	if (FT_Load_Glyph(_face, slot, _loadFlags))
		return false;

	if (FT_Render_Glyph(_face->glyph, _renderMode))
		return false;

	if (_face->glyph->format != FT_GLYPH_FORMAT_BITMAP)
		return false;

	glyph.xOffset = _face->glyph->bitmap_left;
	glyph.yOffset = _ascent - _face->glyph->bitmap_top;

	glyph.advance = ftCeil26_6(_face->glyph->advance.x);

	const FT_Bitmap &bitmap = _face->glyph->bitmap;
	glyph.image.create(bitmap.width, bitmap.rows, PixelFormat::createFormatCLUT8());

	const uint8 *src = bitmap.buffer;
	int srcPitch = bitmap.pitch;
	if (srcPitch < 0) {
		src += (bitmap.rows - 1) * srcPitch;
		srcPitch = -srcPitch;
	}

	uint8 *dst = (uint8 *)glyph.image.getPixels();
	memset(dst, 0, glyph.image.h * glyph.image.pitch);

	switch (bitmap.pixel_mode) {
	case FT_PIXEL_MODE_MONO:
		for (uint y = 0; y < bitmap.rows; ++y) {
			const uint8 *curSrc = src;
			uint8 mask = 0;

			for (uint x = 0; x < bitmap.width; ++x) {
				if ((x % 8) == 0)
					mask = *curSrc++;

				if (mask & 0x80)
					*dst = 255;

				mask <<= 1;
				++dst;
			}

			src += srcPitch;
		}
		break;

	case FT_PIXEL_MODE_GRAY:
		for (uint y = 0; y < bitmap.rows; ++y) {
			memcpy(dst, src, bitmap.width);
			dst += glyph.image.pitch;
			src += srcPitch;
		}
		break;

	default:
		warning("TTFFont::cacheGlyph: Unsupported pixel mode %d", bitmap.pixel_mode);
		glyph.image.free();
		return false;
	}

	return true;
}
Example #8
0
bool TTFFont::load(Common::SeekableReadStream &stream, int size, uint dpi, TTFRenderMode renderMode, const uint32 *mapping) {
	if (!g_ttf.isInitialized())
		return false;

	_size = stream.size();
	if (!_size)
		return false;

	_ttfFile = new uint8[_size];
	assert(_ttfFile);

	if (stream.read(_ttfFile, _size) != _size) {
		delete[] _ttfFile;
		_ttfFile = 0;

		return false;
	}

	if (!g_ttf.loadFont(_ttfFile, _size, _face)) {
		delete[] _ttfFile;
		_ttfFile = 0;

		return false;
	}

	// We only support scalable fonts.
	if (!FT_IS_SCALABLE(_face)) {
		delete[] _ttfFile;
		_ttfFile = 0;

		g_ttf.closeFont(_face);

		return false;
	}

	// Check whether we have kerning support
	_hasKerning = (FT_HAS_KERNING(_face) != 0);

	if (FT_Set_Char_Size(_face, 0, size * 64, dpi, dpi)) {
		delete[] _ttfFile;
		_ttfFile = 0;

		return false;
	}

	switch (renderMode) {
	case kTTFRenderModeNormal:
		_loadFlags = FT_LOAD_TARGET_NORMAL;
		_renderMode = FT_RENDER_MODE_NORMAL;
		break;

	case kTTFRenderModeLight:
		_loadFlags = FT_LOAD_TARGET_LIGHT;
		_renderMode = FT_RENDER_MODE_LIGHT;
		break;

	case kTTFRenderModeMonochrome:
		_loadFlags = FT_LOAD_TARGET_MONO;
		_renderMode = FT_RENDER_MODE_MONO;
		break;
	}

	FT_Fixed yScale = _face->size->metrics.y_scale;
	_ascent = ftCeil26_6(FT_MulFix(_face->ascender, yScale));
	_descent = ftCeil26_6(FT_MulFix(_face->descender, yScale));

	_width = ftCeil26_6(FT_MulFix(_face->max_advance_width, _face->size->metrics.x_scale));
	_height = _ascent - _descent + 1;

	if (!mapping) {
		// Allow loading of all unicode characters.
		_allowLateCaching = true;

		// Load all ISO-8859-1 characters.
		for (uint i = 0; i < 256; ++i) {
			if (!cacheGlyph(_glyphs[i], i)) {
				_glyphs.erase(i);
			}
		}
	} else {
		// We have a fixed map of characters do not load more later.
		_allowLateCaching = false;

		for (uint i = 0; i < 256; ++i) {
			const uint32 unicode = mapping[i] & 0x7FFFFFFF;
			const bool isRequired = (mapping[i] & 0x80000000) != 0;
			// Check whether loading an important glyph fails and error out if
			// that is the case.
			if (!cacheGlyph(_glyphs[i], unicode)) {
				_glyphs.erase(i);
				if (isRequired)
					return false;
			}
		}
	}

	_initialized = (_glyphs.size() != 0);
	return _initialized;
}