github.com/jmigpin/editor@v1.6.0/util/drawutil/drawer4/runereader.go (about) 1 package drawer4 2 3 import ( 4 "image" 5 "io" 6 7 "github.com/jmigpin/editor/util/iout/iorw" 8 "github.com/jmigpin/editor/util/mathutil" 9 ) 10 11 type RuneReader struct { 12 d *Drawer 13 } 14 15 func (rr *RuneReader) Init() { 16 rr.d.st.runeR.fface = rr.d.fface 17 rr.d.st.runeR.pen = rr.startingPen() 18 rr.d.st.runeR.startRi = -1 19 } 20 21 func (rr *RuneReader) Iter() { 22 // initialize start ri 23 if rr.d.st.runeR.startRi == -1 { 24 rr.d.st.runeR.startRi = rr.d.st.runeR.ri 25 } 26 27 ru, size, err := iorw.ReadRuneAt(rr.d.reader, rr.d.st.runeR.ri) 28 if err != nil { 29 // run last advanced position (draw/delayeddraw/selecting) 30 if err == io.EOF { 31 _ = rr.iter2(eofRune, 0) 32 } 33 rr.d.iterStop() 34 return 35 } 36 _ = rr.iter2(ru, size) 37 } 38 39 func (rr *RuneReader) End() {} 40 41 //---------- 42 43 func (rr *RuneReader) eof() bool { 44 return rr.isNormal() && rr.d.st.runeR.ru == 0 45 } 46 47 func (rr *RuneReader) iter2(ru rune, size int) bool { 48 st := &rr.d.st.runeR 49 st.ru = ru 50 51 // add/subtract kern with previous rune 52 k := rr.d.st.runeR.fface.Face.Kern(st.prevRu, st.ru) 53 st.kern = mathutil.Intf2(k) 54 st.pen.X += st.kern 55 56 st.advance = rr.tabbedGlyphAdvance(st.ru) 57 58 if !rr.d.iterNext() { 59 return false 60 } 61 62 // advance for next rune 63 st.ri += size 64 st.prevRu = st.ru 65 st.pen.X += st.advance 66 67 return true 68 } 69 70 //---------- 71 72 func (rr *RuneReader) insertExtraString(s string) bool { 73 rr.pushExtra() 74 defer rr.popExtra() 75 76 for _, ru := range s { 77 if !rr.iter2(ru, len(string(ru))) { 78 return false 79 } 80 } 81 return true 82 } 83 84 //---------- 85 86 func (rr *RuneReader) pushExtra() { 87 rr.d.st.runeR.extra++ 88 } 89 func (rr *RuneReader) popExtra() { 90 rr.d.st.runeR.extra-- 91 } 92 func (rr *RuneReader) isExtra() bool { 93 return rr.d.st.runeR.extra > 0 94 } 95 func (rr *RuneReader) isNormal() bool { 96 return !rr.isExtra() 97 } 98 99 //---------- 100 101 func (rr *RuneReader) glyphAdvance(ru rune) mathutil.Intf { 102 adv, ok := rr.d.st.runeR.fface.Face.GlyphAdvance(ru) 103 if !ok { 104 return 0 105 } 106 return mathutil.Intf2(adv) 107 } 108 109 func (rr *RuneReader) tabbedGlyphAdvance(ru rune) mathutil.Intf { 110 adv := rr.glyphAdvance(ru) 111 if ru == '\t' { 112 adv = rr.nextTabStopAdvance(rr.d.st.runeR.pen.X, adv) 113 } 114 return adv 115 } 116 117 func (rr *RuneReader) nextTabStopAdvance(penx, tadv mathutil.Intf) mathutil.Intf { 118 px := penx - rr.startingPen().X 119 x := px + tadv 120 n := int(x / tadv) 121 nadv := mathutil.Intf(n) * tadv 122 return nadv - px 123 } 124 125 //---------- 126 127 func (rr *RuneReader) penBounds() mathutil.RectangleIntf { 128 st := &rr.d.st.runeR 129 minX, minY := st.pen.X, st.pen.Y 130 maxX, maxY := minX+st.advance, minY+rr.d.lineHeight 131 min := mathutil.PointIntf{minX, minY} 132 max := mathutil.PointIntf{maxX, maxY} 133 return mathutil.RectangleIntf{min, max} 134 } 135 136 func (rr *RuneReader) penBoundsRect() image.Rectangle { 137 pb := rr.penBounds() 138 // expand min (use floor), and max (use ceil) 139 return pb.ToRectFloorCeil() 140 } 141 142 //---------- 143 144 func (rr *RuneReader) startingPen() mathutil.PointIntf { 145 p := rr.d.bounds.Min 146 p.X += rr.d.Opt.RuneReader.StartOffsetX 147 if rr.d.st.runeR.ri == 0 { 148 p.X += rr.d.firstLineOffsetX 149 } 150 return mathutil.PIntf2(p) 151 } 152 153 func (rr *RuneReader) maxX() mathutil.Intf { 154 return mathutil.Intf1(rr.d.bounds.Max.X) 155 } 156 157 //---------- 158 159 type runeType int 160 161 const ( 162 rtNormal runeType = iota 163 rtBackground 164 rtInserted 165 //rtAnnotation 166 )