shithub: opossum

Download patch

ref: 3ce4cfc9371c16b2ac4ac167668122fca13cc850
parent: 613e3bb3449b423ec3d96438f8b9a93aa58c731b
author: Philip Silva <philip.silva@protonmail.com>
date: Sun Dec 27 06:52:29 EST 2020

svg tag

--- a/browser/browser.go
+++ b/browser/browser.go
@@ -2,6 +2,7 @@
 
 import (
 	"9fans.net/go/draw"
+	"bytes"
 	"errors"
 	"fmt"
 	"golang.org/x/net/html"
@@ -133,17 +134,39 @@
 }
 
 func newImage(n *nodes.Node) (ui duit.UI, err error) {
+	var i *draw.Image
+	var cached bool
+	src := attr(*n.DomSubtree, "src")
+
 	if display == nil {
 		// probably called from a unit test
 		return nil, fmt.Errorf("display nil")
 	}
-	src := attr(*n.DomSubtree, "src")
+
+	if n.Data() == "svg" {
+		xml, err := n.Serialized()
+		if  err != nil {
+			return nil, fmt.Errorf("serialize: %w", err)
+		}
+		buf, err := img.Svg(xml, n.Width(), n.Height())
+		if err == nil {
+			var err error
+			r := bytes.NewReader(buf)
+			i, err = duit.ReadImage(display, r)
+			if err != nil {
+				return nil, fmt.Errorf("read image %v: %v", xml, err)
+			}
+			
+			goto img_elem
+		} else {
+			return nil, fmt.Errorf("img svg %v: %v", xml, err)
+		}
+	}
+
 	if src == "" {
 		return nil, fmt.Errorf("no src in %+v", n.Attrs)
 	}
 
-	var i *draw.Image
-	var cached bool
 	if i, cached = imageCache[src]; !cached {
 		r, err := img.Load(browser, src, n.Width(), n.Height())
 		if err != nil {
@@ -158,6 +181,7 @@
 		imageCache[src] = i
 	}
 
+img_elem:
 	return NewElement(
 		&Image{
 			Image: &duit.Image{
@@ -283,8 +307,8 @@
 
 	if v := attr(*n.DomSubtree, "value"); v != "" {
 		t = v
-	} else if nodes.IsPureTextContent(*n) {
-		t = strings.TrimSpace(nodes.ContentFrom(*n))
+	} else if c := strings.TrimSpace(nodes.ContentFrom(*n)); c != "" {
+		t = c
 	} else {
 		t = "Submit"
 	}
@@ -797,7 +821,7 @@
 
 	if n.Type() == html.ElementNode {
 		switch n.Data() {
-		case "style", "script", "svg", "template":
+		case "style", "script", "template":
 			return nil
 		case "input":
 			numElements++
@@ -851,7 +875,7 @@
 				innerContent,
 				n,
 			)
-		case "img":
+		case "img", "svg":
 			numElements++
 			return NewElement(
 				NewImage(n),
@@ -1230,7 +1254,7 @@
 func (b *Browser) LoadUrl() (e duit.Event) {
 	addr := b.LocationField.Text
 	if !strings.HasPrefix(addr, "http") {
-		addr = "https://" + addr
+		addr = "http://" + addr
 	}
 	log.Printf("Getting %v...", addr)
 	url, err := url.Parse(addr)
--- a/img/img.go
+++ b/img/img.go
@@ -62,6 +62,33 @@
 	return
 }
 
+// Svg returns the svg+xml encoded as jpg with the sizing defined in
+// viewbox unless w and h != 0
+func Svg(data string, w, h int) (bs []byte, err error) {
+	data = strings.ReplaceAll(data, "currentColor", "black")
+	r := bytes.NewReader([]byte(data))
+	icon, err := oksvg.ReadIconStream(r)
+	if err != nil {
+		return nil, fmt.Errorf("read icon stream: %w", err)
+	}
+
+	if w == 0 || h == 0 {
+		w = int(icon.ViewBox.W)
+		h = int(icon.ViewBox.H)
+	}
+
+	icon.SetTarget(0, 0, float64(w), float64(h))
+	rgba := image.NewRGBA(image.Rect(0, 0, w, h))
+	icon.Draw(rasterx.NewDasher(w, h, rasterx.NewScannerGV(w, h, rgba, rgba.Bounds())), 1)
+
+	buf := bytes.NewBufferString("")
+	if err = jpeg.Encode(buf, rgba, nil); err != nil {
+		return nil, fmt.Errorf("encode: %w", err)
+	}
+
+	return buf.Bytes(), nil
+}
+
 // Load and resize to w and h if != 0
 func Load(f opossum.Fetcher, src string, w, h int) (r io.Reader, err error) {
 	var imgUrl *url.URL
@@ -82,20 +109,10 @@
 	}
 
 	if contentType.IsSvg() {
-		r := bytes.NewReader(data)
-		icon, _ := oksvg.ReadIconStream(r)
-		if w == 0 || h == 0 {
-			w = 20
-			h = 20
+		data, err = Svg(string(data), w, h)
+		if err != nil {
+			return nil, fmt.Errorf("svg: %v", err)
 		}
-		icon.SetTarget(0, 0, float64(w), float64(h))
-		rgba := image.NewRGBA(image.Rect(0, 0, w, h))
-		icon.Draw(rasterx.NewDasher(w, h, rasterx.NewScannerGV(w, h, rgba, rgba.Bounds())), 1)
-		buf := bytes.NewBufferString("")
-		if err = jpeg.Encode(buf, rgba, nil); err != nil {
-			return nil, fmt.Errorf("encode: %w", err)
-		}
-		data = buf.Bytes()
 	} else if w != 0 || h != 0 {
 		image, _, err := image.Decode(bytes.NewReader(data))
 		if err != nil {
--- a/img/img_test.go
+++ b/img/img_test.go
@@ -26,3 +26,16 @@
 	}
 }
 
+func TestSvg(t *testing.T) {
+	xml := `
+		<svg fill="currentColor" height="24" viewBox="0 0 24 24" width="24">
+		</svg>
+	`
+
+	_, err := Svg(xml, 0, 0)
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+}
+
+
--- a/nodes/nodes.go
+++ b/nodes/nodes.go
@@ -1,6 +1,7 @@
 package nodes
 
 import (
+	"bytes"
 	"golang.org/x/net/html"
 	"opossum/logger"
 	"opossum/style"
@@ -95,6 +96,18 @@
 	return nil
 }
 
+func (n *Node) Find(tag string) (c *Node) {
+	for _, cc := range n.Children {
+		if cc.Data() == tag {
+			return cc
+		} else if f := cc.Find(tag); f != nil {
+			return f
+		}
+	}
+
+	return
+}
+
 func (n *Node) Attr(k string) string {
 	for _, a := range n.Attrs {
 		if a.Key == k {
@@ -147,4 +160,13 @@
 	}
 
 	return strings.TrimSpace(content)
-}
\ No newline at end of file
+}
+
+func (n *Node) Serialized() (string, error) {
+	var b bytes.Buffer
+	
+	err := html.Render(&b, n.DomSubtree)
+	
+	return b.String(), err
+}
+
--- a/style/stylesheets.go
+++ b/style/stylesheets.go
@@ -310,6 +310,7 @@
 
 func (cs Map) preferedFontName(preferences []string) string {
 	avails := availableFontNames
+
 	if len(avails) == 0 {
 		return preferences[0]
 	}
@@ -319,7 +320,7 @@
 		pref, preferences = preferences[0], preferences[1:]
 
 		for _, avail := range avails {
-			if pref == avail {
+			if pref == strings.TrimSuffix(avail, "/") {
 				return avail
 			}
 		}