Diff
diff --git a/docs/font/index.html b/docs/font/index.html
index b50273d..7be1b38 100644
--- a/docs/font/index.html
+++ b/docs/font/index.html
@@ -60,138 +60,138 @@
- 12 "runtime"
- 13 "sort"
- 14 "strconv"
- 15 "strings"
- 16
- 17 "github.com/golang/freetype/truetype"
- 18 "golang.org/x/image/font"
- 19 "golang.org/x/image/math/fixed"
- 20)
- 21
- 22// LoadSystemFont loads a font from the system fonts directory or loads a specific font by name
- 23func GetFontPath(fontName string, bold, italic bool) string {
- 24
- 25 if len(fontName) == 0 {
- 26 fontName = "serif"
- 27 }
- 28
- 29 // Check if a special font family is requested
- 30 switch fontName {
- 31 case "sans-serif":
- 32 return tryLoadSystemFont("Arial", bold, italic)
- 33 case "monospace":
- 34 return tryLoadSystemFont("Andle Mono", bold, italic)
- 35 case "serif":
- 36 return tryLoadSystemFont("Georgia", bold, italic)
- 37 }
- 38
- 39 // Use the default font if the specified font is not found
- 40 return tryLoadSystemFont(fontName, bold, italic)
- 41}
- 42
- 43var allFonts, _ = getSystemFonts()
- 44
- 45func tryLoadSystemFont(fontName string, bold, italic bool) string {
- 46 font := fontName
- 47 if bold {
- 48 font += " Bold"
- 49 }
- 50 if italic {
- 51 font += " Italic"
- 52 }
- 53 for _, v := range allFonts {
- 54 if strings.Contains(v, "/"+font) {
- 55 return v
- 56 }
- 57 }
- 58
- 59 return ""
- 60}
- 61
- 62func sortByLength(strings []string) {
- 63 sort.Slice(strings, func(i, j int) bool {
- 64 return len(strings[i]) < len(strings[j])
- 65 })
- 66}
- 67
- 68func GetFontSize(css map[string]string) float32 {
- 69 fL := len(css["font-size"])
- 70
- 71 var fs float32 = 16
- 72
- 73 if fL > 0 {
- 74 if css["font-size"][fL-2:] == "px" {
- 75 fs64, _ := strconv.ParseFloat(css["font-size"][0:fL-2], 32)
- 76 fs = float32(fs64)
- 77 }
- 78 if css["font-size"][fL-2:] == "em" {
- 79 fs64, _ := strconv.ParseFloat(css["font-size"][0:fL-2], 32)
- 80 fs = float32(fs64)
- 81 }
- 82 }
- 83
- 84 return fs
- 85}
- 86
- 87func LoadFont(fontName string, fontSize int, bold, italic bool) (font.Face, error) {
- 88 // Use a TrueType font file for the specified font name
- 89 fontFile := GetFontPath(fontName, bold, italic)
- 90
- 91 // Read the font file
- 92 fontData, err := os.ReadFile(fontFile)
- 93 if err != nil {
- 94 return nil, err
- 95 }
- 96
- 97 // Parse the TrueType font data
- 98 fnt, err := truetype.Parse(fontData)
- 99 if err != nil {
-100 return nil, err
-101 }
-102
-103 options := truetype.Options{
-104 Size: float64(fontSize),
-105 DPI: 72,
-106 Hinting: font.HintingNone,
-107 }
-108
-109 // Create a new font face with the specified size
-110 return truetype.NewFace(fnt, &options), nil
-111}
-112
-113func MeasureText(s *element.State, text string) int {
-114 t := s.Text
-115 var width fixed.Int26_6
-116
-117 for _, runeValue := range text {
-118 if runeValue == ' ' {
-119 // Handle spaces separately, add word spacing
-120 width += fixed.I(t.WordSpacing)
-121 } else {
-122 adv, ok := t.Font.GlyphAdvance(runeValue)
-123 if !ok {
-124 continue
-125 }
-126
-127 // Update the total width with the glyph advance and bounds
-128 width += adv + fixed.I(t.LetterSpacing)
-129 }
-130 }
-131
-132 return width.Round()
-133}
-134
-135func getSystemFonts() ([]string, error) {
-136 var fontPaths []string
-137
-138 switch runtime.GOOS {
-139 case "windows":
-140 fontPaths = append(fontPaths, getWindowsFontPaths()...)
-141 case "darwin":
-142 fontPaths = append(fontPaths, getMacFontPaths()...)
-143 case "linux":
-144 fontPaths = append(fontPaths, getLinuxFontPaths()...)
-145 default:
-146 return nil, fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
-147 }
-148
-149 sortByLength(fontPaths)
+ 12 "regexp"
+ 13 "runtime"
+ 14 "sort"
+ 15 "strconv"
+ 16 "strings"
+ 17
+ 18 "github.com/golang/freetype/truetype"
+ 19 "golang.org/x/image/font"
+ 20 "golang.org/x/image/math/fixed"
+ 21)
+ 22
+ 23// LoadSystemFont loads a font from the system fonts directory or loads a specific font by name
+ 24func GetFontPath(fontName string, bold, italic bool) string {
+ 25
+ 26 if len(fontName) == 0 {
+ 27 fontName = "serif"
+ 28 }
+ 29
+ 30 // Check if a special font family is requested
+ 31 switch fontName {
+ 32 case "sans-serif":
+ 33 return tryLoadSystemFont("Arial", bold, italic)
+ 34 case "monospace":
+ 35 return tryLoadSystemFont("Andle Mono", bold, italic)
+ 36 case "serif":
+ 37 return tryLoadSystemFont("Georgia", bold, italic)
+ 38 }
+ 39
+ 40 // Use the default font if the specified font is not found
+ 41 return tryLoadSystemFont(fontName, bold, italic)
+ 42}
+ 43
+ 44var allFonts, _ = getSystemFonts()
+ 45
+ 46func tryLoadSystemFont(fontName string, bold, italic bool) string {
+ 47 font := fontName
+ 48 if bold {
+ 49 font += " Bold"
+ 50 }
+ 51 if italic {
+ 52 font += " Italic"
+ 53 }
+ 54 for _, v := range allFonts {
+ 55 if strings.Contains(v, "/"+font) {
+ 56 return v
+ 57 }
+ 58 }
+ 59
+ 60 return ""
+ 61}
+ 62
+ 63func sortByLength(strings []string) {
+ 64 sort.Slice(strings, func(i, j int) bool {
+ 65 return len(strings[i]) < len(strings[j])
+ 66 })
+ 67}
+ 68
+ 69func GetFontSize(css map[string]string) float32 {
+ 70 fL := len(css["font-size"])
+ 71
+ 72 var fs float32 = 16
+ 73
+ 74 if fL > 0 {
+ 75 if css["font-size"][fL-2:] == "px" {
+ 76 fs64, _ := strconv.ParseFloat(css["font-size"][0:fL-2], 32)
+ 77 fs = float32(fs64)
+ 78 }
+ 79 if css["font-size"][fL-2:] == "em" {
+ 80 fs64, _ := strconv.ParseFloat(css["font-size"][0:fL-2], 32)
+ 81 fs = float32(fs64)
+ 82 }
+ 83 }
+ 84
+ 85 return fs
+ 86}
+ 87
+ 88func LoadFont(fontName string, fontSize int, bold, italic bool) (font.Face, error) {
+ 89 // Use a TrueType font file for the specified font name
+ 90 fontFile := GetFontPath(fontName, bold, italic)
+ 91
+ 92 // Read the font file
+ 93 fontData, err := os.ReadFile(fontFile)
+ 94 if err != nil {
+ 95 return nil, err
+ 96 }
+ 97
+ 98 // Parse the TrueType font data
+ 99 fnt, err := truetype.Parse(fontData)
+100 if err != nil {
+101 return nil, err
+102 }
+103
+104 options := truetype.Options{
+105 Size: float64(fontSize),
+106 DPI: 72,
+107 Hinting: font.HintingNone,
+108 }
+109
+110 // Create a new font face with the specified size
+111 return truetype.NewFace(fnt, &options), nil
+112}
+113
+114// func MeasureLine(n *element.Node, state *element.State) (int, int) {
+115// passed := false
+116// lineOffset, nodeOffset := 0, 0
+117// for _, v := range n.Parent.Children {
+118// l := MeasureText(state, v.InnerText)
+119// if v.Properties.Id == n.Properties.Id {
+120// passed = true
+121// lineOffset += l
+122// } else {
+123// if !passed {
+124// nodeOffset += l
+125// }
+126// lineOffset += l
+127// }
+128// }
+129// return lineOffset, nodeOffset
+130// }
+131
+132func MeasureText(s *element.State, text string) int {
+133 t := s.Text
+134 var width fixed.Int26_6
+135
+136 for _, runeValue := range text {
+137 if runeValue == ' ' {
+138 // Handle spaces separately, add word spacing
+139 width += fixed.I(t.WordSpacing)
+140 } else {
+141 adv, ok := t.Font.GlyphAdvance(runeValue)
+142 if !ok {
+143 continue
+144 }
+145
+146 // Update the total width with the glyph advance and bounds
+147 width += adv + fixed.I(t.LetterSpacing)
+148 }
+149 }
@@ -199 +199 @@
-151 return fontPaths, nil
+151 return width.Round()
@@ -202,22 +202,22 @@
-154func getWindowsFontPaths() []string {
-155 var fontPaths []string
-156
-157 // System Fonts
-158 systemFontsDir := "C:\\Windows\\Fonts"
-159 getFontsRecursively(systemFontsDir, &fontPaths)
-160
-161 // User Fonts
-162 userFontsDir := os.ExpandEnv("%APPDATA%\\Microsoft\\Windows\\Fonts")
-163 getFontsRecursively(userFontsDir, &fontPaths)
-164
-165 return fontPaths
-166}
-167
-168func getMacFontPaths() []string {
-169 var fontPaths []string
-170
-171 // System Fonts
-172 systemFontsDirs := []string{"/System/Library/Fonts", "/Library/Fonts"}
-173 for _, dir := range systemFontsDirs {
-174 getFontsRecursively(dir, &fontPaths)
-175 }
+154func MeasureSpace(t *element.Text) int {
+155 adv, _ := t.Font.GlyphAdvance(' ')
+156 return adv.Round()
+157}
+158
+159func MeasureLongest(s *element.State) int {
+160 lines := getLines(s)
+161 var longestLine string
+162 maxLength := 0
+163
+164 for _, line := range lines {
+165 length := len(line)
+166 if length > maxLength {
+167 maxLength = length
+168 longestLine = line
+169 }
+170 }
+171 return MeasureText(s, longestLine)
+172}
+173
+174func getSystemFonts() ([]string, error) {
+175 var fontPaths []string
@@ -225,15 +225,15 @@
-177 // User Fonts
-178 userFontsDir := filepath.Join(os.Getenv("HOME"), "Library/Fonts")
-179 getFontsRecursively(userFontsDir, &fontPaths)
-180
-181 return fontPaths
-182}
-183
-184func getLinuxFontPaths() []string {
-185 var fontPaths []string
-186
-187 // System Fonts
-188 systemFontsDirs := []string{"/usr/share/fonts", "/usr/local/share/fonts"}
-189 for _, dir := range systemFontsDirs {
-190 getFontsRecursively(dir, &fontPaths)
-191 }
+177 switch runtime.GOOS {
+178 case "windows":
+179 fontPaths = append(fontPaths, getWindowsFontPaths()...)
+180 case "darwin":
+181 fontPaths = append(fontPaths, getMacFontPaths()...)
+182 case "linux":
+183 fontPaths = append(fontPaths, getLinuxFontPaths()...)
+184 default:
+185 return nil, fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
+186 }
+187
+188 sortByLength(fontPaths)
+189
+190 return fontPaths, nil
+191}
@@ -241,6 +241,6 @@
-193 // User Fonts
-194 userFontsDir := filepath.Join(os.Getenv("HOME"), ".fonts")
-195 getFontsRecursively(userFontsDir, &fontPaths)
-196
-197 return fontPaths
-198}
+193func getWindowsFontPaths() []string {
+194 var fontPaths []string
+195
+196 // System Fonts
+197 systemFontsDir := "C:\\Windows\\Fonts"
+198 getFontsRecursively(systemFontsDir, &fontPaths)
@@ -248,6 +248,6 @@
-200func getFontsRecursively(dir string, fontPaths *[]string) {
-201 files, err := ioutil.ReadDir(dir)
-202 if err != nil {
-203 fmt.Println("Error reading directory:", err)
-204 return
-205 }
+200 // User Fonts
+201 userFontsDir := os.ExpandEnv("%APPDATA%\\Microsoft\\Windows\\Fonts")
+202 getFontsRecursively(userFontsDir, &fontPaths)
+203
+204 return fontPaths
+205}
@@ -255,7 +255,7 @@
-207 for _, file := range files {
-208 path := filepath.Join(dir, file.Name())
-209 if file.IsDir() {
-210 getFontsRecursively(path, fontPaths)
-211 } else if strings.HasSuffix(strings.ToLower(file.Name()), ".ttf") {
-212 *fontPaths = append(*fontPaths, path)
-213 }
+207func getMacFontPaths() []string {
+208 var fontPaths []string
+209
+210 // System Fonts
+211 systemFontsDirs := []string{"/System/Library/Fonts", "/Library/Fonts"}
+212 for _, dir := range systemFontsDirs {
+213 getFontsRecursively(dir, &fontPaths)
@@ -263,30 +263,30 @@
-215}
-216
-217func Render(s *element.State) (*image.RGBA, int) {
-218 t := &s.Text
-219 // fmt.Println(lines)
-220
-221 if t.LineHeight == 0 {
-222 t.LineHeight = t.EM + 3
-223 }
-224
-225 width := MeasureText(s, t.Text+" ")
-226
-227 // Use fully transparent color for the background
-228 img := image.NewRGBA(image.Rect(0, 0, width, t.LineHeight))
-229
-230 // fmt.Println(t.Width, t.LineHeight, (len(lines)))
-231
-232 r, g, b, a := t.Color.RGBA()
-233
-234 draw.Draw(img, img.Bounds(), &image.Uniform{color.RGBA{uint8(r), uint8(g), uint8(b), uint8(0)}}, image.Point{}, draw.Over)
-235 // fmt.Println(int(t.Font.Metrics().Ascent))
-236 dot := fixed.Point26_6{X: fixed.I(0), Y: (fixed.I(t.LineHeight+(t.EM/2)) / 2)}
-237
-238 dr := &font.Drawer{
-239 Dst: img,
-240 Src: &image.Uniform{color.RGBA{uint8(r), uint8(g), uint8(b), uint8(a)}},
-241 Face: t.Font,
-242 Dot: dot,
-243 }
-244 t.Image = img
+215
+216 // User Fonts
+217 userFontsDir := filepath.Join(os.Getenv("HOME"), "Library/Fonts")
+218 getFontsRecursively(userFontsDir, &fontPaths)
+219
+220 return fontPaths
+221}
+222
+223func getLinuxFontPaths() []string {
+224 var fontPaths []string
+225
+226 // System Fonts
+227 systemFontsDirs := []string{"/usr/share/fonts", "/usr/local/share/fonts"}
+228 for _, dir := range systemFontsDirs {
+229 getFontsRecursively(dir, &fontPaths)
+230 }
+231
+232 // User Fonts
+233 userFontsDir := filepath.Join(os.Getenv("HOME"), ".fonts")
+234 getFontsRecursively(userFontsDir, &fontPaths)
+235
+236 return fontPaths
+237}
+238
+239func getFontsRecursively(dir string, fontPaths *[]string) {
+240 files, err := ioutil.ReadDir(dir)
+241 if err != nil {
+242 fmt.Println("Error reading directory:", err)
+243 return
+244 }
@@ -294,20 +294,20 @@
-246 drawString(*t, dr, t.Text, width)
-247
-248 return t.Image, width
-249}
-250
-251func drawString(t element.Text, dr *font.Drawer, v string, lineWidth int) {
-252 underlinePosition := dr.Dot
-253 for _, ch := range v {
-254 if ch == ' ' {
-255 // Handle spaces separately, add word spacing
-256 dr.Dot.X += fixed.I(t.WordSpacing)
-257 } else {
-258 dr.DrawString(string(ch))
-259 dr.Dot.X += fixed.I(t.LetterSpacing)
-260 }
-261 }
-262 if t.Underlined || t.Overlined || t.LineThrough {
-263
-264 underlinePosition.X = 0
-265 baseLineY := underlinePosition.Y
+246 for _, file := range files {
+247 path := filepath.Join(dir, file.Name())
+248 if file.IsDir() {
+249 getFontsRecursively(path, fontPaths)
+250 } else if strings.HasSuffix(strings.ToLower(file.Name()), ".ttf") {
+251 *fontPaths = append(*fontPaths, path)
+252 }
+253 }
+254}
+255
+256func Render(s *element.State) float32 {
+257 t := &s.Text
+258 lines := getLines(s)
+259 // fmt.Println(lines)
+260
+261 if t.LineHeight == 0 {
+262 t.LineHeight = t.EM + 3
+263 }
+264 // Use fully transparent color for the background
+265 img := image.NewRGBA(image.Rect(0, 0, t.Width, t.LineHeight*(len(lines))))
@@ -315,50 +315,50 @@
-267 if t.Underlined {
-268 underlinePosition.Y = baseLineY + t.Font.Metrics().Descent
-269 drawLine(t.Image, underlinePosition, fixed.Int26_6(lineWidth), t.DecorationThickness, t.DecorationColor)
-270 }
-271 if t.LineThrough {
-272 underlinePosition.Y = baseLineY - (t.Font.Metrics().Descent)
-273 drawLine(t.Image, underlinePosition, fixed.Int26_6(lineWidth), t.DecorationThickness, t.DecorationColor)
-274 }
-275 if t.Overlined {
-276 underlinePosition.Y = baseLineY - t.Font.Metrics().Descent*3
-277 drawLine(t.Image, underlinePosition, fixed.Int26_6(lineWidth), t.DecorationThickness, t.DecorationColor)
-278 }
-279 }
-280}
-281
-282func drawLine(img draw.Image, start fixed.Point26_6, width fixed.Int26_6, thickness int, col color.Color) {
-283 // Bresenham's line algorithm
-284 x0, y0 := start.X.Round(), start.Y.Round()
-285 x1 := x0 + int(width)
-286 y1 := y0
-287 dx := abs(x1 - x0)
-288 dy := abs(y1 - y0)
-289 sx, sy := 1, 1
-290
-291 if x0 > x1 {
-292 sx = -1
-293 }
-294 if y0 > y1 {
-295 sy = -1
-296 }
-297
-298 err := dx - dy
-299
-300 for {
-301 for i := 0; i < thickness; i++ {
-302 img.Set(x0, (y0-(thickness/2))+i, col)
-303 }
-304
-305 if x0 == x1 && y0 == y1 {
-306 break
-307 }
-308
-309 e2 := 2 * err
-310 if e2 > -dy {
-311 err -= dy
-312 x0 += sx
-313 }
-314 if e2 < dx {
-315 err += dx
-316 y0 += sy
+267 // fmt.Println(t.Width, t.LineHeight, (len(lines)))
+268
+269 r, g, b, a := t.Color.RGBA()
+270
+271 draw.Draw(img, img.Bounds(), &image.Uniform{color.RGBA{uint8(r), uint8(g), uint8(b), uint8(0)}}, image.Point{}, draw.Over)
+272 // fmt.Println(int(t.Font.Metrics().Ascent))
+273 dot := fixed.Point26_6{X: fixed.I(0), Y: (fixed.I(t.LineHeight+(t.EM/2)) / 2)}
+274
+275 dr := &font.Drawer{
+276 Dst: img,
+277 Src: &image.Uniform{color.RGBA{uint8(r), uint8(g), uint8(b), uint8(a)}},
+278 Face: t.Font,
+279 Dot: dot,
+280 }
+281 t.Image = img
+282
+283 fh := fixed.I(t.LineHeight)
+284
+285 for _, v := range lines {
+286 lineWidth := MeasureText(s, v)
+287 if t.Align == "justify" {
+288 dr.Dot.X = 0
+289 spaces := strings.Count(v, " ")
+290 if spaces > 1 {
+291 spacing := fixed.I((t.Width - MeasureText(s, v)) / spaces)
+292
+293 if spacing > 0 {
+294 for _, word := range strings.Fields(v) {
+295 dr.DrawString(word)
+296 dr.Dot.X += spacing
+297 }
+298 } else {
+299 dr.Dot.X = 0
+300 drawString(*t, dr, v, lineWidth)
+301 }
+302 } else {
+303 dr.Dot.X = 0
+304 drawString(*t, dr, v, lineWidth)
+305 }
+306
+307 } else {
+308 if t.Align == "left" || t.Align == "" {
+309 dr.Dot.X = 0
+310 } else if t.Align == "center" {
+311 dr.Dot.X = fixed.I((t.Width - MeasureText(s, v)) / 2)
+312 } else if t.Align == "right" {
+313 dr.Dot.X = fixed.I(t.Width - MeasureText(s, v))
+314 }
+315 // dr.Dot.X = 0
+316 drawString(*t, dr, v, lineWidth)
@@ -366,17 +366,156 @@
-318 }
-319}
-320
-321func abs(x int) int {
-322 if x < 0 {
-323 return -x
-324 }
-325 return x
-326}
-327
-328func Min(a, b float32) float32 {
-329 if a < b {
-330 return a
-331 } else {
-332 return b
-333 }
-334}
+318 dr.Dot.Y += fh
+319 }
+320 s.Text.X = MeasureText(s, lines[len(lines)-1])
+321 return float32(t.LineHeight * len(lines))
+322}
+323
+324func drawString(t element.Text, dr *font.Drawer, v string, lineWidth int) {
+325 underlinePosition := dr.Dot
+326 for _, ch := range v {
+327 if ch == ' ' {
+328 // Handle spaces separately, add word spacing
+329 dr.Dot.X += fixed.I(t.WordSpacing)
+330 } else {
+331 dr.DrawString(string(ch))
+332 dr.Dot.X += fixed.I(t.LetterSpacing)
+333 }
+334 }
+335 if t.Underlined || t.Overlined || t.LineThrough {
+336
+337 underlinePosition.X = 0
+338 baseLineY := underlinePosition.Y
+339
+340 if t.Underlined {
+341 underlinePosition.Y = baseLineY + t.Font.Metrics().Descent
+342 drawLine(t.Image, underlinePosition, fixed.Int26_6(lineWidth), t.DecorationThickness, t.DecorationColor)
+343 }
+344 if t.LineThrough {
+345 underlinePosition.Y = baseLineY - (t.Font.Metrics().Descent)
+346 drawLine(t.Image, underlinePosition, fixed.Int26_6(lineWidth), t.DecorationThickness, t.DecorationColor)
+347 }
+348 if t.Overlined {
+349 underlinePosition.Y = baseLineY - t.Font.Metrics().Descent*3
+350 drawLine(t.Image, underlinePosition, fixed.Int26_6(lineWidth), t.DecorationThickness, t.DecorationColor)
+351 }
+352 }
+353}
+354
+355func drawLine(img draw.Image, start fixed.Point26_6, width fixed.Int26_6, thickness int, col color.Color) {
+356 // Bresenham's line algorithm
+357 x0, y0 := start.X.Round(), start.Y.Round()
+358 x1 := x0 + int(width)
+359 y1 := y0
+360 dx := abs(x1 - x0)
+361 dy := abs(y1 - y0)
+362 sx, sy := 1, 1
+363
+364 if x0 > x1 {
+365 sx = -1
+366 }
+367 if y0 > y1 {
+368 sy = -1
+369 }
+370
+371 err := dx - dy
+372
+373 for {
+374 for i := 0; i < thickness; i++ {
+375 img.Set(x0, (y0-(thickness/2))+i, col)
+376 }
+377
+378 if x0 == x1 && y0 == y1 {
+379 break
+380 }
+381
+382 e2 := 2 * err
+383 if e2 > -dy {
+384 err -= dy
+385 x0 += sx
+386 }
+387 if e2 < dx {
+388 err += dx
+389 y0 += sy
+390 }
+391 }
+392}
+393
+394func wrap(s *element.State, breaker string, breakNewLines bool) []string {
+395 var start int = 0
+396 strngs := []string{}
+397 var text []string
+398 broken := strings.Split(s.Text.Text, breaker)
+399 re := regexp.MustCompile(`[\r\n]+`)
+400 if breakNewLines {
+401 for _, v := range broken {
+402 text = append(text, re.Split(v, -1)...)
+403 }
+404 } else {
+405 text = append(text, broken...)
+406 }
+407 for i := 0; i < len(text); i++ {
+408 text[i] = re.ReplaceAllString(text[i], "")
+409 }
+410 for i := 0; i < len(text); i++ {
+411 seg := strings.Join(text[start:int(Min(float32(i+1), float32(len(text))))], breaker)
+412 if MeasureText(s, seg) > s.Text.Width {
+413 strngs = append(strngs, strings.Join(text[start:i], breaker))
+414 start = i
+415 }
+416 }
+417 if len(strngs) > 0 {
+418 strngs = append(strngs, strings.Join(text[start:], breaker))
+419 } else {
+420 strngs = append(strngs, strings.Join(text[start:], breaker))
+421 }
+422 return strngs
+423}
+424
+425func getLines(s *element.State) []string {
+426 t := s.Text
+427 text := s.Text.Text
+428 var lines []string
+429 if t.WhiteSpace == "nowrap" {
+430 re := regexp.MustCompile(`\s+`)
+431 s.Text.Text = re.ReplaceAllString(text, " ")
+432 lines = wrap(s, "<br />", false)
+433 } else {
+434 if t.WhiteSpace == "pre" {
+435 re := regexp.MustCompile("\t")
+436 s.Text.Text = re.ReplaceAllString(text, " ")
+437 nl := regexp.MustCompile(`[\r\n]+`)
+438 lines = nl.Split(text, -1)
+439 } else if t.WhiteSpace == "pre-line" {
+440 re := regexp.MustCompile(`\s+`)
+441 s.Text.Text = re.ReplaceAllString(text, " ")
+442 lines = wrap(s, " ", true)
+443 } else if t.WhiteSpace == "pre-wrap" {
+444 lines = wrap(s, " ", true)
+445 } else {
+446 re := regexp.MustCompile(`\s+`)
+447 s.Text.Text = re.ReplaceAllString(text, " ")
+448 nl := regexp.MustCompile(`[\r\n]+`)
+449 s.Text.Text = nl.ReplaceAllString(text, "")
+450 // n.InnerText = strings.TrimSpace(text)
+451 lines = wrap(s, t.WordBreak, false)
+452 }
+453 for i, v := range lines {
+454 lines[i] = v + t.WordBreak
+455 }
+456 }
+457 return lines
+458}
+459
+460func abs(x int) int {
+461 if x < 0 {
+462 return -x
+463 }
+464 return x
+465}
+466
+467func Min(a, b float32) float32 {
+468 if a < b {
+469 return a
+470 } else {
+471 return b
+472 }
+473}