font/{gofont,opentype},text,widget{,/material}: [API] add font fallback and bidi support

This commit restructures the entire text shaping stack to enable lines of shaped text to
have non-homogeneous properties like which font face they belong to and which direction
a segment of text is going.

The text package now provides a concrete type text.Shaper which can be used to convert
strings into sequences of renderable text.Glyphs. At a high level, the API is used
like this:

    // Prepare some fonts.
    var collection []text.FontFace
    // Make a shaper with those fonts loaded.
    shaper := text.NewShaper(collection)
    // Shape a string.
    shaper.LayoutString(text.Parameters{
		PxPerEm: fixed.I(12),
    }, 0, 100, system.Locale{}, "Hello")
    // Iterate the glyphs from that string.
    for glyph, ok := shaper.NextGlyph(); ok; glyph, ok = shaper.NextGlyph() {
    	// Convert the glyph data into a path. In real uses, convert batches of glyphs
    	// rather than single glyphs to reduce the number of individual paths and offsets
    	// required to display your text.
    	shape := shaper.Shape([]text.Glyph{glyph})
    	// Offset the glyph to the position it declares within its fields. This will
    	// automatically handle correct bidirectional text glyph positioning.
    	offset := op.Offset(image.Pt(glyph.X.Floor(), int(glyph.Y))).Push(gtx.Ops)
    	// Create a clip area from the shape of the glyph.
    	area := clip.Outline{Path: shape}.Push(gtx.Ops)
    	// Paint whatever the current color is within the glyph's shape.
    	paint.PaintOp{}.Add(gtx.Ops)
    	area.Pop()
        offset.Pop()
    }

This API will transparently handle both font fallback (choosing appropriate fonts
from those loaded when the primary font doesn't contain a required glyph) and
bidirectional text (mixed left-to-right and right-to-left text). Glyphs are
iterated in order of the input runes, not their visual order, but proper use
of the provided offsets will ensure that text always displays correctly.

Thanks to Elias Naur for suggesting this glyph iterator strategy. It let us cut
through a lot of accumulated complexity from trying to match our old text APIs,
meaning that this change actually is a net negative change in lines of code.

This commit consumes the upstream github.com/go-text/typesetting/shaping API
now that my prior work is merged there, removing the need for the font/opentype/internal
package entirely.

As part of my efforts, I fuzzed both the low-level text shaping stack and the
editor widget extensively. I've committed regression tests found that way into
the appropriate testdata files to ensure the fuzzer re-checks them.

Fixes: https://todo.sr.ht/~eliasnaur/gio/425
Fixes: https://todo.sr.ht/~eliasnaur/gio/211
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit is contained in:
Chris Waldon
2022-10-10 16:44:22 -04:00
committed by Elias Naur
parent 513250122c
commit b7d126e24c
43 changed files with 3523 additions and 3980 deletions
@@ -0,0 +1,4 @@
go test fuzz v1
string("\xa3\xd90")
int16(-11)
int16(2237)
@@ -0,0 +1,4 @@
go test fuzz v1
string("")
int16(44)
int16(2299)
@@ -0,0 +1,4 @@
go test fuzz v1
string("و سأعر مثpل dolor sitamet, لم يتحم ج د adipscin eit, seddo الحصول علىpمhزة nرidiإun utNlaboe أ يتد magna aliqua.\nPorotit.r رادتهم فيتسوي rbi non aنcuيدكن ما يعقبها .\nNibhiنشجب ورستنكر ommodo nulla\nبكل سهولة ورونة ut consquat لهذا، من من .nam liber jظsto.يRisعs n hمndrerit لينا اضواجبالعمل.نNatoqe تكون Lدتا علي magis disparturient يخسك زمم الأمور ويخرار.\nIn جد ما يsنعنeu أcelerisquecونرا للاتزامات التي ةer entum.إMattis شرط وعندما لا neلue viverra.\nيمسكrزام الأمور abaan لهذر، .\nNisl تي يفض ا علينانfaucًbus ،من منا rm nec.\nSedكauue rلي الاختيار غر vitacongue eu nsequat.\nAt quis risus ك زمام الأمخر ومتا.tSit amet volutpat conseqt maسrisالأمو يiتارثإما nisi.\nDiguissim واجبوالعdل tincidunt نتنمزل feugiatn\nFauلibus التزاماتin eu m bإbendum.رOdio وcخرار إما أن ير صاسر السعادة ned adpiscig ذا، منeنا لم tistiue.\nFeretum leo vel ور ويختور ما pulvi\nr\nUtرإما أ يرفض صادر الmعادة من in metus تlون قدرتوايعليقgىelis imeodلet.\nي التتgر غي مقيدةمبشر et mنمsuada iamمs acنturpis.\nVennatis عل ميزة أو فائدة؟ ولكن oege nuc scele pque سزام ولأمو ويختار ما in.\nرتنا ultricieوtristique ي لااتيار غير قيدة بشرط enim trtor.\nRisus اختيiر غير قيدةeشط عندما quam سان الحكيم عليه أن .suspedsse in.Interمm vاlit نظرا للالتزام التي pellentesue massa pعaceiat ل مرضويتار إما أن يرفض acus.nProin دا تكون قدرتنا علي الاختيار lec us a.\nAuqtor الوقم عيدا تون aegue neque مال q fermentm et.\nطمeet ماك زام الأمور uيختار يmet cursuم لم يتحملجهدو نictum.uIn\nfermetum et sollicitudin ac orci nhبsellus علo الاخت.ا غ rutrum\nTemus mperdietلالمفترض أن.نفرق pellentesque ت بك سهو ة eget raidaم\nرonsequat id prvaمصادا السادة cras ned.\nVlputat رعلي الاختيارغير قيدة sitاamet aliquam\nmongue mauis حيمن ونظراً للالتزاnات التي elelit.\nRgsus qeis vهrius اuam quisque id ار غير قدة بشرط elementumوPreti m تي يفرضهاعuينا الاجب io in vitee.\n شاق إلا مب أل retium qua احكيم عليه أنsيمسك suspendss in et.Vlit ونظراً للالتزامات التي يفرض ultrice .\n الوقت عندما تكون velit dinissim يه ن يمس .\nرnc sclerisque vverramauris inلaliquam sim ً إا أن ut.\nالسعادt ك أجل مl هو أكثر أهمية أو يتحل الألم\nConvillis pفsuere morbi leo una molestie at.")
int16(613)
int16(1976)
@@ -0,0 +1,4 @@
go test fuzz v1
string("د عرمثال dstي met لم aqل جدmوpمg lرe dرd لو عل ميrةsdiduntut lab renنيتذدagلaaiua.ئPocttأior رادرsاي mيrbلmnonaيdتد ماةعcلخ\nد بوولنكcmme ul\nبsسة uولnوuoeaهnا،من mن tn libeo jtsteاisusهin hen عnنادmب eلعملNaلeسكنعقرنا علي ااs diلre rinti مسl زي.pلrور و \nار.تn ندمم نا e sc\nlلrsueونً Tالت mاL التمeزe.\nMaيit e و وكدمl مfeierta.\nمسmزامhالر قhi tnoلهاموoرNu تrFر ع ي اauipus ،i نالمneauemiاm علنتنارغيرvitas au c n eqnt.\nAtuسuخ sبمام grأور ختaغ.\n mee v utهateس e alاmis\nأمأاكيخاار إماsi.igmi واجب ا rتnتunt iنتنزiueلia.ضةaucb التتا n eu mi رمndكOd ايي. اإهنيرe مدرلخ اد sd ndiاun ذ من مالe triلu.iقmcnoui أo وaوياوإ.pulvinar.\nrت إماأ يرف مصSاfعدمنiو مts iن ورتنم eliاieيرt.\nي ا شغرحميمبط ettlsuda apeاsa turqe.Veneتtisiع ميةوأو sة؟ كن eرncaيliuatم امnر ايتارإga uemاutrci biqu ً.لiيار ي مlي لطen اtو or\nRssخياoغيراميe شmcصناو uaيويمعله دس su.endiRseini\nnrاie\nt نرللسنز يات لتي pelqe iact لأمو را تريض macsmPoاا ا نأSدتن امدrت م lntuا u.\nAuatr سيتiياtجون ut nequ ضيى eo seض etumثtجaoee مسl tم.مuأيت وmt crrsغ c sمs اdictn.I أ,entrm Doiiludin c iaseleusيعلالختيررر rutrmmيmp mprieh فeرةa ن dف\nesمeldمsue يdكل امrخd egt i a eu.uCs uaن drtaمشدر لعدةشrنeظ\nVlpuatrعي pختيارهmرcمقيoةit am t اleua.\n ongulmaقisين.نnرل لللتز لتي م.\niousqui varNs اeل uiue ld uريحميcن برeneeum\nPrtزm يفرضا عاالاجب ن sيeشدelممن جل prstiتiqu rا\nحكlم ل ها،نك uspe duse اn ًaنeliت ً رازv لتي رفfيىutلise lsق oدمتكونيvelidgsدc tvle sNe أscاplsqنeمvشساtuتsرin aliqطi e ر إمدأنةقut لع ن أجuلما ه vرمة tصتحماللم\nConveli posمeل er leرr mلee .")
int16(1228)
int16(782)