shithub: mycel

Download patch

ref: 5acc68f9d3f5e32037b25853b899e62f9aac98c7
parent: 61a338e19d2e61337515130f2c635e5b6428a687
author: Philip Silva <philip.silva@protonmail.com>
date: Sat Mar 27 17:33:48 EDT 2021

Support picture tag

- try to pick smallest image/image fitting to screen scale
- prevent too large images on some websites leading to
  too wide text

--- a/browser/browser.go
+++ b/browser/browser.go
@@ -18,6 +18,7 @@
 	"github.com/psilva261/opossum/nodes"
 	"github.com/psilva261/opossum/style"
 	"os"
+	"strconv"
 	"strings"
 
 	"github.com/mjl-/duit"
@@ -189,7 +190,9 @@
 		return nil, fmt.Errorf("display nil")
 	}
 
-	if n.Data() == "svg" {
+	if n.Data() == "picture" {
+		src = newPicture(n)
+	} else if n.Data() == "svg" {
 		xml, err := n.Serialized()
 		if  err != nil {
 			return nil, fmt.Errorf("serialize: %w", err)
@@ -240,6 +243,43 @@
 	), nil
 }
 
+func newPicture(n *nodes.Node) string {
+	smallestImg := ""
+	smallestW := 0
+	scale := 1
+
+	if dui != nil {
+		scale = int(dui.Scale(1))
+	}
+
+	for _, source := range n.FindAll("source") {
+		for _, s := range strings.Split(source.Attr("srcset"), ",") {
+			s = strings.TrimSpace(s)
+			tmp := strings.Split(s, " ")
+			src := ""
+			s := ""
+			src = tmp[0]
+			if len(tmp) == 2 {
+				s = tmp[1]
+			}
+			if s == "" || s == fmt.Sprintf("%vx", scale) {
+				return src
+			}
+			s = strings.TrimSuffix(s, "w")
+			w, err := strconv.Atoi(s)
+			if err != nil {
+				continue
+			}
+			if smallestImg == "" || smallestW > w {
+				smallestImg = src
+				smallestW = w
+			}
+		}
+	}
+
+	return smallestImg
+}
+
 type Element struct {
 	duit.UI
 	n       *nodes.Node
@@ -1035,7 +1075,7 @@
 			return NewElement(btn, n)
 		case "table":
 			return NewTable(n).Element(r+1, b, n)
-		case "img", "svg":
+		case "picture", "img", "svg":
 			return NewElement(NewImage(n), n)
 		case "pre":
 			return NewElement(
--- a/browser/browser_test.go
+++ b/browser/browser_test.go
@@ -410,3 +410,22 @@
 	}
 }
 
+func TestNewPicture(t *testing.T) {
+	htm := `
+		<picture itemprop="contentUrl">
+			<source srcset="https://example.com/2040 2040w,https://example.com/1880 1880w,https://example.com/1400 1400w" media="(-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi)">
+    		<source srcset="https://example.com/1020 1020w,https://example.com/940 940w,https://example.com/700 700w">
+    		<img src="https://example.com/465" height="5000" width="7000" loading="lazy">
+    	</picture>
+	`
+	nt, _, err := digestHtm(htm)
+	if err != nil {
+		t.Fatalf("digest: %v", err)
+	}
+
+	p := nt.Find("picture")
+	src := newPicture(p)
+	if src != "https://example.com/700" {
+		t.Error()
+	}
+}
--- a/nodes/nodes.go
+++ b/nodes/nodes.go
@@ -122,6 +122,18 @@
 	return
 }
 
+func (n *Node) FindAll(tag string) (cs []*Node) {
+	for _, cc := range n.Children {
+		if cc.Data() == tag {
+			cs = append(cs, cc)
+		} else {
+			cs = append(cs, cc.FindAll(tag)...)
+		}
+	}
+
+	return
+}
+
 func (n *Node) Attr(k string) string {
 	for _, a := range n.Attrs {
 		if a.Key == k {