diff --git a/e2etests/e2e_test.go b/e2etests/e2e_test.go index 41ad5498d..5a5b7c57d 100644 --- a/e2etests/e2e_test.go +++ b/e2etests/e2e_test.go @@ -38,6 +38,7 @@ func TestE2E(t *testing.T) { t.Run("regression", testRegression) t.Run("todo", testTodo) t.Run("measured", testMeasured) + t.Run("unicode", testUnicode) } func testSanity(t *testing.T) { diff --git a/e2etests/testdata/regression/dagre_special_ids/dagre/board.exp.json b/e2etests/testdata/regression/dagre_special_ids/dagre/board.exp.json index d7c736755..2cb1ebfab 100644 --- a/e2etests/testdata/regression/dagre_special_ids/dagre/board.exp.json +++ b/e2etests/testdata/regression/dagre_special_ids/dagre/board.exp.json @@ -91,7 +91,7 @@ "x": 302, "y": 0 }, - "width": 102, + "width": 97, "height": 82, "opacity": 1, "strokeDash": 0, @@ -119,7 +119,7 @@ "italic": false, "bold": true, "underline": false, - "labelWidth": 57, + "labelWidth": 52, "labelHeight": 37, "labelPosition": "INSIDE_MIDDLE_CENTER", "zIndex": 0, @@ -129,7 +129,7 @@ "id": "\"a\\\\yode\"", "type": "rectangle", "pos": { - "x": 464, + "x": 459, "y": 8 }, "width": 94, @@ -170,7 +170,7 @@ "id": "there", "type": "rectangle", "pos": { - "x": 624, + "x": 619, "y": 182 }, "width": 83, @@ -211,7 +211,7 @@ "id": "'a\\\"ode'", "type": "rectangle", "pos": { - "x": 618, + "x": 613, "y": 8 }, "width": 94, @@ -252,7 +252,7 @@ "id": "\"a\\\\node\"", "type": "rectangle", "pos": { - "x": 772, + "x": 767, "y": 8 }, "width": 95, @@ -317,19 +317,19 @@ "labelPercentage": 0, "route": [ { - "x": 511, + "x": 506, "y": 74 }, { - "x": 511, + "x": 506, "y": 120.4 }, { - "x": 533.5, + "x": 528.5, "y": 144.12662337662337 }, { - "x": 623.5, + "x": 618.5, "y": 192.63311688311688 } ], @@ -365,19 +365,19 @@ "labelPercentage": 0, "route": [ { - "x": 665, + "x": 660, "y": 74 }, { - "x": 665, + "x": 660, "y": 120.4 }, { - "x": 665, + "x": 660, "y": 142 }, { - "x": 665, + "x": 660, "y": 182 } ], @@ -413,19 +413,19 @@ "labelPercentage": 0, "route": [ { - "x": 819.5, + "x": 814.5, "y": 74 }, { - "x": 819.5, + "x": 814.5, "y": 120.4 }, { - "x": 796.9, + "x": 791.9, "y": 144 }, { - "x": 706.5, + "x": 701.5, "y": 192 } ], diff --git a/e2etests/testdata/regression/dagre_special_ids/dagre/sketch.exp.svg b/e2etests/testdata/regression/dagre_special_ids/dagre/sketch.exp.svg index 35734e017..5b4018056 100644 --- a/e2etests/testdata/regression/dagre_special_ids/dagre/sketch.exp.svg +++ b/e2etests/testdata/regression/dagre_special_ids/dagre/sketch.exp.svg @@ -3,7 +3,7 @@ id="d2-svg" style="background: white;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" -width="1071" height="452" viewBox="-102 -102 1071 452">๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธ + + + \ No newline at end of file diff --git a/e2etests/testdata/unicode/emojis/elk/board.exp.json b/e2etests/testdata/unicode/emojis/elk/board.exp.json new file mode 100644 index 000000000..2e524b35a --- /dev/null +++ b/e2etests/testdata/unicode/emojis/elk/board.exp.json @@ -0,0 +1,170 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 12, + "y": 12 + }, + "width": 205, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 160, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "โœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠ", + "type": "rectangle", + "pos": { + "x": 237, + "y": 12 + }, + "width": 833, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "โœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠ", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 788, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "โ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธ", + "type": "rectangle", + "pos": { + "x": 201, + "y": 148 + }, + "width": 905, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "โ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธ", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 860, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(โœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠ -> โ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธ)[0]", + "src": "โœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠ", + "srcArrow": "none", + "srcLabel": "", + "dst": "โ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธ", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 653.5, + "y": 78 + }, + { + "x": 653.5, + "y": 148 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/unicode/emojis/elk/sketch.exp.svg b/e2etests/testdata/unicode/emojis/elk/sketch.exp.svg new file mode 100644 index 000000000..7ccc8cb4f --- /dev/null +++ b/e2etests/testdata/unicode/emojis/elk/sketch.exp.svg @@ -0,0 +1,52 @@ + +๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธ + + + \ No newline at end of file diff --git a/e2etests/testdata/unicode/japanese-basic/dagre/board.exp.json b/e2etests/testdata/unicode/japanese-basic/dagre/board.exp.json new file mode 100644 index 000000000..4bc654165 --- /dev/null +++ b/e2etests/testdata/unicode/japanese-basic/dagre/board.exp.json @@ -0,0 +1,48 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 0, + "y": 0 + }, + "width": 246, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 201, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/unicode/japanese-basic/dagre/sketch.exp.svg b/e2etests/testdata/unicode/japanese-basic/dagre/sketch.exp.svg new file mode 100644 index 000000000..b30f6e8c4 --- /dev/null +++ b/e2etests/testdata/unicode/japanese-basic/dagre/sketch.exp.svg @@ -0,0 +1,52 @@ + +ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ + + + \ No newline at end of file diff --git a/e2etests/testdata/unicode/japanese-basic/elk/board.exp.json b/e2etests/testdata/unicode/japanese-basic/elk/board.exp.json new file mode 100644 index 000000000..7b54eaf15 --- /dev/null +++ b/e2etests/testdata/unicode/japanese-basic/elk/board.exp.json @@ -0,0 +1,48 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 12, + "y": 12 + }, + "width": 246, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 201, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/unicode/japanese-basic/elk/sketch.exp.svg b/e2etests/testdata/unicode/japanese-basic/elk/sketch.exp.svg new file mode 100644 index 000000000..29d9caa5c --- /dev/null +++ b/e2etests/testdata/unicode/japanese-basic/elk/sketch.exp.svg @@ -0,0 +1,52 @@ + +ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ + + + \ No newline at end of file diff --git a/e2etests/testdata/unicode/japanese-full/dagre/board.exp.json b/e2etests/testdata/unicode/japanese-full/dagre/board.exp.json new file mode 100644 index 000000000..76f3ee1c3 --- /dev/null +++ b/e2etests/testdata/unicode/japanese-full/dagre/board.exp.json @@ -0,0 +1,138 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 0, + "y": 0 + }, + "width": 1382, + "height": 98, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ใ‚ใ‚‹ๆ—ฅใ€ใƒˆใƒžใƒˆใŒ้“ใ‚’ๆญฉใ„ใฆใ„ใŸใ‚‰ใ€้“่ทฏใฎๅ‘ใ“ใ†ใ‹ใ‚‰ใ‚ญใƒฅใ‚ฆใƒชใŒใ‚„ใฃใฆๆฅใพใ—ใŸใ€‚\nใƒˆใƒžใƒˆใฏ้ฉšใ„ใฆๅฐ‹ใญใพใ—ใŸใ€‚\nใ€Œใ‚ญใƒฅใ‚ฆใƒชใ•ใ‚“ใ€ใฉใ†ใ—ใฆใ‚ใชใŸใฏใ“ใ“ใซใ„ใ‚‹ใฎใงใ™ใ‹๏ผŸใ€ ใ‚ญใƒฅใ‚ฆใƒชใฏ็ญ”ใˆใพใ—ใŸใ€‚ใ€Œใ‚ใชใŸใจๅŒใ˜็†็”ฑใงใ“ใ“ใซใ„ใพใ™ใ€‚ใ‚ตใƒฉใƒ€ใซใชใ‚‹ใŸใ‚ใซใ€‚ใ€", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 1337, + "labelHeight": 53, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "rectangle", + "pos": { + "x": 8, + "y": 219 + }, + "width": 1367, + "height": 115, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ใ€ŒใƒใƒŠใƒŠใฏ็šฎใ‚’ๅ‰ฅใ„ใฆ้ฃŸในใ‚‹ใ‚‚ใฎใงใ™ใ€‚ใ€", + "fontSize": 55, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 1322, + "labelHeight": 70, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a -> b)[0]", + "src": "a", + "srcArrow": "none", + "srcLabel": "", + "dst": "b", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "ใ€Œใƒใ‚ซใฏๆญปใชใชใใ‚ƒๆฒปใ‚‰ใชใ„ใ€‚ใ€", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 289, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 691, + "y": 98 + }, + { + "x": 691, + "y": 146.4 + }, + { + "x": 691, + "y": 170.7 + }, + { + "x": 691, + "y": 219.5 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/unicode/japanese-full/dagre/sketch.exp.svg b/e2etests/testdata/unicode/japanese-full/dagre/sketch.exp.svg new file mode 100644 index 000000000..e821ce14a --- /dev/null +++ b/e2etests/testdata/unicode/japanese-full/dagre/sketch.exp.svg @@ -0,0 +1,59 @@ + +ใ‚ใ‚‹ๆ—ฅใ€ใƒˆใƒžใƒˆใŒ้“ใ‚’ๆญฉใ„ใฆใ„ใŸใ‚‰ใ€้“่ทฏใฎๅ‘ใ“ใ†ใ‹ใ‚‰ใ‚ญใƒฅใ‚ฆใƒชใŒใ‚„ใฃใฆๆฅใพใ—ใŸใ€‚ใƒˆใƒžใƒˆใฏ้ฉšใ„ใฆๅฐ‹ใญใพใ—ใŸใ€‚ใ€Œใ‚ญใƒฅใ‚ฆใƒชใ•ใ‚“ใ€ใฉใ†ใ—ใฆใ‚ใชใŸใฏใ“ใ“ใซใ„ใ‚‹ใฎใงใ™ใ‹๏ผŸใ€ ใ‚ญใƒฅใ‚ฆใƒชใฏ็ญ”ใˆใพใ—ใŸใ€‚ใ€Œใ‚ใชใŸใจๅŒใ˜็†็”ฑใงใ“ใ“ใซใ„ใพใ™ใ€‚ใ‚ตใƒฉใƒ€ใซใชใ‚‹ใŸใ‚ใซใ€‚ใ€ใ€ŒใƒใƒŠใƒŠใฏ็šฎใ‚’ๅ‰ฅใ„ใฆ้ฃŸในใ‚‹ใ‚‚ใฎใงใ™ใ€‚ใ€ ใ€Œใƒใ‚ซใฏๆญปใชใชใใ‚ƒๆฒปใ‚‰ใชใ„ใ€‚ใ€ + + + \ No newline at end of file diff --git a/e2etests/testdata/unicode/japanese-full/elk/board.exp.json b/e2etests/testdata/unicode/japanese-full/elk/board.exp.json new file mode 100644 index 000000000..08cca5c14 --- /dev/null +++ b/e2etests/testdata/unicode/japanese-full/elk/board.exp.json @@ -0,0 +1,129 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 12, + "y": 12 + }, + "width": 1382, + "height": 98, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ใ‚ใ‚‹ๆ—ฅใ€ใƒˆใƒžใƒˆใŒ้“ใ‚’ๆญฉใ„ใฆใ„ใŸใ‚‰ใ€้“่ทฏใฎๅ‘ใ“ใ†ใ‹ใ‚‰ใ‚ญใƒฅใ‚ฆใƒชใŒใ‚„ใฃใฆๆฅใพใ—ใŸใ€‚\nใƒˆใƒžใƒˆใฏ้ฉšใ„ใฆๅฐ‹ใญใพใ—ใŸใ€‚\nใ€Œใ‚ญใƒฅใ‚ฆใƒชใ•ใ‚“ใ€ใฉใ†ใ—ใฆใ‚ใชใŸใฏใ“ใ“ใซใ„ใ‚‹ใฎใงใ™ใ‹๏ผŸใ€ ใ‚ญใƒฅใ‚ฆใƒชใฏ็ญ”ใˆใพใ—ใŸใ€‚ใ€Œใ‚ใชใŸใจๅŒใ˜็†็”ฑใงใ“ใ“ใซใ„ใพใ™ใ€‚ใ‚ตใƒฉใƒ€ใซใชใ‚‹ใŸใ‚ใซใ€‚ใ€", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 1337, + "labelHeight": 53, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "rectangle", + "pos": { + "x": 19, + "y": 271 + }, + "width": 1367, + "height": 115, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ใ€ŒใƒใƒŠใƒŠใฏ็šฎใ‚’ๅ‰ฅใ„ใฆ้ฃŸในใ‚‹ใ‚‚ใฎใงใ™ใ€‚ใ€", + "fontSize": 55, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 1322, + "labelHeight": 70, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a -> b)[0]", + "src": "a", + "srcArrow": "none", + "srcLabel": "", + "dst": "b", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "ใ€Œใƒใ‚ซใฏๆญปใชใชใใ‚ƒๆฒปใ‚‰ใชใ„ใ€‚ใ€", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 289, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 703, + "y": 110 + }, + { + "x": 703, + "y": 271 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/unicode/japanese-full/elk/sketch.exp.svg b/e2etests/testdata/unicode/japanese-full/elk/sketch.exp.svg new file mode 100644 index 000000000..16635fff6 --- /dev/null +++ b/e2etests/testdata/unicode/japanese-full/elk/sketch.exp.svg @@ -0,0 +1,59 @@ + +ใ‚ใ‚‹ๆ—ฅใ€ใƒˆใƒžใƒˆใŒ้“ใ‚’ๆญฉใ„ใฆใ„ใŸใ‚‰ใ€้“่ทฏใฎๅ‘ใ“ใ†ใ‹ใ‚‰ใ‚ญใƒฅใ‚ฆใƒชใŒใ‚„ใฃใฆๆฅใพใ—ใŸใ€‚ใƒˆใƒžใƒˆใฏ้ฉšใ„ใฆๅฐ‹ใญใพใ—ใŸใ€‚ใ€Œใ‚ญใƒฅใ‚ฆใƒชใ•ใ‚“ใ€ใฉใ†ใ—ใฆใ‚ใชใŸใฏใ“ใ“ใซใ„ใ‚‹ใฎใงใ™ใ‹๏ผŸใ€ ใ‚ญใƒฅใ‚ฆใƒชใฏ็ญ”ใˆใพใ—ใŸใ€‚ใ€Œใ‚ใชใŸใจๅŒใ˜็†็”ฑใงใ“ใ“ใซใ„ใพใ™ใ€‚ใ‚ตใƒฉใƒ€ใซใชใ‚‹ใŸใ‚ใซใ€‚ใ€ใ€ŒใƒใƒŠใƒŠใฏ็šฎใ‚’ๅ‰ฅใ„ใฆ้ฃŸในใ‚‹ใ‚‚ใฎใงใ™ใ€‚ใ€ ใ€Œใƒใ‚ซใฏๆญปใชใชใใ‚ƒๆฒปใ‚‰ใชใ„ใ€‚ใ€ + + + \ No newline at end of file diff --git a/e2etests/testdata/unicode/japanese-mixed/dagre/board.exp.json b/e2etests/testdata/unicode/japanese-mixed/dagre/board.exp.json new file mode 100644 index 000000000..506dfab48 --- /dev/null +++ b/e2etests/testdata/unicode/japanese-mixed/dagre/board.exp.json @@ -0,0 +1,494 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 1646, + "y": 0 + }, + "width": 668, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ใƒˆใƒžใƒˆใŒ่ตคใใชใฃใŸใฎใฏใชใœใงใ™ใ‹๏ผŸBecause it saw the salad dressing!๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 623, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "rectangle", + "pos": { + "x": 0, + "y": 166 + }, + "width": 3959, + "height": 171, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ใƒˆใƒžใƒˆใŒ่ตคใใชใฃใŸใฎใฏใชใœใงใ™ใ‹๏ผŸBecause it saw the salad dressing!๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ", + "fontSize": 100, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 3914, + "labelHeight": 126, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "c", + "type": "rectangle", + "pos": { + "x": 1817, + "y": 437 + }, + "width": 326, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ไปŠๆ—ฅใฏTokyoใงsushiใ‚’้ฃŸในใพใ—ใŸ", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 281, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "d", + "type": "rectangle", + "pos": { + "x": 888, + "y": 603 + }, + "width": 2184, + "height": 100, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ๅ…ˆๆ—ฅใ€Shibuyaใงๅ‹้”ใจshoppingใ‚’ๆฅฝ๐Ÿ˜Šใ—ใ‚“ใ ๅพŒใ€ramenๅฑ‹ใงdelicious๐Ÿ˜Šใชใƒฉใƒผใƒกใƒณใ‚’้ฃŸในใŸใ€‚", + "fontSize": 43, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 2139, + "labelHeight": 55, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "e", + "type": "rectangle", + "pos": { + "x": 1877, + "y": 803 + }, + "width": 206, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "English English English", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 161, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "f", + "type": "rectangle", + "pos": { + "x": 1897, + "y": 969 + }, + "width": 165, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ๅ…ˆๆ—ฅๅ…ˆๆ—ฅๅ…ˆๆ—ฅ", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 120, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a -> b)[0]", + "src": "a", + "srcArrow": "none", + "srcLabel": "", + "dst": "b", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1979.5, + "y": 66 + }, + { + "x": 1979.5, + "y": 106 + }, + { + "x": 1979.5, + "y": 126 + }, + { + "x": 1979.5, + "y": 166 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(b -> c)[0]", + "src": "b", + "srcArrow": "none", + "srcLabel": "", + "dst": "c", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1979.5, + "y": 337 + }, + { + "x": 1979.5, + "y": 377 + }, + { + "x": 1979.5, + "y": 397 + }, + { + "x": 1979.5, + "y": 437 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(c -> d)[0]", + "src": "c", + "srcArrow": "none", + "srcLabel": "", + "dst": "d", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1979.5, + "y": 503 + }, + { + "x": 1979.5, + "y": 543 + }, + { + "x": 1979.5, + "y": 563 + }, + { + "x": 1979.5, + "y": 603 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(d -> e)[0]", + "src": "d", + "srcArrow": "none", + "srcLabel": "", + "dst": "e", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1979.5, + "y": 703 + }, + { + "x": 1979.5, + "y": 743 + }, + { + "x": 1979.5, + "y": 763 + }, + { + "x": 1979.5, + "y": 803 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(e -> f)[0]", + "src": "e", + "srcArrow": "none", + "srcLabel": "", + "dst": "f", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1979.5, + "y": 869 + }, + { + "x": 1979.5, + "y": 909 + }, + { + "x": 1979.5, + "y": 929 + }, + { + "x": 1979.5, + "y": 969 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/unicode/japanese-mixed/dagre/sketch.exp.svg b/e2etests/testdata/unicode/japanese-mixed/dagre/sketch.exp.svg new file mode 100644 index 000000000..77274b84b --- /dev/null +++ b/e2etests/testdata/unicode/japanese-mixed/dagre/sketch.exp.svg @@ -0,0 +1,52 @@ + +ใƒˆใƒžใƒˆใŒ่ตคใใชใฃใŸใฎใฏใชใœใงใ™ใ‹๏ผŸBecause it saw the salad dressing!๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถใƒˆใƒžใƒˆใŒ่ตคใใชใฃใŸใฎใฏใชใœใงใ™ใ‹๏ผŸBecause it saw the salad dressing!๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถไปŠๆ—ฅใฏTokyoใงsushiใ‚’้ฃŸในใพใ—ใŸๅ…ˆๆ—ฅใ€Shibuyaใงๅ‹้”ใจshoppingใ‚’ๆฅฝ๐Ÿ˜Šใ—ใ‚“ใ ๅพŒใ€ramenๅฑ‹ใงdelicious๐Ÿ˜Šใชใƒฉใƒผใƒกใƒณใ‚’้ฃŸในใŸใ€‚English English Englishๅ…ˆๆ—ฅๅ…ˆๆ—ฅๅ…ˆๆ—ฅ + + + \ No newline at end of file diff --git a/e2etests/testdata/unicode/japanese-mixed/elk/board.exp.json b/e2etests/testdata/unicode/japanese-mixed/elk/board.exp.json new file mode 100644 index 000000000..622db44fb --- /dev/null +++ b/e2etests/testdata/unicode/japanese-mixed/elk/board.exp.json @@ -0,0 +1,449 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "rectangle", + "pos": { + "x": 1657, + "y": 12 + }, + "width": 668, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ใƒˆใƒžใƒˆใŒ่ตคใใชใฃใŸใฎใฏใชใœใงใ™ใ‹๏ผŸBecause it saw the salad dressing!๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 623, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "rectangle", + "pos": { + "x": 12, + "y": 148 + }, + "width": 3959, + "height": 171, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ใƒˆใƒžใƒˆใŒ่ตคใใชใฃใŸใฎใฏใชใœใงใ™ใ‹๏ผŸBecause it saw the salad dressing!๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ", + "fontSize": 100, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 3914, + "labelHeight": 126, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "c", + "type": "rectangle", + "pos": { + "x": 1828, + "y": 389 + }, + "width": 326, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ไปŠๆ—ฅใฏTokyoใงsushiใ‚’้ฃŸในใพใ—ใŸ", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 281, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "d", + "type": "rectangle", + "pos": { + "x": 899, + "y": 525 + }, + "width": 2184, + "height": 100, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ๅ…ˆๆ—ฅใ€Shibuyaใงๅ‹้”ใจshoppingใ‚’ๆฅฝ๐Ÿ˜Šใ—ใ‚“ใ ๅพŒใ€ramenๅฑ‹ใงdelicious๐Ÿ˜Šใชใƒฉใƒผใƒกใƒณใ‚’้ฃŸในใŸใ€‚", + "fontSize": 43, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 2139, + "labelHeight": 55, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "e", + "type": "rectangle", + "pos": { + "x": 1888, + "y": 695 + }, + "width": 206, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "English English English", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 161, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "f", + "type": "rectangle", + "pos": { + "x": 1909, + "y": 831 + }, + "width": 165, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ๅ…ˆๆ—ฅๅ…ˆๆ—ฅๅ…ˆๆ—ฅ", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 120, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a -> b)[0]", + "src": "a", + "srcArrow": "none", + "srcLabel": "", + "dst": "b", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1991.5, + "y": 78 + }, + { + "x": 1991.5, + "y": 148 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(b -> c)[0]", + "src": "b", + "srcArrow": "none", + "srcLabel": "", + "dst": "c", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1991.5, + "y": 319 + }, + { + "x": 1991.5, + "y": 389 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(c -> d)[0]", + "src": "c", + "srcArrow": "none", + "srcLabel": "", + "dst": "d", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1991.5, + "y": 455 + }, + { + "x": 1991.5, + "y": 525 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(d -> e)[0]", + "src": "d", + "srcArrow": "none", + "srcLabel": "", + "dst": "e", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1991.5, + "y": 625 + }, + { + "x": 1991.5, + "y": 695 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(e -> f)[0]", + "src": "e", + "srcArrow": "none", + "srcLabel": "", + "dst": "f", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1991.5, + "y": 761 + }, + { + "x": 1991.5, + "y": 831 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/unicode/japanese-mixed/elk/sketch.exp.svg b/e2etests/testdata/unicode/japanese-mixed/elk/sketch.exp.svg new file mode 100644 index 000000000..6edeb9aa3 --- /dev/null +++ b/e2etests/testdata/unicode/japanese-mixed/elk/sketch.exp.svg @@ -0,0 +1,52 @@ + +ใƒˆใƒžใƒˆใŒ่ตคใใชใฃใŸใฎใฏใชใœใงใ™ใ‹๏ผŸBecause it saw the salad dressing!๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถใƒˆใƒžใƒˆใŒ่ตคใใชใฃใŸใฎใฏใชใœใงใ™ใ‹๏ผŸBecause it saw the salad dressing!๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถไปŠๆ—ฅใฏTokyoใงsushiใ‚’้ฃŸในใพใ—ใŸๅ…ˆๆ—ฅใ€Shibuyaใงๅ‹้”ใจshoppingใ‚’ๆฅฝ๐Ÿ˜Šใ—ใ‚“ใ ๅพŒใ€ramenๅฑ‹ใงdelicious๐Ÿ˜Šใชใƒฉใƒผใƒกใƒณใ‚’้ฃŸในใŸใ€‚English English Englishๅ…ˆๆ—ฅๅ…ˆๆ—ฅๅ…ˆๆ—ฅ + + + \ No newline at end of file diff --git a/e2etests/testdata/unicode/with-style/dagre/board.exp.json b/e2etests/testdata/unicode/with-style/dagre/board.exp.json new file mode 100644 index 000000000..475a72efb --- /dev/null +++ b/e2etests/testdata/unicode/with-style/dagre/board.exp.json @@ -0,0 +1,48 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "ใŠใ‚„ใ™ใฟใชใ•ใ„", + "type": "rectangle", + "pos": { + "x": 0, + "y": 0 + }, + "width": 185, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 15, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": true, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ใŠใ‚„ใ™ใฟใชใ•ใ„", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 140, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/unicode/with-style/dagre/sketch.exp.svg b/e2etests/testdata/unicode/with-style/dagre/sketch.exp.svg new file mode 100644 index 000000000..64a18001c --- /dev/null +++ b/e2etests/testdata/unicode/with-style/dagre/sketch.exp.svg @@ -0,0 +1,52 @@ + +ใŠใ‚„ใ™ใฟใชใ•ใ„ + + + \ No newline at end of file diff --git a/e2etests/testdata/unicode/with-style/elk/board.exp.json b/e2etests/testdata/unicode/with-style/elk/board.exp.json new file mode 100644 index 000000000..201320c67 --- /dev/null +++ b/e2etests/testdata/unicode/with-style/elk/board.exp.json @@ -0,0 +1,48 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "ใŠใ‚„ใ™ใฟใชใ•ใ„", + "type": "rectangle", + "pos": { + "x": 12, + "y": 12 + }, + "width": 185, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 15, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": true, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ใŠใ‚„ใ™ใฟใชใ•ใ„", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 140, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/unicode/with-style/elk/sketch.exp.svg b/e2etests/testdata/unicode/with-style/elk/sketch.exp.svg new file mode 100644 index 000000000..fa4d7d8a1 --- /dev/null +++ b/e2etests/testdata/unicode/with-style/elk/sketch.exp.svg @@ -0,0 +1,52 @@ + +ใŠใ‚„ใ™ใฟใชใ•ใ„ + + + \ No newline at end of file diff --git a/e2etests/unicode_test.go b/e2etests/unicode_test.go new file mode 100644 index 000000000..0629cdf09 --- /dev/null +++ b/e2etests/unicode_test.go @@ -0,0 +1,56 @@ +package e2etests + +import ( + _ "embed" + "testing" +) + +func testUnicode(t *testing.T) { + tcs := []testCase{ + { + name: "japanese-basic", + script: `a: ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ใ‚ +`, + }, + { + name: "japanese-full", + script: `a: "ใ‚ใ‚‹ๆ—ฅใ€ใƒˆใƒžใƒˆใŒ้“ใ‚’ๆญฉใ„ใฆใ„ใŸใ‚‰ใ€้“่ทฏใฎๅ‘ใ“ใ†ใ‹ใ‚‰ใ‚ญใƒฅใ‚ฆใƒชใŒใ‚„ใฃใฆๆฅใพใ—ใŸใ€‚\nใƒˆใƒžใƒˆใฏ้ฉšใ„ใฆๅฐ‹ใญใพใ—ใŸใ€‚\nใ€Œใ‚ญใƒฅใ‚ฆใƒชใ•ใ‚“ใ€ใฉใ†ใ—ใฆใ‚ใชใŸใฏใ“ใ“ใซใ„ใ‚‹ใฎใงใ™ใ‹๏ผŸใ€ ใ‚ญใƒฅใ‚ฆใƒชใฏ็ญ”ใˆใพใ—ใŸใ€‚ใ€Œใ‚ใชใŸใจๅŒใ˜็†็”ฑใงใ“ใ“ใซใ„ใพใ™ใ€‚ใ‚ตใƒฉใƒ€ใซใชใ‚‹ใŸใ‚ใซใ€‚ใ€" + +b: "ใ€ŒใƒใƒŠใƒŠใฏ็šฎใ‚’ๅ‰ฅใ„ใฆ้ฃŸในใ‚‹ใ‚‚ใฎใงใ™ใ€‚ใ€" { + style.font-size: 55 +} + +a -> b: ใ€Œใƒใ‚ซใฏๆญปใชใชใใ‚ƒๆฒปใ‚‰ใชใ„ใ€‚ใ€ +`, + }, + { + name: "emojis", + script: `a: ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ๐Ÿ™ˆ +โœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠโœŠ -> โ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธโ˜๏ธ +`, + }, + { + name: "with-style", + script: `ใŠใ‚„ใ™ใฟใชใ•ใ„: {style.stroke-width: 15; style.double-border: true} +`, + }, + { + name: "japanese-mixed", + script: `a: "ใƒˆใƒžใƒˆใŒ่ตคใใชใฃใŸใฎใฏใชใœใงใ™ใ‹๏ผŸBecause it saw the salad dressing!๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ" +b: "ใƒˆใƒžใƒˆใŒ่ตคใใชใฃใŸใฎใฏใชใœใงใ™ใ‹๏ผŸBecause it saw the salad dressing!๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ถ" { + style.font-size: 100 +} +c: ไปŠๆ—ฅใฏTokyoใงsushiใ‚’้ฃŸในใพใ—ใŸ +d: ๅ…ˆๆ—ฅใ€Shibuyaใงๅ‹้”ใจshoppingใ‚’ๆฅฝ๐Ÿ˜Šใ—ใ‚“ใ ๅพŒใ€ramenๅฑ‹ใงdelicious๐Ÿ˜Šใชใƒฉใƒผใƒกใƒณใ‚’้ฃŸในใŸใ€‚{ + style.font-size: 43 +} +e: English English English +f: ๅ…ˆๆ—ฅๅ…ˆๆ—ฅๅ…ˆๆ—ฅ +a -> b -> c -> d -> e -> f + +`, + }, + } + + runa(t, tcs) +} diff --git a/go.mod b/go.mod index feec9b43c..c8986bd2f 100644 --- a/go.mod +++ b/go.mod @@ -10,8 +10,10 @@ require ( github.com/fsnotify/fsnotify v1.6.0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/lucasb-eyer/go-colorful v1.2.0 + github.com/mattn/go-runewidth v0.0.14 github.com/mazznoer/csscolorparser v0.1.3 github.com/playwright-community/playwright-go v0.2000.1 + github.com/rivo/uniseg v0.4.3 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.1 github.com/yuin/goldmark v1.5.3 diff --git a/go.sum b/go.sum index 1f31c5679..9b83338c3 100644 --- a/go.sum +++ b/go.sum @@ -115,6 +115,8 @@ github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mazznoer/csscolorparser v0.1.3 h1:vug4zh6loQxAUxfU1DZEu70gTPufDPspamZlHAkKcxE= github.com/mazznoer/csscolorparser v0.1.3/go.mod h1:Aj22+L/rYN/Y6bj3bYqO3N6g1dtdHtGfQ32xZ5PJQic= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= @@ -128,6 +130,10 @@ github.com/playwright-community/playwright-go v0.2000.1/go.mod h1:1y9cM9b9dVHnuR github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= +github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= diff --git a/lib/textmeasure/textmeasure.go b/lib/textmeasure/textmeasure.go index b46cc1711..cdf9c811c 100644 --- a/lib/textmeasure/textmeasure.go +++ b/lib/textmeasure/textmeasure.go @@ -5,10 +5,12 @@ package textmeasure import ( "math" + "strings" "unicode" "unicode/utf8" "github.com/golang/freetype/truetype" + "github.com/rivo/uniseg" "oss.terrastruct.com/d2/d2renderers/d2fonts" "oss.terrastruct.com/d2/lib/geo" @@ -166,6 +168,44 @@ func (r *Ruler) addFontSize(font d2fonts.Font) { func (t *Ruler) Measure(font d2fonts.Font, s string) (width, height int) { w, h := t.MeasurePrecise(font, s) + // Weird unicode stuff is going on when this is true + // See https://github.com/rivo/uniseg#grapheme-clusters + // This method is a good-enough approximation. It overshoots, but not by much. + // I suspect we need to import a font with the right glyphs to get the precise measurements + // but Hans fonts are heavy. + if uniseg.GraphemeClusterCount(s) != len(s) { + for _, line := range strings.Split(s, "\n") { + lineW, _ := t.MeasurePrecise(font, line) + gr := uniseg.NewGraphemes(line) + + mono := d2fonts.SourceCodePro.Font(font.Size, font.Style) + for gr.Next() { + if gr.Width() == 1 { + continue + } + // For each grapheme which doesn't have width=1, the ruler measured wrongly. + // So, replace the measured width with a scaled measurement of a monospace version + var prevRune rune + dot := t.Orig.Copy() + b := newRect() + for _, r := range gr.Runes() { + var control bool + dot, control = t.controlRune(r, dot, font) + if control { + continue + } + + var bounds *rect + _, _, bounds, dot = t.atlases[font].DrawRune(prevRune, r, dot) + b = b.union(bounds) + prevRune = r + } + lineW -= b.w() + lineW += t.spaceWidth(mono) * float64(gr.Width()) + } + w = math.Max(w, lineW) + } + } return int(math.Ceil(w)), int(math.Ceil(h)) }