~jaro/balkon

259fe6a14bb6d13e227635bfe344970b422ace1e — Jaro 1 year, 9 months ago aec7239
Use ICU to find line break boundaries.
M .golden/loremIpsum100em/golden => .golden/loremIpsum100em/golden +10 -9
@@ 1,5 1,5 @@
ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -2242, x_size = 99586, y_size = 2242}, spanLayouts = [
    SpanLayout [Fragment {fragmentRect = Rect {x_origin = 0, y_origin = 0, x_size = 99586, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -3363, x_size = 99185, y_size = 3363}, spanLayouts = [
    SpanLayout [Fragment {fragmentRect = Rect {x_origin = 0, y_origin = 0, x_size = 95643, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 47, cluster = 0, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 507, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 1, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 85, cluster = 2, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 212,15 212,15 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -2242, x_size = 
        (GlyphInfo {codepoint = 3, cluster = 209, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 72, cluster = 210, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 68, cluster = 211, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 212, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 70, cluster = 213, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 452, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 212, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -1121, x_size = 99185, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 70, cluster = 213, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 452, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 214, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 80, cluster = 215, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 80, cluster = 216, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 217, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 71, cluster = 218, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -1121, x_size = 99283, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 82, cluster = 219, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 71, cluster = 218, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 219, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 220, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 70, cluster = 221, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 452, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 222, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 435,8 435,9 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -2242, x_size = 
        (GlyphInfo {codepoint = 72, cluster = 433, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 86, cluster = 434, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 87, cluster = 435, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 436, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 79, cluster = 437, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 436, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -2242, x_size = 4041, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 79, cluster = 437, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 68, cluster = 438, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 69, cluster = 439, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 440, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),

M .golden/loremIpsum20em/golden => .golden/loremIpsum20em/golden +52 -52
@@ 1,5 1,5 @@
ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size = 19967, y_size = 12331}, spanLayouts = [
    SpanLayout [Fragment {fragmentRect = Rect {x_origin = 0, y_origin = 0, x_size = 19905, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size = 19525, y_size = 12331}, spanLayouts = [
    SpanLayout [Fragment {fragmentRect = Rect {x_origin = 0, y_origin = 0, x_size = 18541, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 47, cluster = 0, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 507, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 1, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 85, cluster = 2, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 39,12 39,12 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 87, cluster = 36, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 88, cluster = 37, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 85, cluster = 38, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 39, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 68, cluster = 40, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 39, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -1121, x_size = 17674, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 68, cluster = 40, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 71, cluster = 41, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 42, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -1121, x_size = 19860, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 83, cluster = 43, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 42, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 83, cluster = 43, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 44, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 86, cluster = 45, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 70, cluster = 46, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 465, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 79,17 79,17 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 83, cluster = 75, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 76, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 85, cluster = 77, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 78, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 79, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 78, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -2242, x_size = 16812, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 76, cluster = 79, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 81, cluster = 80, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 70, cluster = 81, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 465, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 82, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 71, cluster = 83, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 84, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 71, cluster = 85, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 88, cluster = 86, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -2242, x_size = 19179, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 81, cluster = 87, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 88, cluster = 86, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 81, cluster = 87, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 87, cluster = 88, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 89, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 88, cluster = 90, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 117,8 117,9 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 74, cluster = 112, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 578, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 81, cluster = 113, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 68, cluster = 114, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 115, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 68, cluster = 116, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 115, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -3363, x_size = 17211, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 68, cluster = 116, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 79, cluster = 117, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 118, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 84, cluster = 119, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 131,9 132,8 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 3, cluster = 126, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 72, cluster = 127, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 81, cluster = 128, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 129, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -3363, x_size = 19967, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 80, cluster = 130, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 129, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 80, cluster = 130, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 131, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 68, cluster = 132, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 71, cluster = 133, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 156,8 156,9 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 88, cluster = 150, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 151, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 86, cluster = 152, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 153, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 81, cluster = 154, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 153, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -4484, x_size = 19508, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 81, cluster = 154, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 155, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 86, cluster = 156, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 87, cluster = 157, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 175,9 176,8 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 68, cluster = 169, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 87, cluster = 170, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 171, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 172, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -4484, x_size = 19496, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 81, cluster = 173, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 172, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 81, cluster = 173, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 174, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 88, cluster = 175, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 79, cluster = 176, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 202,8 202,9 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 3, cluster = 195, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 88, cluster = 196, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 87, cluster = 197, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 198, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 68, cluster = 199, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 198, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -5605, x_size = 18074, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 68, cluster = 199, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 79, cluster = 200, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 201, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 84, cluster = 202, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 220,9 221,8 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 70, cluster = 213, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 452, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 214, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 80, cluster = 215, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 80, cluster = 216, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -5605, x_size = 19717, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 82, cluster = 217, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 80, cluster = 216, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 217, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 71, cluster = 218, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 219, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 220, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 241,8 241,9 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 88, cluster = 233, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 234, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 86, cluster = 235, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 236, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 68, cluster = 237, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 236, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -6726, x_size = 16045, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 68, cluster = 237, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 88, cluster = 238, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 87, cluster = 239, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 392, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 72, cluster = 240, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 265,9 266,8 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 85, cluster = 257, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 72, cluster = 258, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 83, cluster = 259, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 85, cluster = 260, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -6726, x_size = 19780, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 72, cluster = 261, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 85, cluster = 260, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 72, cluster = 261, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 75, cluster = 262, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 571, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 72, cluster = 263, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 81, cluster = 264, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 279,8 279,9 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 3, cluster = 270, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 271, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 81, cluster = 272, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 273, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 89, cluster = 274, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 488, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 273, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -7847, x_size = 19525, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 89, cluster = 274, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 488, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 275, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 79, cluster = 276, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 88, cluster = 277, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 311,9 312,8 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 71, cluster = 302, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 303, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 79, cluster = 304, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 305, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -7847, x_size = 19775, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 85, cluster = 306, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 305, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 85, cluster = 306, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 72, cluster = 307, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 308, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 72, cluster = 309, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 325,8 325,9 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 76, cluster = 315, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 68, cluster = 316, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 87, cluster = 317, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 318, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 81, cluster = 319, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 318, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -8968, x_size = 17455, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 81, cluster = 319, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 88, cluster = 320, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 79, cluster = 321, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 79, cluster = 322, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 358,16 359,16 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 87, cluster = 348, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 349, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 350, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 70, cluster = 351, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 465, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -8968, x_size = 19822, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 70, cluster = 352, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 465, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 70, cluster = 351, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 465, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 70, cluster = 352, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 465, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 68, cluster = 353, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 72, cluster = 354, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 70, cluster = 355, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 465, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 68, cluster = 356, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 87, cluster = 357, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 402, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 358, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 70, cluster = 359, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 465, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 358, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -10089, x_size = 18534, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 70, cluster = 359, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 465, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 88, cluster = 360, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 83, cluster = 361, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 362, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 403,14 404,14 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 88, cluster = 392, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 79, cluster = 393, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 273, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 83, cluster = 394, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 68, cluster = 395, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -10089, x_size = 19687, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 3, cluster = 396, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 68, cluster = 395, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 396, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 84, cluster = 397, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 88, cluster = 398, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 399, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 400, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 401, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 3, cluster = 400, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -11210, x_size = 19490, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 82, cluster = 401, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 431, cluster = 402, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 1033, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 70, cluster = 405, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 465, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 76, cluster = 406, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}),


@@ 448,9 449,8 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = -12331, x_size =
        (GlyphInfo {codepoint = 68, cluster = 438, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 522, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 69, cluster = 439, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 589, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 82, cluster = 440, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 85, cluster = 441, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0})]
    }, Fragment {fragmentRect = Rect {x_origin = 0, y_origin = -11210, x_size = 1681, y_size = -1121}, fragmentPen = (0,-932), fragmentGlyphs =
        [(GlyphInfo {codepoint = 88, cluster = 442, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 85, cluster = 441, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 386, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 88, cluster = 442, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 574, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 80, cluster = 443, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 861, y_advance = 0, x_offset = 0, y_offset = 0}),
        (GlyphInfo {codepoint = 17, cluster = 444, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 246, y_advance = 0, x_offset = 0, y_offset = 0})]
    }]

M balkon.cabal => balkon.cabal +4 -1
@@ 97,6 97,7 @@ library
    -- Modules exported by the library.
    exposed-modules:
        Data.Text.ParagraphLayout,
        Data.Text.ParagraphLayout.Break,
        Data.Text.ParagraphLayout.Fragment,
        Data.Text.ParagraphLayout.LineHeight,
        Data.Text.ParagraphLayout.Plain,


@@ 133,6 134,7 @@ test-suite balkon-test

    other-modules:
        Data.Text.ParagraphLayoutSpec,
        Data.Text.ParagraphLayout.BreakSpec,
        Data.Text.ParagraphLayout.FontLoader,
        Data.Text.ParagraphLayout.ParagraphConstruction,
        Data.Text.ParagraphLayout.ParagraphData,


@@ 153,7 155,8 @@ test-suite balkon-test
        hspec-discover,
        hspec-golden ^>=0.2.0.0,
        harfbuzz-pure ^>=1.0.2.0,
        text ^>=2.0.1
        text ^>=2.0.1,
        text-icu ^>=0.8.0.2

    build-tool-depends:
        hspec-discover:hspec-discover

A src/Data/Text/ParagraphLayout/Break.hs => src/Data/Text/ParagraphLayout/Break.hs +39 -0
@@ 0,0 1,39 @@
-- | Boundary analysis using `Data.Text.ICU`, but returning numeric offsets
-- instead of text slices.
--
-- Within this module, each /offset/ refers to the number of `Word8` items
-- (also called UTF-8 code units or bytes) between the start of the input `Text`
-- and the position of the break. The internal offset of the `Text` from the
-- start of its underlying byte array is excluded.
module Data.Text.ParagraphLayout.Break (breaksDesc, subOffsetsDesc)
where

import Data.Text (Text)
import Data.Text.Foreign (lengthWord8)
import Data.Text.ICU (Break, Breaker, breaksRight, brkPrefix, brkStatus)

-- | List of all breaks in the given text, with offsets in descending order,
-- including the status of the break if applicable.
--
-- Includes the start of the text (with offset 0) as the last list item.
--
-- Excludes the end of the text (with offset equal to the text length).
breaksDesc :: Breaker a -> Text -> [(Int, a)]
breaksDesc breaker input = map brkStartOffsetStatus $ breaksRight breaker input

brkStartOffsetStatus :: Break a -> (Int, a)
brkStartOffsetStatus brk = (brkStartOffset brk, brkStatus brk)

-- | The ICU library returns "breaks" as slices of text with two boundaries.
-- This gives the smaller of the two distances from the start of the text
-- to the boundaries of the break.
brkStartOffset :: Break a -> Int
brkStartOffset brk = lengthWord8 (brkPrefix brk)

-- | Given a list of offsets into a text in descending order, produce a list of
-- corresponding offsets into a slice of the text starting at a given offset.
subOffsetsDesc :: Int -> [(Int, a)] -> [(Int, a)]
subOffsetsDesc d = takeWhile valid . map adjust
    where
        valid (off, _) = off >= 0
        adjust (off, a) = (off - d, a)

M src/Data/Text/ParagraphLayout/Plain.hs => src/Data/Text/ParagraphLayout/Plain.hs +70 -11
@@ 22,6 22,7 @@ where

import Data.Int (Int32)
import Data.List (mapAccumL)
import Data.Maybe (fromMaybe, listToMaybe)
import Data.Text.Array (Array)
import Data.Text.Foreign (I8, lengthWord8)
import Data.Text.Glyphize


@@ 35,9 36,12 @@ import Data.Text.Glyphize
    ,fontExtentsForDir
    ,shape
    )
import Data.Text.ICU (LocaleName(Locale), breakLine)
import qualified Data.Text.ICU as BreakStatus (Line)
import Data.Text.Internal (Text(Text))
import qualified Data.Text.Lazy as Lazy

import Data.Text.ParagraphLayout.Break
import Data.Text.ParagraphLayout.Fragment
import Data.Text.ParagraphLayout.LineHeight
import qualified Data.Text.ParagraphLayout.ProtoFragment as PF


@@ 234,13 238,40 @@ tryAddSplitRunsH _ currentX runs 0 = do
    let (runs1, runs2) = splitTextsAt8 1 runs
    let (_, pfs) = mapAccumL addRunH currentX runs1
    (pfs, runs2)
tryAddSplitRunsH maxWidth currentX runs splitPoint = do
    let (runs1, runs2) = splitTextsAt8 splitPoint runs
tryAddSplitRunsH maxWidth currentX runs breakPoint = do
    -- TODO: Trim spaces around breaks.
    let (runs1, runs2) = splitTextsAt8 breakPoint runs
    let (nextX, pfs) = mapAccumL addRunH currentX runs1
    let next = nextBreakPoint (fromIntegral breakPoint) runs
    if abs nextX <= maxWidth
        then (pfs, runs2)
        -- TODO: Use ICU breaking library.
        else tryAddSplitRunsH maxWidth currentX runs (splitPoint-1)
        else tryAddSplitRunsH maxWidth currentX runs (fromIntegral next)

-- | Find the farthermost break point in one of the given runs, whose offset is
-- less than the given limit, respecting locale rules.
--
-- The result will be an offset in `Word8` units from the start of the first
-- `Run` from the list.
--
-- If no breaks are possible, the result will be @0@.
nextBreakPoint :: Int -> [WithSpan Run] -> Int
nextBreakPoint _ [] = 0
nextBreakPoint limit runs@(headRun:_) = fromMaybe 0 $ listToMaybe points
    where
        -- TODO: Try to limit deconstruction of texts for offsets.
        (Text _ firstRunOffset _) = getText headRun
        points =
            dropWhile (>= limit) $ breakPoints firstRunOffset $ reverse runs

breakPoints :: Int -> [WithSpan Run] -> [Int]
breakPoints _ [] = []
breakPoints firstRunOffset (x:xs) = offsets ++ rest
    where
        -- TODO: Try to limit deconstruction of texts for offsets.
        (Text _ thisRunOffset _) = getText x
        offsets = map (correctOffset . fst) (runLineBreaks x)
        correctOffset = (+ (thisRunOffset - firstRunOffset))
        rest = breakPoints firstRunOffset xs

-- | Calculate layout for multiple runs on the same line and
-- arrange them in one horizontal direction starting from the given x_offset.


@@ 282,24 313,52 @@ shapeRun (WithSpan rs run) = shape font buffer features
        features = []

resolveSpans :: Paragraph -> [RS.ResolvedSpan]
resolveSpans (Paragraph arr off spans opts) = do
    let texts = cuts arr off spans
resolveSpans p@(Paragraph arr off spans opts) = do
    let (end, texts) = cuts arr off spans
    let indexes = [0..]
    let paragraphStart = fromIntegral off

    (s, t, i) <- zip3 spans texts indexes
    let lang = spanLanguage s
    let breaks = paragraphLineBreaks p end lang
    -- TODO: Try to limit deconstruction of texts for offsets.
    let (Text _ spanStart _) = t
    return RS.ResolvedSpan
        { RS.spanIndex = i
        , RS.spanText = t
        , RS.spanFont = paragraphFont opts
        , RS.spanLineHeight = paragraphLineHeight opts
        , RS.spanLanguage = spanLanguage s
        , RS.spanLanguage = lang
        , RS.spanLineBreaks = subOffsetsDesc (spanStart - paragraphStart) breaks
        }

-- | Produce a list of `Text`s, defined by an initial offset and a list of
-- consecutive `Span`s, out of the underlying `Array`.
paragraphLineBreaks :: Paragraph -> I8 -> String -> [(Int, BreakStatus.Line)]
paragraphLineBreaks (Paragraph arr off _ _) end lang =
    breaksDesc (breakLine (localeFromLanguage lang)) paragraphText
    where
        paragraphText = Text arr (fromIntegral off) (fromIntegral (end - off))

runLineBreaks :: WithSpan Run -> [(Int, BreakStatus.Line)]
runLineBreaks (WithSpan rs run) = dropWhile (not . valid) $
    subOffsetsDesc (runStart - spanStart) $ RS.spanLineBreaks rs
    where
        valid (off, _) = off < runLength
        runLength = lengthWord8 $ getText run
        -- TODO: Try to limit deconstruction of texts for offsets.
        (Text _ runStart _) = getText run
        (Text _ spanStart _) = getText rs

-- TODO: Identify and correct for differences between the two.
localeFromLanguage :: String -> LocaleName
localeFromLanguage x = Locale x

-- | Given an underlying `Array`, an initial offset, and a list of consecutive
-- `Span`s, produce a list of `Text`s corresponding to the given spans, as well
-- as the offset of the end of the last `Text`.
--
-- TODO: Consider adding checks for array bounds.
cuts :: Array -> I8 -> [Span] -> [Text]
cuts arr initialOffset spans = snd $ mapAccumL (cut arr) initialOffset spans
cuts :: Array -> I8 -> [Span] -> (I8, [Text])
cuts arr initialOffset spans = mapAccumL (cut arr) initialOffset spans

-- | Produce a `Text`, defined by an initial offset and a `Span`, out of the
-- underlying `Array`.

M src/Data/Text/ParagraphLayout/ResolvedSpan.hs => src/Data/Text/ParagraphLayout/ResolvedSpan.hs +2 -0
@@ 3,6 3,7 @@ where

import Data.Text (Text)
import Data.Text.Glyphize (Font)
import qualified Data.Text.ICU as BreakStatus (Line)

import Data.Text.ParagraphLayout.LineHeight
import Data.Text.ParagraphLayout.TextContainer


@@ 15,6 16,7 @@ data ResolvedSpan = ResolvedSpan
    , spanFont :: Font
    , spanLineHeight :: LineHeight
    , spanLanguage :: String
    , spanLineBreaks :: [(Int, BreakStatus.Line)]
    }
    deriving (Show)


A test/Data/Text/ParagraphLayout/BreakSpec.hs => test/Data/Text/ParagraphLayout/BreakSpec.hs +122 -0
@@ 0,0 1,122 @@
module Data.Text.ParagraphLayout.BreakSpec (spec) where

import Data.Text (empty, pack, singleton)
import Data.Text.ICU
    (LocaleName(Locale)
    ,breakCharacter
    ,breakLine
    ,breakSentence
    ,breakWord
    )
import qualified Data.Text.ICU as BreakStatus (Line(..), Word(..))

import Test.Hspec
import Data.Text.ParagraphLayout.Break

spec :: Spec
spec = do

    describe "breaksDesc" $ do

        -- One of the crucial building blocks of a text layout engine.
        describe "breakLine" $ do
            let b lang = breaksDesc $ breakLine (Locale lang)

            it "finds no breaks in empty input" $
                b "en" empty `shouldBe`
                    []

            it "finds break at offset 0 in non-empty input" $
                b "en" (singleton 'a') `shouldBe`
                    [(0, BreakStatus.Soft)]

            it "finds hard break after newline" $
                b "en" (pack "hello\nworld") `shouldBe`
                    [(6, BreakStatus.Hard)
                    ,(0, BreakStatus.Soft)
                    ]

            it "finds soft breaks after spaces and tabs" $
                b "en" (pack "a few\twords") `shouldBe`
                    [(6, BreakStatus.Soft)
                    ,(2, BreakStatus.Soft)
                    ,(0, BreakStatus.Soft)
                    ]

            it "finds soft breaks after spaces and hyphens" $
                b "cs" (pack "následuje stanice Frýdek-Místek") `shouldBe`
                    [(27, BreakStatus.Soft)
                    ,(19, BreakStatus.Soft)
                    ,(11, BreakStatus.Soft)
                    ,(0, BreakStatus.Soft)
                    ]

            it "finds soft breaks in Japanese kana" $
                b "ja" (pack "トイレはどこですか?") `shouldBe`
                    [(24, BreakStatus.Soft)
                    ,(21, BreakStatus.Soft)
                    ,(18, BreakStatus.Soft)
                    ,(15, BreakStatus.Soft)
                    ,(12, BreakStatus.Soft)
                    ,(9, BreakStatus.Soft)
                    ,(6, BreakStatus.Soft)
                    ,(3, BreakStatus.Soft)
                    ,(0, BreakStatus.Soft)
                    ]

        -- Probably not useful for a web browser rendering engine.
        describe "breakSentence" $ do
            let b lang = breaksDesc $ breakSentence (Locale lang)

            it "finds no breaks in empty input" $
                b "en" empty `shouldBe`
                    []

            it "finds break at offset 0 in non-empty input" $
                b "en" (singleton 'a') `shouldBe`
                    [(0, ())]

        -- Probably not useful for a web browser rendering engine,
        -- but may be used for text search and selection.
        describe "breakWord" $ do
            let b lang = breaksDesc $ breakWord (Locale lang)

            it "finds no breaks in empty input" $
                b "en" empty `shouldBe`
                    []

            it "finds break at offset 0 in non-empty input" $
                b "en" (singleton 'a') `shouldBe`
                    [(0, BreakStatus.Uncategorized)]

            it "finds breaks after runs of letters and spaces" $
                b "en" (pack "a few   words") `shouldBe`
                    [(8, BreakStatus.Uncategorized)
                    ,(5, BreakStatus.Letter)
                    ,(2, BreakStatus.Uncategorized)
                    ,(1, BreakStatus.Letter)
                    ,(0, BreakStatus.Uncategorized)
                    ]

        -- Probably not useful for Balkón;
        -- HarfBuzz takes care of identifying character clusters for us.
        describe "breakCharacter" $ do
            let b lang = breaksDesc $ breakCharacter (Locale lang)

            it "finds no breaks in empty input" $
                b "en" empty `shouldBe`
                    []

            it "finds break at offset 0 in non-empty input" $
                b "en" (singleton 'a') `shouldBe`
                    [(0, ())]

    describe "subOffsetsDesc" $ do

        let result = subOffsetsDesc 5 [(11, 'a'), (8, 'b'), (5, 'c'), (2, 'd')]

        it "should reduce offsets" $
            map fst result `shouldBe` [6, 3, 0]

        it "should preserve payload" $
            map snd result `shouldBe` ['a', 'b', 'c']

M test/Data/Text/ParagraphLayout/SpanData.hs => test/Data/Text/ParagraphLayout/SpanData.hs +3 -0
@@ 17,6 17,7 @@ emptySpan font = ResolvedSpan
    , spanFont = font
    , spanLineHeight = Normal
    , spanLanguage = "en"
    , spanLineBreaks = []
    }

czechHello :: Font -> ResolvedSpan


@@ 26,6 27,7 @@ czechHello font = ResolvedSpan
    , spanFont = font
    , spanLineHeight = Normal
    , spanLanguage = "cs"
    , spanLineBreaks = []
    }

serbianMixedScript :: Font -> ResolvedSpan


@@ 35,4 37,5 @@ serbianMixedScript font = ResolvedSpan
    , spanFont = font
    , spanLineHeight = Normal
    , spanLanguage = "sr"
    , spanLineBreaks = []
    }