Example #1
0
void Font::drawText(Bitmap *dest, Point2i pos, const std::string &text) const {
	int initial = pos.x;

	for (size_t i=0; i<text.length(); i++) {
		char character = text[i];
		if (character == '\r')
			continue;
		if (character == '\n') {
			pos.x = initial;
			pos.y += (int) (getMaxVerticalBearing()*4.0/3.0);
			continue;
		}

		const Font::Glyph &glyph = getGlyph(character);

		Point2i targetOffset = pos + Vector2i(
			glyph.horizontalBearing,
			getMaxVerticalBearing() - glyph.verticalBearing - 1
		);

		Point2i sourceOffset(
			(int) (glyph.tx.x * m_bitmap->getWidth()),
			(int) (glyph.tx.y * m_bitmap->getHeight()));

		dest->accumulate(m_bitmap.get(), sourceOffset, targetOffset, glyph.size);

		pos.x += glyph.horizontalAdvance;

		if (i+1 < text.length())
			pos.x += getKerning(character, text[i+1]);
	}
}
float ofxTextAlign::getWidth(const char *str, bool single_line)
{
	float ret = 0;
	float tmp = 0;
	const char *ptr = str;
	char prev = -1;
	while(*ptr != '\0' && !(single_line && *ptr == '\n')) {
		switch(*ptr) {
		case '\n':
			ret = max(ret, tmp);
			tmp = 0;
			prev = -1;
			break;
		default:
			if(prev != -1) {
				tmp += getKerning(*ptr, prev);
			}
			prev = *ptr;
			tmp += getAdvance(*ptr);
			break;
		}
		++ptr;
	}
	return max(ret, tmp);
}
Example #3
0
Vector2i Font::getSize(const std::string &text) const {
	Vector2i size(0, getMaxVerticalBearing());
	int pos = 0;

	for (size_t i=0; i<text.length(); i++) {
		char character = text[i];
		if (character == '\r')
			continue;
		if (character == '\n') {
			size.y += (int) (getMaxVerticalBearing()*(4.0 / 3.0));
			size.x = std::max(size.x, pos);
			pos = 0;
			continue;
		}

		const Font::Glyph &glyph = getGlyph(character);

		pos += glyph.horizontalAdvance;

		if (i+1 < text.length())
			pos += getKerning(character, text[i+1]);
	}
	size.x = std::max(size.x, pos);

	return size;
}
//-----------------------------------------------------------
ofTexture ofTrueTypeFont::getStringTexture(const std::string& str, bool vflip) const{
    string str_valid;
	utf8::replace_invalid(str.begin(),str.end(),back_inserter(str_valid));
	vector<glyph> glyphs;
	vector<ofVec2f> glyphPositions;
	utf8::iterator<const char*> it(&str_valid.front(), &str_valid.front(), (&str_valid.back())+1);
	utf8::iterator<const char*> end((&str_valid.back())+1, &str_valid.front(), (&str_valid.back())+1);
	int	x = 0;
	int	y = 0;
	long height = 0;
	uint32_t prevC = 0;
	while(it != end){
		try{
			auto c = *it;
			if (c == '\n') {
				y += lineHeight;
				x = 0 ; //reset X Pos back to zero
				prevC = 0;
			} else {
				glyphs.push_back(loadGlyph(c));
				if(prevC>0){
					x += getKerning(c,prevC);
				}else if(settings.direction == ofTtfSettings::RightToLeft){
					x += glyphs.back().props.width;
				}
				glyphPositions.emplace_back(static_cast<float>(x), static_cast<float>(y));
				x += glyphs.back().props.advance * letterSpacing;
				height = max(height, glyphs.back().props.ymax + y + long(getLineHeight()));
			}
			++it;
			prevC = c;
		}catch(...){
			break;
		}
	}
	ofTexture tex;
	ofPixels totalPixels;
	totalPixels.allocate(x, height, OF_PIXELS_GRAY_ALPHA);
	//-------------------------------- clear data:
	totalPixels.set(0,255); // every luminance pixel = 255
	totalPixels.set(1,0);
	size_t i = 0;
	for(auto & g: glyphs){
		if(settings.direction == ofTtfSettings::LeftToRight){
			g.pixels.blendInto(totalPixels, glyphPositions[i].x, glyphPositions[i].y + getLineHeight() + g.props.ymin + getDescenderHeight() );
		}else{
			g.pixels.blendInto(totalPixels, x-glyphPositions[i].x, glyphPositions[i].y + getLineHeight() + g.props.ymin + getDescenderHeight() );
		}
		i++;
		if(i==glyphPositions.size()){
			break;
		}
	}
	tex.allocate(totalPixels);
	return tex;
}
Example #5
0
void Font::writeInternal(float x, float y, float z, const char *text, int count, float spacing) {
	for (int n = 0; n < count;) {
		int glyph = getTextChar(text, n, &n);
		x += renderGlyph(x, y, z, glyph);
		if (glyph == ' ')
			x += spacing;
		if (n < count)
			x += getKerning(glyph, getTextChar(text, n));
	}
}
Example #6
0
void FontDescription::updateTypesettingFeatures() {
    m_fields.m_typesettingFeatures = s_defaultTypesettingFeatures;

    switch (textRendering()) {
    case AutoTextRendering:
        break;
    case OptimizeSpeed:
        m_fields.m_typesettingFeatures &= ~(blink::Kerning | Ligatures);
        break;
    case GeometricPrecision:
    case OptimizeLegibility:
        m_fields.m_typesettingFeatures |= blink::Kerning | Ligatures;
        break;
    }

    switch (getKerning()) {
    case FontDescription::NoneKerning:
        m_fields.m_typesettingFeatures &= ~blink::Kerning;
        break;
    case FontDescription::NormalKerning:
        m_fields.m_typesettingFeatures |= blink::Kerning;
        break;
    case FontDescription::AutoKerning:
        break;
    }

    // As per CSS (http://dev.w3.org/csswg/css-text-3/#letter-spacing-property),
    // When the effective letter-spacing between two characters is not zero (due
    // to either justification or non-zero computed letter-spacing), user agents
    // should not apply optional ligatures.
    if (m_letterSpacing == 0) {
        switch (commonLigaturesState()) {
        case FontDescription::DisabledLigaturesState:
            m_fields.m_typesettingFeatures &= ~blink::Ligatures;
            break;
        case FontDescription::EnabledLigaturesState:
            m_fields.m_typesettingFeatures |= blink::Ligatures;
            break;
        case FontDescription::NormalLigaturesState:
            break;
        }

        if (discretionaryLigaturesState() ==
                FontDescription::EnabledLigaturesState ||
                historicalLigaturesState() == FontDescription::EnabledLigaturesState ||
                contextualLigaturesState() == FontDescription::EnabledLigaturesState) {
            m_fields.m_typesettingFeatures |= blink::Ligatures;
        }
    }

    if (variantCaps() != CapsNormal)
        m_fields.m_typesettingFeatures |= blink::Caps;
}
float	StringFontWidth( const char *str ) {
	float	len = 0;
	float	kerning = 0;
	while ( *str ) {
		int i = *str;
		if ( i >= ' ' && i < 128 ) {
			len += glyphRects[i-32].xadvance + kerning;
			kerning = getKerning( str );
		}
		str++;
	}
	return len;
}
/*
 ==================
 iphoneDrawText
 
 Returns the width in pixels
 ==================
 */
float iphoneDrawText( float x, float y, float scale, const char *str ) {
	float	fx = x;
	float	fy = y;
	float	kerning = 0;
	
	PK_BindTexture( arialFontTexture );
	glBegin( GL_QUADS );
	
	while ( *str ) {
		int i = *str;
		if ( i >= ' ' && i < 128 ) {
			GlyphRect *glyph = &glyphRects[i-32];
			
			// the glyphRects don't include the shadow outline
			float	x0 = ( glyph->x0 - 1 ) / 256.0;
			float	y0 = ( glyph->y0 - 1 ) / 256.0;
			float	x1 = ( glyph->x1 + 2 ) / 256.0;
			float	y1 = ( glyph->y1 + 2 ) / 256.0;
			
			float	width = ( x1 - x0 ) * 256 * scale;
			float	height = ( y1 - y0 ) * 256 * scale;
			
			float	xoff = ( glyph->xoff - 1 ) * scale + kerning;
			float	yoff = ( glyph->yoff - 1 ) * scale;
			
			glTexCoord2f( x0, y0 );
			glVertex2f( fx + xoff, fy + yoff );
			
			glTexCoord2f( x1, y0 );
			glVertex2f( fx + xoff + width, fy + yoff );
			
			glTexCoord2f( x1, y1 );
			glVertex2f( fx + xoff + width, fy + yoff + height );
			
			glTexCoord2f( x0, y1 );
			glVertex2f( fx + xoff, fy + yoff + height );
      
			fx += glyph->xadvance * scale + kerning;
      //			fx += ceil(glyph->xadvance);	// with the outline, ceil is probably the right thing
			kerning = getKerning( str );
		}
		str++;
	}
	
	glEnd();
	
	return fx - x;
}
const char* ofxTextAlign::drawLine(const char *str, float x, float y)
{
	const char *ptr = str;
	int letter_count = getLetterCount(str, true);
	float extra_spacing = letter_count>1?(getDrawWidth(str, true)-getWidth(str, true))/(float)(letter_count-1):0;
	while(*ptr != '\0') {
		if(*ptr=='\n') {
			++ptr;
			break;
		}
		float interval = getAdvance(*ptr) + getKerning(*(ptr+1), *ptr) + extra_spacing;
		ptr = drawChar(ptr, x, y);
		x += interval;
	}
	return ptr;
}
    float getStringWidth (const String& text)
    {
        const CharPointer_UTF16 utf16 (text.toUTF16());
        const size_t numChars = utf16.length();
        HeapBlock<int16> results (numChars + 1);
        results[numChars] = -1;
        float x = 0;

        if (GetGlyphIndices (dc, utf16, (int) numChars, reinterpret_cast <WORD*> (results.getData()),
                             GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
        {
            for (size_t i = 0; i < numChars; ++i)
                x += getKerning (dc, results[i], results[i + 1]);
        }

        return x;
    }
void ofTrueTypeFont::iterateString(const string & str, float x, float y, bool vFlipped, std::function<void(uint32_t, ofVec2f)> f) const{
	ofVec2f pos(x,y);

	int newLineDirection		= 1;
	if(!vFlipped){
		// this would align multiline texts to the last line when vflip is disabled
		//int lines = ofStringTimesInString(c,"\n");
		//Y = lines*lineHeight;
		newLineDirection = -1;
	}

	int directionX = settings.direction == ofTtfSettings::LeftToRight?1:-1;

	string str_valid;
	utf8::replace_invalid(str.begin(),str.end(),back_inserter(str_valid));
	utf8::iterator<const char*> it(&str_valid.front(), &str_valid.front(), (&str_valid.back())+1);
	utf8::iterator<const char*> end((&str_valid.back())+1, &str_valid.front(), (&str_valid.back())+1);
    uint32_t prevC = 0;
	while(it != end){
		try{
			auto c = *it;
			if (c == '\n') {
				pos.y += lineHeight*newLineDirection;
				pos.x = x ; //reset X Pos back to zero
				prevC = 0;
			}if (c == '\t') {
				pos.x += getGlyphProperties(' ').advance * letterSpacing * 4 * directionX;
				prevC = c;
			} else if(isValidGlyph(c)) {
				const auto & props = getGlyphProperties(c);
				if(prevC>0){
					pos.x += getKerning(c,prevC);// * directionX;
				}
				f(c,pos);
				pos.x += props.advance * letterSpacing * directionX;
				prevC = c;
			}
			++it;
		}catch(...){
			break;
		}
	}
}
Example #12
0
void ofTrueTypeFont::iterateString(const string & str, float x, float y, bool vFlipped, std::function<void(uint32_t, ofVec2f)> f) const {
    ofVec2f pos(x,y);

    int newLineDirection		= 1;
    if(!vFlipped) {
        // this would align multiline texts to the last line when vflip is disabled
        //int lines = ofStringTimesInString(c,"\n");
        //Y = lines*lineHeight;
        newLineDirection = -1;
    }

    int directionX = settings.direction == ofTtfSettings::LeftToRight?1:-1;

    uint32_t prevC = 0;
    for(auto c: ofUTF8Iterator(str)) {
        try {
            if (c == '\n') {
                pos.y += lineHeight*newLineDirection;
                pos.x = x ; //reset X Pos back to zero
                prevC = 0;
            }
            if (c == '\t') {
                pos.x += getGlyphProperties(' ').advance * letterSpacing * 4 * directionX;
                prevC = c;
            } else if(isValidGlyph(c)) {
                const auto & props = getGlyphProperties(c);
                if(prevC>0) {
                    pos.x += getKerning(c,prevC);// * directionX;
                }
                f(c,pos);
                pos.x += props.advance * letterSpacing * directionX;
                prevC = c;
            }
        } catch(...) {
            break;
        }
    }
}
    void getGlyphPositions (const String& text, Array <int>& resultGlyphs, Array <float>& xOffsets)
    {
        const CharPointer_UTF16 utf16 (text.toUTF16());
        const size_t numChars = utf16.length();
        HeapBlock<int16> results (numChars + 1);
        results[numChars] = -1;
        float x = 0;

        if (GetGlyphIndices (dc, utf16, (int) numChars, reinterpret_cast <WORD*> (results.getData()),
                             GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
        {
            resultGlyphs.ensureStorageAllocated ((int) numChars);
            xOffsets.ensureStorageAllocated ((int) numChars + 1);

            for (size_t i = 0; i < numChars; ++i)
            {
                resultGlyphs.add (results[i]);
                xOffsets.add (x);
                x += getKerning (dc, results[i], results[i + 1]);
            }
        }

        xOffsets.add (x);
    }
Example #14
0
/*
* FTLIB_StrlenForWidth
* returns the len allowed for the string to fit inside a given width when using a given font.
*/
size_t FTLIB_StrlenForWidth( const char *str, qfontface_t *font, size_t maxwidth, int flags )
{
	const char *s, *olds;
	size_t width = 0;
	int gc;
	int advance = 0;
	wchar_t num, prev_num = 0;
	qglyph_t *glyph, *prev_glyph = NULL;
	renderString_f renderString;
	getKerning_f getKerning;
	bool hasKerning;

	if( !str || !font )
		return 0;

	renderString = font->f->renderString;
	getKerning = font->f->getKerning;
	hasKerning = ( flags & TEXTDRAWFLAG_KERNING ) && font->hasKerning;

	for( s = str; s; )
	{
		olds = s;
		gc = FTLIB_GrabChar( &s, &num, NULL, flags );
		if( gc == GRABCHAR_CHAR )
		{
			if( num == '\n' )
				break;

			if( num < ' ' )
				continue;

			glyph = FTLIB_GetGlyph( font, num );
			if( !glyph )
			{
				num = FTLIB_REPLACEMENT_GLYPH;
				glyph = FTLIB_GetGlyph( font, num );
			}

			if( !glyph->shader )
				renderString( font, olds );

			advance = glyph->x_advance;
			if( hasKerning && prev_num ) {
				advance += getKerning( font, prev_glyph, glyph );
			}

			if( maxwidth && ( ( width + advance ) > maxwidth ) )
			{
				s = olds;
				break;
			}

			width += advance;

			prev_num = num;
			prev_glyph = glyph;
		}
		else if( gc == GRABCHAR_COLOR )
			continue;
		else if( gc == GRABCHAR_END )
			break;
		else
			assert( 0 );
	}

	return (unsigned int)( s - str );
}
Example #15
0
/*
* FTLIB_DrawClampString
*/
void FTLIB_DrawClampString( int x, int y, const char *str, int xmin, int ymin, int xmax, int ymax, qfontface_t *font, vec4_t color, int flags )
{
	int xoffset = 0;
	vec4_t scolor;
	int colorindex;
	wchar_t num, prev_num = 0;
	const char *s = str, *olds;
	int gc;
	qglyph_t *glyph, *prev_glyph = NULL;
	renderString_f renderString;
	getKerning_f getKerning;
	bool hasKerning;

	if( !str || !font )
		return;
	if( ( xmax <= xmin ) || ( ymax <= ymin ) || ( x > xmax ) || ( y > ymax ) )
		return;

	Vector4Copy( color, scolor );

	renderString = font->f->renderString;
	getKerning = font->f->getKerning;
	hasKerning = ( flags & TEXTDRAWFLAG_KERNING ) && font->hasKerning;

	while( 1 )
	{
		olds = s;
		gc = FTLIB_GrabChar( &s, &num, &colorindex, flags );
		if( gc == GRABCHAR_CHAR )
		{
			if( num == '\n' )
				break;

			if( num < ' ' )
				continue;

			glyph = FTLIB_GetGlyph( font, num );
			if( !glyph )
			{
				num = FTLIB_REPLACEMENT_GLYPH;
				glyph = FTLIB_GetGlyph( font, num );
			}

			if( !glyph->shader )
				renderString( font, olds );

			if( prev_num )
			{
				xoffset += prev_glyph->x_advance;
				if( hasKerning )
					xoffset += getKerning( font, prev_glyph, glyph );
			}

			if( x + xoffset > xmax )
				break;

			FTLIB_DrawClampChar( x + xoffset, y, num, xmin, ymin, xmax, ymax, font, scolor );

			prev_num = num;
			prev_glyph = glyph;
		}
		else if( gc == GRABCHAR_COLOR )
		{
			assert( ( unsigned )colorindex < MAX_S_COLORS );
			VectorCopy( color_table[colorindex], scolor );
		}
		else if( gc == GRABCHAR_END )
			break;
		else
			assert( 0 );
	}
}
Example #16
0
/* FTLIB_DrawMultilineString
 *
 * Draws a string with word wrap.
 */
int FTLIB_DrawMultilineString( int x, int y, const char *str, int halign, int maxwidth, int maxlines, qfontface_t *font, vec4_t color, int flags )
{
	bool ended = false; // whether to stop drawing lines

	// characters and glyphs
	const char *oldstr;
	int gc, colorindex;
	wchar_t num, prev_num;
	qglyph_t *glyph, *prev_glyph;
	int glyph_width;
	renderString_f renderString;
	getKerning_f getKerning;
	bool hasKerning;

	// words
	const char *word; // beginning of the current word
	int word_chars, space_chars; // length of the current word and number of spaces before it
	int word_width, space_width; // width of the current word and the spaces before it
	vec4_t word_color; // starting color of the current word
	bool in_space; // whether currently in a sequence of spaces

	// line drawing
	const char *line; // beginning of the line
	int line_chars; // number of characters to draw in this line
	int line_width; // width of the current line
	int line_x; // x position of the current character in line
	vec4_t line_color, line_next_color; // first color in the line
	int line_height; // height of a single line
	int lines = 0; // number of lines drawn - the return value

	if( !str || !font || ( maxwidth <= 0 ) )
		return 0;

	halign = halign % 3; // ignore vertical alignment

	renderString = font->f->renderString;
	getKerning = font->f->getKerning;
	hasKerning = ( flags & TEXTDRAWFLAG_KERNING ) && font->hasKerning;

	VectorCopy( color, line_next_color );
	line_color[3] = color[3];
	line_height = FTLIB_FontHeight( font );

	do
	{
		// reset
		word_chars = space_chars = 0;
		word_width = space_width = 0;
		in_space = true; // assume starting from a whitespace so preceding whitespaces can be skipped
		line_chars = 0;
		line_width = 0;
		VectorCopy( line_next_color, line_color );

		// find where to wrap
		prev_num = 0;
		prev_glyph = NULL;
		while( str )
		{
			oldstr = str;
			gc = FTLIB_GrabChar( &str, &num, &colorindex, flags );
			if( gc == GRABCHAR_CHAR )
			{
				if( num == '\n' )
				{
					if( !word_chars )
						space_chars = space_width = 0;
					VectorCopy( color, line_next_color );
					break;
				}

				if( num < ' ' )
					continue;

				glyph = FTLIB_GetGlyph( font, num );
				if( !glyph )
				{
					num = FTLIB_REPLACEMENT_GLYPH;
					glyph = FTLIB_GetGlyph( font, num );
				}

				if( !glyph->shader )
					renderString( font, oldstr );

				if( Q_IsBreakingSpaceChar( num ) )
				{
					if( in_space )
					{
						if( !line_chars )
							continue; // skip preceding whitespaces in a line
					}
					else
					{
						in_space = true;

						// reached the space without wrapping - send the current word to the line
						line_chars += space_chars + word_chars;
						word_chars = space_chars = 0;
						line_width += space_width + word_width;
						word_width = space_width = 0;
					}
					space_chars++;
					if( hasKerning && prev_num )
						space_width += getKerning( font, prev_glyph, glyph );
					space_width += glyph->x_advance;
				}
				else
				{
					in_space = false;

					glyph_width = glyph->x_advance;
					if( hasKerning && prev_num )
						glyph_width += getKerning( font, prev_glyph, glyph );

					if( !word_chars )
					{
						word = oldstr;
						VectorCopy( line_next_color, word_color );
					}

					if( line_chars )
					{
						// wrap after the previous word, ignoring spaces between the words
						if( ( line_width + space_width + word_width + glyph_width ) > maxwidth )
						{
							str = word;
							VectorCopy( word_color, line_next_color );
							word_chars = space_chars = 0;
							word_width = space_width = 0;
							break;
						}
					}
					else
					{
						line = word;
						if( word_chars ) // always draw at least 1 character in a line
						{
							if( ( word_width + glyph_width ) > maxwidth )
							{
								str = oldstr;
								break;
							}
						}
					}

					word_chars++;
					word_width += glyph_width;
				}

				prev_num = num;
				prev_glyph = glyph;
			}
			else if( gc == GRABCHAR_COLOR )
			{
				assert( ( unsigned )colorindex < MAX_S_COLORS );
				VectorCopy( color_table[colorindex], line_next_color );
				if( !line_chars && !word_chars )
					VectorCopy( line_next_color, line_color );
			}
			else if( gc == GRABCHAR_END )
			{
				ended = true;
				break;
			}
			else
				assert( 0 );
		}
		// add the remaining part of the word
		line_chars += space_chars + word_chars;
		line_width += space_width + word_width;

		// draw the line
		if( line_chars > 0 )
		{
			line_x = x;
			if( halign == ALIGN_CENTER_TOP )
				line_x -= line_width >> 1;
			else if( halign == ALIGN_RIGHT_TOP )
				line_x -= line_width;

			prev_num = 0;
			prev_glyph = NULL;
			while( ( line_chars > 0 ) && line )
			{
				gc = FTLIB_GrabChar( &line, &num, &colorindex, flags );
				if( gc == GRABCHAR_CHAR )
				{
					if( num < ' ' )
						continue;

					line_chars--;

					glyph = FTLIB_GetGlyph( font, num );
					if( !glyph )
					{
						num = FTLIB_REPLACEMENT_GLYPH;
						glyph = FTLIB_GetGlyph( font, num );
					}

					if( hasKerning && prev_num )
						line_x += getKerning( font, prev_glyph, glyph );

					FTLIB_DrawRawChar( line_x, y, num, font, line_color );

					line_x += glyph->x_advance;

					prev_num = num;
					prev_glyph = glyph;
				}
				else if( gc == GRABCHAR_COLOR )
				{
					assert( ( unsigned )colorindex < MAX_S_COLORS );
					VectorCopy( color_table[colorindex], line_color );
				}
				else if( gc == GRABCHAR_END )
					break;
				else
					assert( 0 );
			}
		}
Example #17
0
/*
* FTLIB_DrawRawString - Doesn't care about aligning. Returns drawn len.
* It can stop when reaching maximum width when a value has been parsed.
*/
size_t FTLIB_DrawRawString( int x, int y, const char *str, size_t maxwidth, int *width, qfontface_t *font, vec4_t color, int flags )
{
	unsigned int xoffset = 0;
	vec4_t scolor;
	const char *s, *olds;
	int gc, colorindex;
	wchar_t num, prev_num = 0;
	qglyph_t *glyph, *prev_glyph = NULL;
	renderString_f renderString;
	getKerning_f getKerning;
	bool hasKerning;

	if( !str || !font )
		return 0;

	Vector4Copy( color, scolor );

	renderString = font->f->renderString;
	getKerning = font->f->getKerning;
	hasKerning = ( flags & TEXTDRAWFLAG_KERNING ) && font->hasKerning;

	for( s = str; s; )
	{
		olds = s;
		gc = FTLIB_GrabChar( &s, &num, &colorindex, flags );
		if( gc == GRABCHAR_CHAR )
		{
			if( num == '\n' )
				break;

			if( num < ' ' )
				continue;

			glyph = FTLIB_GetGlyph( font, num );
			if( !glyph )
			{
				num = FTLIB_REPLACEMENT_GLYPH;
				glyph = FTLIB_GetGlyph( font, num );
			}

			if( !glyph->shader )
				renderString( font, olds );

			// ignore kerning at this point so the full width of the previous character will always be returned
			if( maxwidth && ( ( xoffset + glyph->x_advance ) > maxwidth ) )
			{
				s = olds;
				break;
			}

			if( hasKerning && prev_num )
				xoffset += getKerning( font, prev_glyph, glyph );

			FTLIB_DrawRawChar( x + xoffset, y, num, font, scolor );

			xoffset += glyph->x_advance;

			prev_num = num;
			prev_glyph = glyph;
		}
		else if( gc == GRABCHAR_COLOR )
		{
			assert( ( unsigned )colorindex < MAX_S_COLORS );
			VectorCopy( color_table[colorindex], scolor );
		}
		else if( gc == GRABCHAR_END )
			break;
		else
			assert( 0 );
	}

	if( width )
		*width = xoffset;

	return ( s - str );
}
Example #18
0
/*
* FTLIB_strWidth
* doesn't count invisible characters. Counts up to given length, if any.
*/
size_t FTLIB_strWidth( const char *str, qfontface_t *font, size_t maxlen, int flags )
{
	const char *s = str, *olds;
	size_t width = 0;
	wchar_t num, prev_num = 0;
	qglyph_t *glyph, *prev_glyph = NULL;
	renderString_f renderString;
	getKerning_f getKerning;
	bool hasKerning;

	if( !str || !font )
		return 0;

	renderString = font->f->renderString;
	getKerning = font->f->getKerning;
	hasKerning = ( flags & TEXTDRAWFLAG_KERNING ) && font->hasKerning;

	while( *s && *s != '\n' )
	{
		if( maxlen && (size_t)( s - str ) >= maxlen )  // stop counting at desired len
			return width;

		olds = s;

		switch( FTLIB_GrabChar( &s, &num, NULL, flags ) )
		{
		case GRABCHAR_CHAR:
			if( num < ' ' )
				break;

			glyph = FTLIB_GetGlyph( font, num );
			if( !glyph )
			{
				num = FTLIB_REPLACEMENT_GLYPH;
				glyph = FTLIB_GetGlyph( font, num );
			}

			if( !glyph->shader )
				renderString( font, olds );

			if( prev_num && hasKerning )
				width += getKerning( font, prev_glyph, glyph );

			width += glyph->x_advance;

			prev_num = num;
			prev_glyph = glyph;
			break;

		case GRABCHAR_COLOR:
			break;

		case GRABCHAR_END:
			return width;

		default:
			assert( 0 );
		}
	}

	return width;
}