コード例 #1
0
int TTFFont::getCharWidth(byte chr) const {
	GlyphCache::const_iterator glyphEntry = _glyphs.find(chr);
	if (glyphEntry == _glyphs.end())
		return 0;
	else
		return glyphEntry->_value.advance;
}
コード例 #2
0
ファイル: ttf.cpp プロジェクト: alexbevi/scummvm
int TTFFont::getKerningOffset(uint32 left, uint32 right) const {
	if (!_hasKerning)
		return 0;

	assureCached(left);
	assureCached(right);

	FT_UInt leftGlyph, rightGlyph;
	GlyphCache::const_iterator glyphEntry;

	glyphEntry = _glyphs.find(left);
	if (glyphEntry != _glyphs.end()) {
		leftGlyph = glyphEntry->_value.slot;
	} else {
		return 0;
	}

	glyphEntry = _glyphs.find(right);
	if (glyphEntry != _glyphs.end()) {
		rightGlyph = glyphEntry->_value.slot;
	} else {
		return 0;
	}

	if (!leftGlyph || !rightGlyph)
		return 0;

	FT_Vector kerningVector;
	FT_Get_Kerning(_face, leftGlyph, rightGlyph, FT_KERNING_DEFAULT, &kerningVector);
	return (kerningVector.x / 64);
}
コード例 #3
0
ファイル: ttf.cpp プロジェクト: alexbevi/scummvm
Common::Rect TTFFont::getBoundingBox(uint32 chr) const {
	assureCached(chr);
	GlyphCache::const_iterator glyphEntry = _glyphs.find(chr);
	if (glyphEntry == _glyphs.end()) {
		return Common::Rect();
	} else {
		const int xOffset = glyphEntry->_value.xOffset;
		const int yOffset = glyphEntry->_value.yOffset;
		const Graphics::Surface &image = glyphEntry->_value.image;
		return Common::Rect(xOffset, yOffset, xOffset + image.w, yOffset + image.h);
	}
}
コード例 #4
0
void FreeTypeFont::doFillGlyphCache(GlyphCache& cache, const std::vector<char32_t>& characters)
#endif
{
    /** @bug Crash when atlas is too small */

    /* Get glyph codes from characters */
    std::vector<FT_UInt> charIndices;
    charIndices.resize(characters.size()+1);
    charIndices[0] = 0;
    std::transform(characters.begin(), characters.end(), charIndices.begin()+1,
        [this](const char32_t c) { return FT_Get_Char_Index(ftFont, c); });

    /* Remove duplicates (e.g. uppercase and lowercase mapped to same glyph) */
    std::sort(charIndices.begin(), charIndices.end());
    charIndices.erase(std::unique(charIndices.begin(), charIndices.end()), charIndices.end());

    /* Sizes of all characters */
    std::vector<Vector2i> charSizes;
    charSizes.reserve(charIndices.size());
    for(FT_UInt c: charIndices) {
        CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Load_Glyph(ftFont, c, FT_LOAD_DEFAULT) == 0);
        charSizes.push_back(Vector2i(ftFont->glyph->metrics.width, ftFont->glyph->metrics.height)/64);
    }

    /* Create texture atlas */
    const std::vector<Rectanglei> charPositions = cache.reserve(charSizes);

    /* Render all characters to the atlas and create character map */
    unsigned char* pixmap = new unsigned char[cache.textureSize().product()]();
    /** @todo Some better way for this */
    #ifndef MAGNUM_TARGET_GLES2
    Image2D image(ImageFormat::Red, ImageType::UnsignedByte, cache.textureSize(), pixmap);
    #else
    Image2D image(Context::current() && Context::current()->isExtensionSupported<Extensions::GL::EXT::texture_rg>() ?
        ImageFormat::Red : ImageFormat::Luminance, ImageType::UnsignedByte, cache.textureSize(), pixmap);
    #endif
    for(std::size_t i = 0; i != charPositions.size(); ++i) {
        /* Load and render glyph */
        /** @todo B&W only if radius != 0 */
        FT_GlyphSlot glyph = ftFont->glyph;
        CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Load_Glyph(ftFont, charIndices[i], FT_LOAD_DEFAULT) == 0);
        CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL) == 0);

        /* Copy rendered bitmap to texture image */
        const FT_Bitmap& bitmap = glyph->bitmap;
        CORRADE_INTERNAL_ASSERT(std::abs(bitmap.width-charPositions[i].width()) <= 2);
        CORRADE_INTERNAL_ASSERT(std::abs(bitmap.rows-charPositions[i].height()) <= 2);
        for(Int yin = 0, yout = charPositions[i].bottom(), ymax = bitmap.rows; yin != ymax; ++yin, ++yout)
            for(Int xin = 0, xout = charPositions[i].left(), xmax = bitmap.width; xin != xmax; ++xin, ++xout)
                pixmap[yout*cache.textureSize().x() + xout] = bitmap.buffer[(bitmap.rows-yin-1)*bitmap.width + xin];

        /* Insert glyph parameters into cache */
        cache.insert(charIndices[i],
            Vector2i(glyph->bitmap_left, glyph->bitmap_top-charPositions[i].height()),
            charPositions[i]);
    }

    /* Set cache image */
    cache.setImage({}, image);
}
コード例 #5
0
ファイル: ttf.cpp プロジェクト: alexbevi/scummvm
void TTFFont::assureCached(uint32 chr) const {
	if (!chr || !_allowLateCaching || _glyphs.contains(chr)) {
		return;
	}

	Glyph newGlyph;
	if (cacheGlyph(newGlyph, chr)) {
		_glyphs[chr] = newGlyph;
	}
}
コード例 #6
0
inline void server_add_char( GlyphCache & gly_cache, uint8_t cacheId, uint16_t cacheIndex
                    , int16_t offset, int16_t baseline
                    , uint16_t width, uint16_t height, const uint8_t * data)
{
    FontChar fi(offset, baseline, width, height, 0);
    memcpy(fi.data.get(), data, fi.datasize());


LOG(LOG_INFO, "cacheId=%u cacheIndex=%u", cacheId, cacheIndex);
    gly_cache.set_glyph(std::move(fi), cacheId, cacheIndex);
}
コード例 #7
0
void TTFFont::drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const {
	GlyphCache::const_iterator glyphEntry = _glyphs.find(chr);
	if (glyphEntry == _glyphs.end())
		return;

	const Glyph &glyph = glyphEntry->_value;

	x += glyph.xOffset;
	y += glyph.yOffset;

	if (x > dst->w)
		return;
	if (y > dst->h)
		return;

	int w = glyph.image.w;
	int h = glyph.image.h;

	const uint8 *srcPos = (const uint8 *)glyph.image.getBasePtr(0, 0);

	// Make sure we are not drawing outside the screen bounds
	if (x < 0) {
		srcPos -= x;
		w += x;
		x = 0;
	}

	if (x + w > dst->w)
		w = dst->w - x;

	if (w <= 0)
		return;

	if (y < 0) {
		srcPos -= y * glyph.image.pitch;
		h += y;
		y = 0;
	}

	if (y + h > dst->h)
		h = dst->h - y;

	if (h <= 0)
		return;

	uint8 *dstPos = (uint8 *)dst->getBasePtr(x, y);

	if (dst->format.bytesPerPixel == 1) {
		for (int cy = 0; cy < h; ++cy) {
			uint8 *rDst = dstPos;
			const uint8 *src = srcPos;

			for (int cx = 0; cx < w; ++cx) {
				// We assume a 1Bpp mode is a color indexed mode, thus we can
				// not take advantage of anti-aliasing here.
				if (*src >= 0x80)
					*rDst = color;

				++rDst;
				++src;
			}

			dstPos += dst->pitch;
			srcPos += glyph.image.pitch;
		}
	} else if (dst->format.bytesPerPixel == 2) {
		renderGlyph<uint16>(dstPos, dst->pitch, srcPos, glyph.image.pitch, w, h, color, dst->format);
	} else if (dst->format.bytesPerPixel == 4) {
		renderGlyph<uint32>(dstPos, dst->pitch, srcPos, glyph.image.pitch, w, h, color, dst->format);
	}
}
コード例 #8
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;
}
コード例 #9
0
ファイル: ttf.cpp プロジェクト: alexbevi/scummvm
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;
}
コード例 #10
0
std::vector<std::pair<std::string, Containers::Array<char>>> MagnumFontConverter::doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const {
    Utility::Configuration configuration;

    configuration.setValue("version", 1);
    configuration.setValue("image", Utility::Directory::filename(filename) + ".tga");
    configuration.setValue("originalImageSize", cache.textureSize());
    configuration.setValue("padding", cache.padding());
    configuration.setValue("fontSize", font.size());
    configuration.setValue("ascent", font.ascent());
    configuration.setValue("descent", font.descent());
    configuration.setValue("lineHeight", font.lineHeight());

    /* Compress glyph IDs so the glyphs are in consecutive array, glyph 0
       should stay at position 0 */
    std::unordered_map<UnsignedInt, UnsignedInt> glyphIdMap;
    glyphIdMap.reserve(cache.glyphCount());
    glyphIdMap.emplace(0, 0);
    for(const std::pair<UnsignedInt, std::pair<Vector2i, Range2Di>>& glyph: cache)
        glyphIdMap.emplace(glyph.first, glyphIdMap.size());

    /** @todo Save only glyphs contained in @p characters */

    /* Inverse map from new glyph IDs to old ones */
    std::vector<UnsignedInt> inverseGlyphIdMap(glyphIdMap.size());
    for(const std::pair<UnsignedInt, UnsignedInt>& map: glyphIdMap)
        inverseGlyphIdMap[map.second] = map.first;

    /* Character->glyph map, map glyph IDs to new ones */
    for(const char32_t c: characters) {
        Utility::ConfigurationGroup* group = configuration.addGroup("char");
        const UnsignedInt glyphId = font.glyphId(c);
        group->setValue("unicode", c);

        /* Map old glyph ID to new, if not found, map to glyph 0 */
        auto found = glyphIdMap.find(glyphId);
        group->setValue("glyph", found == glyphIdMap.end() ? 0 : glyphIdMap.at(glyphId));
    }

    /* Save glyph properties in order which preserves their IDs, remove padding
       from the values so they aren't added twice when using the font later */
    /** @todo Some better way to handle this padding stuff */
    for(UnsignedInt oldGlyphId: inverseGlyphIdMap) {
        std::pair<Vector2i, Range2Di> glyph = cache[oldGlyphId];
        Utility::ConfigurationGroup* group = configuration.addGroup("glyph");
        group->setValue("advance", font.glyphAdvance(oldGlyphId));
        group->setValue("position", glyph.first+cache.padding());
        group->setValue("rectangle", glyph.second.padded(-cache.padding()));
    }

    std::ostringstream confOut;
    configuration.save(confOut);
    std::string confStr = confOut.str();
    Containers::Array<char> confData{confStr.size()};
    std::copy(confStr.begin(), confStr.end(), confData.begin());

    /* Save cache image */
    Image2D image(PixelFormat::Red, PixelType::UnsignedByte);
    cache.texture().image(0, image);
    auto tgaData = Trade::TgaImageConverter().exportToData(image);

    std::vector<std::pair<std::string, Containers::Array<char>>> out;
    out.emplace_back(filename + ".conf", std::move(confData));
    out.emplace_back(filename + ".tga", std::move(tgaData));
    return out;
}
コード例 #11
0
// TODO implementation of the server_draw_text function below is a small subset of possibilities text can be packed (detecting duplicated strings). See MS-RDPEGDI 2.2.2.2.1.1.2.13 GlyphIndex (GLYPHINDEX_ORDER)
static inline void server_draw_text(
                GraphicApi & drawable,
                Font const & font, int16_t x, int16_t y, const char * text,
                uint32_t fgcolor, uint32_t bgcolor, const Rect & clip)
{
    // TODO static not const is a bad idea
    static GlyphCache mod_glyph_cache;

    UTF8toUnicodeIterator unicode_iter(text);

    while (*unicode_iter) {
        int total_width = 0;
        int total_height = 0;
        uint8_t data[256];
        auto data_begin = std::begin(data);
        const auto data_end = std::end(data)-2;

        const int cacheId = 7;
        int distance_from_previous_fragment = 0;
        while (data_begin != data_end) {
            const uint32_t charnum = *unicode_iter;
            if (!charnum) {
                break ;
            }
            ++unicode_iter;

            int cacheIndex = 0;
            FontChar const * font_item = font.glyph_at(charnum);
            if (!font_item) {
                LOG(LOG_WARNING, "server_draw_text() - character not defined >0x%02x<", charnum);
                font_item = &font.unknown_glyph();
            }

            // TODO avoid passing parameters by reference to get results
            const GlyphCache::t_glyph_cache_result cache_result =
                mod_glyph_cache.add_glyph(*font_item, cacheId, cacheIndex);
            (void)cache_result; // supress warning

            *data_begin = cacheIndex;
            ++data_begin;
            *data_begin = distance_from_previous_fragment;
            ++data_begin;
            distance_from_previous_fragment = font_item->incby;
            total_width += font_item->incby;
            total_height = std::max(uint16_t(total_height), font_item->height);
        }

        const Rect bk(x, y, total_width + 1, total_height + 1);

        RDPGlyphIndex glyphindex(
            cacheId,            // cache_id
            0x03,               // fl_accel
            0x0,                // ui_charinc
            1,                  // f_op_redundant,
            fgcolor,            // BackColor (text color)
            bgcolor,            // ForeColor (color of the opaque rectangle)
            bk,                 // bk
            bk,                 // op
            // brush
            RDPBrush(0, 0, 3, 0xaa,
                reinterpret_cast<const uint8_t *>("\xaa\x55\xaa\x55\xaa\x55\xaa\x55")),
            x,                  // glyph_x
            y + total_height,   // glyph_y
            data_begin - data,  // data_len in bytes
            data                // data
        );

        x += total_width;

        drawable.draw(glyphindex, clip, mod_glyph_cache);
    }
}