{"action":"created","issue":{"url":"https://api.github.com/repos/libgdx/libgdx/issues/3099","labels_url":"https://api.github.com/repos/libgdx/libgdx/issues/3099/labels{/name}","comments_url":"https://api.github.com/repos/libgdx/libgdx/issues/3099/comments","events_url":"https://api.github.com/repos/libgdx/libgdx/issues/3099/events","html_url":"https://github.com/libgdx/libgdx/issues/3099","id":73879330,"number":3099,"title":"Font wrapping error (uses wrong glyph)","user":{"login":"RobRendell","id":1848870,"avatar_url":"https://avatars.githubusercontent.com/u/1848870?v=3","gravatar_id":"","url":"https://api.github.com/users/RobRendell","html_url":"https://github.com/RobRendell","followers_url":"https://api.github.com/users/RobRendell/followers","following_url":"https://api.github.com/users/RobRendell/following{/other_user}","gists_url":"https://api.github.com/users/RobRendell/gists{/gist_id}","starred_url":"https://api.github.com/users/RobRendell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RobRendell/subscriptions","organizations_url":"https://api.github.com/users/RobRendell/orgs","repos_url":"https://api.github.com/users/RobRendell/repos","events_url":"https://api.github.com/users/RobRendell/events{/privacy}","received_events_url":"https://api.github.com/users/RobRendell/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-05-07T07:27:28Z","updated_at":"2015-05-07T23:22:27Z","closed_at":"2015-05-07T13:28:19Z","body":"Are you sick of me raising font wrapping errors yet? :)\r\n\r\nAt lines 148-150 of `GlyphLayout` in the current 1.5.7-SNAPSHOT head, there is a test:\r\n```\r\n// Don't wrap if the glyph would fit with just its width (no xadvance or kerning).\r\nif (wrap && x > targetWidth && i > 1 && x - xAdvance //\r\n\t+ (run.glyphs.get(i - 1).xoffset + run.glyphs.get(i - 1).width) * fontData.scaleX - 0.00001f > targetWidth) {\r\n```\r\nI believe that should be using the xoffset and width of `run.glyphs.get(i)`, not `run.glyphs.get(i - 1)`\r\n\r\nBelow is a reprise of my search-for-bad-strings test which alternates the combination of characters so wide and narrow characters alternate.  It quickly finds a wrapping error with the current code.\r\n\r\nScreenshot:\r\n![image](https://cloud.githubusercontent.com/assets/1848870/7510276/b4b94b74-f4dd-11e4-8c41-9eb75835e5f7.png)\r\n\r\nTest code that produced that screenshot:\r\n```\r\nimport com.badlogic.gdx.ApplicationAdapter;\r\nimport com.badlogic.gdx.Gdx;\r\nimport com.badlogic.gdx.graphics.Color;\r\nimport com.badlogic.gdx.graphics.GL20;\r\nimport com.badlogic.gdx.graphics.g2d.BitmapFont;\r\nimport com.badlogic.gdx.graphics.g2d.BitmapFontCache;\r\nimport com.badlogic.gdx.graphics.g2d.GlyphLayout;\r\nimport com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;\r\nimport com.badlogic.gdx.scenes.scene2d.Stage;\r\nimport com.badlogic.gdx.scenes.scene2d.ui.Label;\r\nimport com.badlogic.gdx.scenes.scene2d.ui.Table;\r\nimport com.badlogic.gdx.utils.viewport.FitViewport;\r\n\r\npublic class FontWrapIssue extends ApplicationAdapter {\r\n\r\n    private static final float GAME_WIDTH = 230.4f;\r\n\r\n    private static final String CHARACTERS = \"WMGCwATFLkJyrfIil\";\r\n    private static final int NUM_CHARACTERS = CHARACTERS.length();\r\n\r\n    private Stage stage;\r\n\r\n    private LabelHack label;\r\n\r\n    private boolean searching = true;\r\n    private long combination = NUM_CHARACTERS * NUM_CHARACTERS * NUM_CHARACTERS * NUM_CHARACTERS * NUM_CHARACTERS;\r\n\r\n    public static void main (String[] args) throws Exception {\r\n        new LwjglApplication(new FontWrapIssue());\r\n    }\r\n\r\n    @Override\r\n    public void create () {\r\n        float gameScale = GAME_WIDTH / Gdx.graphics.getWidth();\r\n        int gameHeight = (int) (Gdx.graphics.getHeight() * gameScale + 0.5);\r\n        stage = new Stage(new FitViewport(GAME_WIDTH, gameHeight));\r\n        Gdx.input.setInputProcessor(stage);\r\n        resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());\r\n        FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal(\"data/arial.ttf\"));\r\n        FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();\r\n        parameter.size = (int) (20 / gameScale + 0.5);\r\n        BitmapFont font = generator.generateFont(parameter);\r\n        font.getData().setScale(gameScale);\r\n        Label.LabelStyle labelStyle = new Label.LabelStyle();\r\n        labelStyle.font = font;\r\n        labelStyle.fontColor = Color.WHITE;\r\n        Table table = new Table();\r\n        table.setFillParent(true);\r\n        addLabel(table, \"\", labelStyle);\r\n        stage.addActor(table);\r\n        table.debug();\r\n    }\r\n\r\n    private void addLabel(Table table, String text, Label.LabelStyle labelStyle) {\r\n        label = new LabelHack(text, labelStyle);\r\n        label.setWrap(true);\r\n        table.add(label).fillX().expandX().row();\r\n\r\n    }\r\n\r\n    @Override\r\n    public void render () {\r\n        if (searching) {\r\n            combination++;\r\n            label.setText(String.format(\"test with %s %s issue\", generateCombination(combination), generateCombination(combination)));\r\n        }\r\n        Gdx.gl.glClearColor(0, 0, 0, 1);\r\n        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);\r\n        stage.act(Gdx.graphics.getDeltaTime());\r\n        stage.draw();\r\n        if (searching) {\r\n            int cacheLines = 0;\r\n            for (GlyphLayout glyphLayout : label.getCache().getLayouts()) {\r\n                cacheLines += glyphLayout.runs.size;\r\n            }\r\n            int boundLines = (int) (label.getHeight() / label.getStyle().font.getLineHeight() + 0.5);\r\n            searching = (cacheLines == boundLines);\r\n        }\r\n    }\r\n\r\n    private String generateCombination(long combination) {\r\n        StringBuilder builder = new StringBuilder();\r\n        boolean toggle = false;\r\n        while (combination > 0) {\r\n            int index = (int) (combination % NUM_CHARACTERS);\r\n            if (toggle) index = NUM_CHARACTERS - 1 - index;\r\n            toggle = !toggle;\r\n            builder.append(CHARACTERS.charAt(index));\r\n            combination /= NUM_CHARACTERS;\r\n        }\r\n        return builder.toString();\r\n    }\r\n\r\n    public static class LabelHack extends Label {\r\n\r\n        public LabelHack(CharSequence text, LabelStyle style) {\r\n            super(text, style);\r\n        }\r\n\r\n        public BitmapFontCache getCache() {\r\n            return getBitmapFontCache();\r\n        }\r\n    }\r\n}\r\n```"},"comment":{"url":"https://api.github.com/repos/libgdx/libgdx/issues/comments/100045509","html_url":"https://github.com/libgdx/libgdx/issues/3099#issuecomment-100045509","issue_url":"https://api.github.com/repos/libgdx/libgdx/issues/3099","id":100045509,"user":{"login":"RobRendell","id":1848870,"avatar_url":"https://avatars.githubusercontent.com/u/1848870?v=3","gravatar_id":"","url":"https://api.github.com/users/RobRendell","html_url":"https://github.com/RobRendell","followers_url":"https://api.github.com/users/RobRendell/followers","following_url":"https://api.github.com/users/RobRendell/following{/other_user}","gists_url":"https://api.github.com/users/RobRendell/gists{/gist_id}","starred_url":"https://api.github.com/users/RobRendell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RobRendell/subscriptions","organizations_url":"https://api.github.com/users/RobRendell/orgs","repos_url":"https://api.github.com/users/RobRendell/repos","events_url":"https://api.github.com/users/RobRendell/events{/privacy}","received_events_url":"https://api.github.com/users/RobRendell/received_events","type":"User","site_admin":false},"created_at":"2015-05-07T23:22:27Z","updated_at":"2015-05-07T23:22:27Z","body":"Hmm, it looks like my suggested fix was wrong - glyph layout can now bomb out with an IndexOutOfBoundsException.  There's something wrong in there (as shown by the test finding a string that wraps incorrectly), but `run.xAdvances.size` is actually one larger than `run.glyphs.size`, so you can get a situation where i is < n but out of bounds for `run.glyphs.get(i)`.\r\n\r\nThe test code above will eventually hit the IndexOutOfBoundsException.  Should I raise a new issue or can you re-open this one?"}}