When using color markup, each subsequent block after a colored block is offset to the left compared to unstyled text.
Additionally, the markup escape code [[ does not correctly cause the markup to be ignored if a closing bracket follows after a word which happens to be a valid color.

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
public class ColorRenderingMain extends ApplicationAdapter {
static final String TEXT_PLAIN = "AAA BBB CCC DDD EEE";
static final String TEXT_COLOR = "[RED]AAA [BLUE]BBB [RED]CCC [BLUE]DDD [RED]EEE";
static final String TEXT_ESCAPE = "[[ORANGE]Escaped, but is colored";
SpriteBatch batch;
BitmapFont font;
public void create () {
batch = new SpriteBatch();
font = new BitmapFont();
font.setColor(Color.BLACK);
font.getData().markupEnabled = true;
}
public void render () {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
font.draw(batch, TEXT_PLAIN, 5, Gdx.graphics.getHeight() - 5);
font.draw(batch, TEXT_COLOR, 5, Gdx.graphics.getHeight() - 20);
font.draw(batch, TEXT_ESCAPE, 5, Gdx.graphics.getHeight() - 35);
batch.end();
}
public static void main (String[] args) throws Exception {
new LwjglApplication(new ColorRenderingMain());
}
}
1.9.3
I've only tested this on windows.
With no color, the glyphs are drawn as a single glyph run. BitmapFont getGlyphs adjusts the glyphs at start and end of a glyph run so the bounds fit tighter, and this is where the difference comes from.
When not followed by a colored run, the x-advances computed by getGlyphs for "A " are 0, 8, 4, so the run width is 12. 0 is the offset for the A position. 8 is the x-advance for A. 4 is the width of space.
getGlyphs has a boolean called tightBounds which is normally true and affects how the first and last glyphs are adjusted so they aren't drawn left of the drawing position or right of the run width. When followed by a colored run, tightBounds is false because more text will be drawn next to the run.
When followed by a colored run, the x-advances computed by getGlyphs for "A " are -1, 8, 2, so the run width is 9. -1 is the offset for the A position, shifted because tightBounds is false. This is wrong because this text is actually first (leftmost), so the tightBounds true should be used for the first glyph. 8 is the x-advance for A. 2 is the x-advance for space, which is correct. The width wasn't used because tightBounds is false since another run is drawn next to this one.
We could have separate tightBoundsStart and tightBoundsEnd parameters to fix at least that part of the problem.
I'm out of time to look into this further for now. Ideally colored and not colored text would have exactly the same spacing, but the complexity of breaking the text into runs makes it hard, especially when wrapping and truncation are considered.
I've found an issue where if the text wraps at the same point that it changes colour then the wrapping will be incorrect and the glyphs will draw outside the bounds of the Label that its being drawn to. I'm not sure if this is related to this issue but it seems similar that markup and wrapping and spacing cause incorrect results.
EDIT: This is actually a different issue, I've made a minimum example and explained it better here: https://github.com/libgdx/libgdx/issues/4425
Most helpful comment
With no color, the glyphs are drawn as a single glyph run. BitmapFont
getGlyphsadjusts the glyphs at start and end of a glyph run so the bounds fit tighter, and this is where the difference comes from.When not followed by a colored run, the x-advances computed by
getGlyphsfor "A " are0, 8, 4, so the run width is 12. 0 is the offset for the A position. 8 is the x-advance for A. 4 is the width of space.getGlyphshas a boolean calledtightBoundswhich is normally true and affects how the first and last glyphs are adjusted so they aren't drawn left of the drawing position or right of the run width. When followed by a colored run,tightBoundsis false because more text will be drawn next to the run.When followed by a colored run, the x-advances computed by
getGlyphsfor "A " are-1, 8, 2, so the run width is 9. -1 is the offset for the A position, shifted becausetightBoundsis false. This is wrong because this text is actually first (leftmost), so thetightBoundstrue should be used for the first glyph. 8 is the x-advance for A. 2 is the x-advance for space, which is correct. The width wasn't used becausetightBoundsis false since another run is drawn next to this one.We could have separate
tightBoundsStartandtightBoundsEndparameters to fix at least that part of the problem.I'm out of time to look into this further for now. Ideally colored and not colored text would have exactly the same spacing, but the complexity of breaking the text into runs makes it hard, especially when wrapping and truncation are considered.