Diff
diff --git a/docs/cstyle/index.html b/docs/cstyle/index.html
index ec0c057..40d24d1 100644
--- a/docs/cstyle/index.html
+++ b/docs/cstyle/index.html
@@ -23,0 +24,2 @@
+# CreateDocument?(go)
+# CreateNode?(go)
@@ -28,0 +31 @@
+# initNodes?(go)
@@ -53,2 +56,2 @@
- 20 "strings"
- 21)
+ 20 "strconv"
+ 21 "strings"
@@ -56,22 +59,22 @@
- 23type Plugin struct {
- 24 Styles map[string]string
- 25 Level int
- 26 Handler func(*element.Node)
- 27}
- 28
- 29type CSS struct {
- 30 Width float32
- 31 Height float32
- 32 StyleSheets []map[string]map[string]string
- 33 Plugins []Plugin
- 34 Document *element.Node
- 35}
- 36
- 37func (c *CSS) StyleSheet(path string) {
- 38 // Parse the CSS file
- 39 dat, err := os.ReadFile(path)
- 40 utils.Check(err)
- 41 styles := parser.ParseCSS(string(dat))
- 42
- 43 c.StyleSheets = append(c.StyleSheets, styles)
- 44}
+ 23 "golang.org/x/net/html"
+ 24)
+ 25
+ 26type Plugin struct {
+ 27 Styles map[string]string
+ 28 Level int
+ 29 Handler func(*element.Node)
+ 30}
+ 31
+ 32type CSS struct {
+ 33 Width float32
+ 34 Height float32
+ 35 StyleSheets []map[string]map[string]string
+ 36 Plugins []Plugin
+ 37 Document *element.Node
+ 38}
+ 39
+ 40func (c *CSS) StyleSheet(path string) {
+ 41 // Parse the CSS file
+ 42 dat, err := os.ReadFile(path)
+ 43 utils.Check(err)
+ 44 styles := parser.ParseCSS(string(dat))
@@ -79,39 +82,39 @@
- 46func (c *CSS) StyleTag(css string) {
- 47 styles := parser.ParseCSS(css)
- 48 c.StyleSheets = append(c.StyleSheets, styles)
- 49}
- 50
- 51var inheritedProps = []string{
- 52 "color",
- 53 "cursor",
- 54 "font",
- 55 "font-family",
- 56 "font-size",
- 57 "font-style",
- 58 "font-weight",
- 59 "letter-spacing",
- 60 "line-height",
- 61 "text-align",
- 62 "text-indent",
- 63 "text-justify",
- 64 "text-shadow",
- 65 "text-transform",
- 66 "visibility",
- 67 "word-spacing",
- 68 "display",
- 69}
- 70
- 71// need to get rid of the .props for the most part all styles should be computed dynamically
- 72// can keep like focusable and stuff that describes the element
- 73
- 74// currently the append child does not work due to the props and other stuff not existing so it fails
- 75// moving to a real time style compute would fix that
- 76
- 77// :hover is parsed correctly but because the hash func doesn't invalidate it becuase the val
- 78// is updated in the props. change to append :hover to style to create the effect
- 79// or merge the class with the styles? idk have to think more
- 80
- 81func (c *CSS) GetStyles(n element.Node) map[string]string {
- 82 styles := map[string]string{}
- 83 for k, v := range n.Style {
- 84 styles[k] = v
+ 46 c.StyleSheets = append(c.StyleSheets, styles)
+ 47}
+ 48
+ 49func (c *CSS) StyleTag(css string) {
+ 50 styles := parser.ParseCSS(css)
+ 51 c.StyleSheets = append(c.StyleSheets, styles)
+ 52}
+ 53
+ 54func (c *CSS) CreateDocument(doc *html.Node) element.Node {
+ 55 id := doc.FirstChild.Data + "0"
+ 56 n := doc.FirstChild
+ 57 node := element.Node{
+ 58 Parent: &element.Node{
+ 59 Properties: element.Properties{
+ 60 Id: "ROOT",
+ 61 X: 0,
+ 62 Y: 0,
+ 63 Width: c.Width,
+ 64 Height: c.Height,
+ 65 EM: 16,
+ 66 },
+ 67
+ 68 Style: map[string]string{
+ 69 "width": strconv.FormatFloat(float64(c.Width), 'f', -1, 32) + "px",
+ 70 "height": strconv.FormatFloat(float64(c.Height), 'f', -1, 32) + "px",
+ 71 },
+ 72 },
+ 73 Properties: element.Properties{
+ 74 Id: id,
+ 75 X: 0,
+ 76 Y: 0,
+ 77 },
+ 78 }
+ 79 i := 0
+ 80 for child := n.FirstChild; child != nil; child = child.NextSibling {
+ 81 if child.Type == html.ElementNode {
+ 82 node.Children = append(node.Children, CreateNode(node, child, fmt.Sprint(i)))
+ 83 i++
+ 84 }
@@ -119,12 +122,12 @@
- 86 if n.Parent != nil {
- 87 ps := c.GetStyles(*n.Parent)
- 88 for _, v := range inheritedProps {
- 89 if ps[v] != "" {
- 90 styles[v] = ps[v]
- 91 }
- 92 }
- 93
- 94 }
- 95 hovered := false
- 96 if slices.Contains(n.ClassList.Classes, ":hover") {
- 97 hovered = true
+ 86 return initNodes(&node, *c)
+ 87}
+ 88
+ 89func CreateNode(parent element.Node, n *html.Node, slug string) element.Node {
+ 90 id := n.Data + slug
+ 91 node := element.Node{
+ 92 Parent: &parent,
+ 93 TagName: n.Data,
+ 94 InnerText: utils.GetInnerText(n),
+ 95 Properties: element.Properties{
+ 96 Id: id,
+ 97 },
@@ -132,132 +135,132 @@
- 99
-100 for _, styleSheet := range c.StyleSheets {
-101 for selector := range styleSheet {
-102 // fmt.Println(selector, n.Properties.Id)
-103 key := selector
-104 if strings.Contains(selector, ":hover") && hovered {
-105 selector = strings.Replace(selector, ":hover", "", -1)
-106 }
-107 if element.TestSelector(selector, &n) {
-108 for k, v := range styleSheet[key] {
-109 styles[k] = v
-110 }
-111 }
-112
-113 }
-114 }
-115 inline := parser.ParseStyleAttribute(n.GetAttribute("style") + ";")
-116 styles = utils.Merge(styles, inline)
-117 // add hover and focus css events
-118
-119 return styles
-120}
-121
-122func (c *CSS) Render(doc element.Node) []element.Node {
-123 return flatten(doc)
-124}
-125
-126func (c *CSS) AddPlugin(plugin Plugin) {
-127 c.Plugins = append(c.Plugins, plugin)
-128}
-129
-130func hash(n *element.Node) string {
-131 // Create a new FNV-1a hash
-132 hasher := md5.New()
-133
-134 // Extract and sort the keys
-135 var keys []string
-136 for key := range n.Style {
-137 keys = append(keys, key)
-138 }
-139 sort.Strings(keys)
-140
-141 // Concatenate all values into a single string
-142 var concatenatedValues string
-143 for _, key := range keys {
-144 concatenatedValues += key + n.Style[key]
-145 }
-146 concatenatedValues += n.ClassList.Value
-147 concatenatedValues += n.Id
-148 hasher.Write([]byte(concatenatedValues))
-149 sum := hasher.Sum(nil)
-150 str := hex.EncodeToString(sum)
-151 if n.Properties.Hash != str {
-152 fmt.Println(n.Properties.Id)
-153 fmt.Println(concatenatedValues)
-154 fmt.Println(n.Properties.Hash, str)
-155 }
-156
-157 return str
-158}
-159
-160func (c *CSS) ComputeNodeStyle(n *element.Node) *element.Node {
-161 plugins := c.Plugins
-162 hv := hash(n)
-163 if n.Properties.Hash != hv {
-164 fmt.Println("RELOAD")
-165 // this is kinda a sloppy way to do this but it works ig
-166 n.Style = c.GetStyles(*n)
-167 n.Properties.Hash = hv
-168 }
-169 styleMap := n.Style
-170
-171 if styleMap["display"] == "none" {
-172 n.Properties.X = 0
-173 n.Properties.Y = 0
-174 n.Properties.Width = 0
-175 n.Properties.Height = 0
-176 return n
-177 }
-178
-179 width, height := n.Properties.Width, n.Properties.Height
-180 x, y := n.Parent.Properties.X, n.Parent.Properties.Y
-181
-182 var top, left, right, bottom bool = false, false, false, false
-183
-184 m := utils.GetMP(*n, "margin")
-185 p := utils.GetMP(*n, "padding")
-186
-187 if styleMap["position"] == "absolute" {
-188 base := utils.GetPositionOffsetNode(n)
-189 if styleMap["top"] != "" {
-190 v, _ := utils.ConvertToPixels(styleMap["top"], float32(n.Properties.EM), n.Parent.Properties.Width)
-191 y = v + base.Properties.Y
-192 top = true
-193 }
-194 if styleMap["left"] != "" {
-195 v, _ := utils.ConvertToPixels(styleMap["left"], float32(n.Properties.EM), n.Parent.Properties.Width)
-196 x = v + base.Properties.X
-197 left = true
-198 }
-199 if styleMap["right"] != "" {
-200 v, _ := utils.ConvertToPixels(styleMap["right"], float32(n.Properties.EM), n.Parent.Properties.Width)
-201 x = (base.Properties.Width - width) - v
-202 right = true
-203 }
-204 if styleMap["bottom"] != "" {
-205 v, _ := utils.ConvertToPixels(styleMap["bottom"], float32(n.Properties.EM), n.Parent.Properties.Width)
-206 y = (base.Properties.Height - height) - v
-207 bottom = true
-208 }
-209 } else {
-210 for i, v := range n.Parent.Children {
-211 if v.Properties.Id == n.Properties.Id {
-212 if i-1 > 0 {
-213 sibling := n.Parent.Children[i-1]
-214 if styleMap["display"] == "inline" {
-215 if sibling.Style["display"] == "inline" {
-216 y = sibling.Properties.Y
-217 } else {
-218 y = sibling.Properties.Y + sibling.Properties.Height
-219 }
-220 } else {
-221 y = sibling.Properties.Y + sibling.Properties.Height
-222 }
-223 }
-224 break
-225 } else if styleMap["display"] != "inline" {
-226 mc := utils.GetMP(v, "margin")
-227 pc := utils.GetMP(v, "padding")
-228 y += mc.Top + mc.Bottom + pc.Top + pc.Bottom + v.Properties.Height
-229 }
-230 }
+ 99 for _, attr := range n.Attr {
+100 if attr.Key == "class" {
+101 classes := strings.Split(attr.Val, " ")
+102 for _, class := range classes {
+103 node.ClassList.Add(class)
+104 }
+105 } else if attr.Key == "id" {
+106 node.Id = attr.Val
+107 } else if attr.Key == "contenteditable" && (attr.Val == "" || attr.Val == "true") {
+108 node.Properties.Editable = true
+109 } else if attr.Key == "href" {
+110 node.Href = attr.Val
+111 } else if attr.Key == "src" {
+112 node.Src = attr.Val
+113 } else if attr.Key == "title" {
+114 node.Title = attr.Val
+115 }
+116 }
+117 i := 0
+118 for child := n.FirstChild; child != nil; child = child.NextSibling {
+119 if child.Type == html.ElementNode {
+120 node.Children = append(node.Children, CreateNode(node, child, slug+fmt.Sprint(i)))
+121 i++
+122 }
+123 }
+124 return node
+125}
+126
+127var inheritedProps = []string{
+128 "color",
+129 "cursor",
+130 "font",
+131 "font-family",
+132 "font-size",
+133 "font-style",
+134 "font-weight",
+135 "letter-spacing",
+136 "line-height",
+137 "text-align",
+138 "text-indent",
+139 "text-justify",
+140 "text-shadow",
+141 "text-transform",
+142 "visibility",
+143 "word-spacing",
+144 "display",
+145}
+146
+147// need to get rid of the .props for the most part all styles should be computed dynamically
+148// can keep like focusable and stuff that describes the element
+149
+150// currently the append child does not work due to the props and other stuff not existing so it fails
+151// moving to a real time style compute would fix that
+152
+153// :hover is parsed correctly but because the hash func doesn't invalidate it becuase the val
+154// is updated in the props. change to append :hover to style to create the effect
+155// or merge the class with the styles? idk have to think more
+156
+157func (c *CSS) GetStyles(n element.Node) map[string]string {
+158 styles := map[string]string{}
+159 for k, v := range n.Style {
+160 styles[k] = v
+161 }
+162 if n.Parent != nil {
+163 ps := c.GetStyles(*n.Parent)
+164 for _, v := range inheritedProps {
+165 if ps[v] != "" {
+166 styles[v] = ps[v]
+167 }
+168 }
+169
+170 }
+171 hovered := false
+172 if slices.Contains(n.ClassList.Classes, ":hover") {
+173 hovered = true
+174 }
+175
+176 for _, styleSheet := range c.StyleSheets {
+177 for selector := range styleSheet {
+178 // fmt.Println(selector, n.Properties.Id)
+179 key := selector
+180 if strings.Contains(selector, ":hover") && hovered {
+181 selector = strings.Replace(selector, ":hover", "", -1)
+182 }
+183 if element.TestSelector(selector, &n) {
+184 for k, v := range styleSheet[key] {
+185 styles[k] = v
+186 }
+187 }
+188
+189 }
+190 }
+191 inline := parser.ParseStyleAttribute(n.GetAttribute("style") + ";")
+192 styles = utils.Merge(styles, inline)
+193 // add hover and focus css events
+194
+195 return styles
+196}
+197
+198func (c *CSS) Render(doc element.Node) []element.Node {
+199 return flatten(doc)
+200}
+201
+202func (c *CSS) AddPlugin(plugin Plugin) {
+203 c.Plugins = append(c.Plugins, plugin)
+204}
+205
+206func hash(n *element.Node) string {
+207 // Create a new FNV-1a hash
+208 hasher := md5.New()
+209
+210 // Extract and sort the keys
+211 var keys []string
+212 for key := range n.Style {
+213 keys = append(keys, key)
+214 }
+215 sort.Strings(keys)
+216
+217 // Concatenate all values into a single string
+218 var concatenatedValues string
+219 for _, key := range keys {
+220 concatenatedValues += key + n.Style[key]
+221 }
+222 concatenatedValues += n.ClassList.Value
+223 concatenatedValues += n.Id
+224 hasher.Write([]byte(concatenatedValues))
+225 sum := hasher.Sum(nil)
+226 str := hex.EncodeToString(sum)
+227 if n.Properties.Hash != str {
+228 fmt.Println(n.Properties.Id)
+229 fmt.Println(concatenatedValues)
+230 fmt.Println(n.Properties.Hash, str)
@@ -266,26 +269,26 @@
-233 // Display modes need to be calculated here
-234
-235 relPos := !top && !left && !right && !bottom
-236
-237 if left || relPos {
-238 x += m.Left
-239 }
-240 if top || relPos {
-241 y += m.Top
-242 }
-243 if right {
-244 x -= m.Right
-245 }
-246 if bottom {
-247 y -= m.Bottom
-248 }
-249
-250 bold, italic := false, false
-251
-252 if n.Style["font-weight"] == "bold" {
-253 bold = true
-254 }
-255
-256 if n.Style["font-style"] == "italic" {
-257 italic = true
-258 }
+233 return str
+234}
+235
+236func (c *CSS) ComputeNodeStyle(n *element.Node) *element.Node {
+237 plugins := c.Plugins
+238 hv := hash(n)
+239 if n.Properties.Hash != hv {
+240 fmt.Println("RELOAD")
+241 // this is kinda a sloppy way to do this but it works ig
+242 n.Style = c.GetStyles(*n)
+243 n.Properties.Hash = hv
+244 }
+245 styleMap := n.Style
+246
+247 if styleMap["display"] == "none" {
+248 n.Properties.X = 0
+249 n.Properties.Y = 0
+250 n.Properties.Width = 0
+251 n.Properties.Height = 0
+252 return n
+253 }
+254
+255 width, height := n.Properties.Width, n.Properties.Height
+256 x, y := n.Parent.Properties.X, n.Parent.Properties.Y
+257
+258 var top, left, right, bottom bool = false, false, false, false
@@ -293,48 +296,48 @@
-260 if n.Properties.Text.Font == nil {
-261 f, _ := font.LoadFont(n.Style["font-family"], int(n.Properties.EM), bold, italic)
-262 letterSpacing, _ := utils.ConvertToPixels(n.Style["letter-spacing"], n.Properties.EM, width)
-263 wordSpacing, _ := utils.ConvertToPixels(n.Style["word-spacing"], n.Properties.EM, width)
-264 lineHeight, _ := utils.ConvertToPixels(n.Style["line-height"], n.Properties.EM, width)
-265 if lineHeight == 0 {
-266 lineHeight = n.Properties.EM + 3
-267 }
-268
-269 n.Properties.Text.LineHeight = int(lineHeight)
-270 n.Properties.Text.Font = f
-271 n.Properties.Text.WordSpacing = int(wordSpacing)
-272 n.Properties.Text.LetterSpacing = int(letterSpacing)
-273 }
-274
-275 if len(n.Children) == 0 {
-276 // Confirm text exists
-277 if len(n.InnerText) > 0 && !utils.IsParent(*n, "head") {
-278 innerWidth := width
-279 innerHeight := height
-280 genTextNode(n, &innerWidth, &innerHeight, p)
-281 width = innerWidth + p.Left + p.Right
-282 height = innerHeight
-283 }
-284 }
-285
-286 n.Properties.X = x
-287 n.Properties.Y = y
-288 n.Properties.Width = width
-289 n.Properties.Height = height
-290
-291 // Call children here
-292
-293 var childYOffset float32
-294 for i, v := range n.Children {
-295 v.Parent = n
-296 n.Children[i] = *c.ComputeNodeStyle(&v)
-297 if styleMap["height"] == "" {
-298 if n.Children[i].Style["position"] != "absolute" && n.Children[i].Properties.Y > childYOffset {
-299 childYOffset = n.Children[i].Properties.Y
-300 m := utils.GetMP(n.Children[i], "margin")
-301 p := utils.GetMP(n.Children[i], "padding")
-302 n.Properties.Height += n.Children[i].Properties.Height
-303 n.Properties.Height += m.Top
-304 n.Properties.Height += m.Bottom
-305 n.Properties.Height += p.Top
-306 n.Properties.Height += p.Bottom
-307 }
+260 m := utils.GetMP(*n, "margin")
+261 p := utils.GetMP(*n, "padding")
+262
+263 if styleMap["position"] == "absolute" {
+264 base := utils.GetPositionOffsetNode(n)
+265 if styleMap["top"] != "" {
+266 v, _ := utils.ConvertToPixels(styleMap["top"], float32(n.Properties.EM), n.Parent.Properties.Width)
+267 y = v + base.Properties.Y
+268 top = true
+269 }
+270 if styleMap["left"] != "" {
+271 v, _ := utils.ConvertToPixels(styleMap["left"], float32(n.Properties.EM), n.Parent.Properties.Width)
+272 x = v + base.Properties.X
+273 left = true
+274 }
+275 if styleMap["right"] != "" {
+276 v, _ := utils.ConvertToPixels(styleMap["right"], float32(n.Properties.EM), n.Parent.Properties.Width)
+277 x = (base.Properties.Width - width) - v
+278 right = true
+279 }
+280 if styleMap["bottom"] != "" {
+281 v, _ := utils.ConvertToPixels(styleMap["bottom"], float32(n.Properties.EM), n.Parent.Properties.Width)
+282 y = (base.Properties.Height - height) - v
+283 bottom = true
+284 }
+285 } else {
+286 for i, v := range n.Parent.Children {
+287 if v.Properties.Id == n.Properties.Id {
+288 if i-1 > 0 {
+289 sibling := n.Parent.Children[i-1]
+290 if styleMap["display"] == "inline" {
+291 if sibling.Style["display"] == "inline" {
+292 y = sibling.Properties.Y
+293 } else {
+294 y = sibling.Properties.Y + sibling.Properties.Height
+295 }
+296 } else {
+297 y = sibling.Properties.Y + sibling.Properties.Height
+298 }
+299 }
+300 break
+301 } else if styleMap["display"] != "inline" {
+302 mc := utils.GetMP(v, "margin")
+303 pc := utils.GetMP(v, "padding")
+304 y += mc.Top + mc.Bottom + pc.Top + pc.Bottom + v.Properties.Height
+305 }
+306 }
+307 }
@@ -342,32 +345,32 @@
-309 }
-310 }
-311
-312 // Sorting the array by the Level field
-313 sort.Slice(plugins, func(i, j int) bool {
-314 return plugins[i].Level < plugins[j].Level
-315 })
-316
-317 for _, v := range plugins {
-318 matches := true
-319 for name, value := range v.Styles {
-320 if styleMap[name] != value && !(value == "*") {
-321 matches = false
-322 }
-323 }
-324 if matches {
-325 v.Handler(n)
-326 }
-327 }
-328
-329 return n
-330}
-331
-332func InitNode(n *element.Node, c CSS) *element.Node {
-333 n.Style = c.GetStyles(*n)
-334 border, err := CompleteBorder(n.Style)
-335 if err == nil {
-336 n.Properties.Border = border
-337 }
-338
-339 fs, _ := utils.ConvertToPixels(n.Style["font-size"], n.Parent.Properties.EM, n.Parent.Properties.Width)
-340 n.Properties.EM = fs
+309 // Display modes need to be calculated here
+310
+311 relPos := !top && !left && !right && !bottom
+312
+313 if left || relPos {
+314 x += m.Left
+315 }
+316 if top || relPos {
+317 y += m.Top
+318 }
+319 if right {
+320 x -= m.Right
+321 }
+322 if bottom {
+323 y -= m.Bottom
+324 }
+325
+326 if len(n.Children) == 0 {
+327 // Confirm text exists
+328 if len(n.InnerText) > 0 {
+329 innerWidth := width
+330 innerHeight := height
+331 genTextNode(n, &innerWidth, &innerHeight, p)
+332 width = innerWidth + p.Left + p.Right
+333 height = innerHeight
+334 }
+335 }
+336
+337 n.Properties.X = x
+338 n.Properties.Y = y
+339 n.Properties.Width = width
+340 n.Properties.Height = height
@@ -375,49 +378,49 @@
-342 width, _ := utils.ConvertToPixels(n.Style["width"], n.Properties.EM, n.Parent.Properties.Width)
-343 if n.Style["min-width"] != "" {
-344 minWidth, _ := utils.ConvertToPixels(n.Style["min-width"], n.Properties.EM, n.Parent.Properties.Width)
-345 width = utils.Max(width, minWidth)
-346 }
-347
-348 if n.Style["max-width"] != "" {
-349 maxWidth, _ := utils.ConvertToPixels(n.Style["max-width"], n.Properties.EM, n.Parent.Properties.Width)
-350 width = utils.Min(width, maxWidth)
-351 }
-352
-353 height, _ := utils.ConvertToPixels(n.Style["height"], n.Properties.EM, n.Parent.Properties.Height)
-354 if n.Style["min-height"] != "" {
-355 minHeight, _ := utils.ConvertToPixels(n.Style["min-height"], n.Properties.EM, n.Parent.Properties.Height)
-356 height = utils.Max(height, minHeight)
-357 }
-358
-359 if n.Style["max-height"] != "" {
-360 maxHeight, _ := utils.ConvertToPixels(n.Style["max-height"], n.Properties.EM, n.Parent.Properties.Height)
-361 height = utils.Min(height, maxHeight)
-362 }
-363
-364 n.Properties.Width = width
-365 n.Properties.Height = height
-366
-367 bold, italic := false, false
-368
-369 if n.Style["font-weight"] == "bold" {
-370 bold = true
-371 }
-372
-373 if n.Style["font-style"] == "italic" {
-374 italic = true
-375 }
-376
-377 f, _ := font.LoadFont(n.Style["font-family"], int(n.Properties.EM), bold, italic)
-378 letterSpacing, _ := utils.ConvertToPixels(n.Style["letter-spacing"], n.Properties.EM, width)
-379 wordSpacing, _ := utils.ConvertToPixels(n.Style["word-spacing"], n.Properties.EM, width)
-380 lineHeight, _ := utils.ConvertToPixels(n.Style["line-height"], n.Properties.EM, width)
-381 if lineHeight == 0 {
-382 lineHeight = n.Properties.EM + 3
-383 }
-384
-385 n.Properties.Text.LineHeight = int(lineHeight)
-386 n.Properties.Text.Font = f
-387 n.Properties.Text.WordSpacing = int(wordSpacing)
-388 n.Properties.Text.LetterSpacing = int(letterSpacing)
-389 return n
-390}
+342 // Call children here
+343
+344 var childYOffset float32
+345 for i, v := range n.Children {
+346 v.Parent = n
+347 n.Children[i] = *c.ComputeNodeStyle(&v)
+348 if styleMap["height"] == "" {
+349 if n.Children[i].Style["position"] != "absolute" && n.Children[i].Properties.Y > childYOffset {
+350 childYOffset = n.Children[i].Properties.Y
+351 m := utils.GetMP(n.Children[i], "margin")
+352 p := utils.GetMP(n.Children[i], "padding")
+353 n.Properties.Height += n.Children[i].Properties.Height
+354 n.Properties.Height += m.Top
+355 n.Properties.Height += m.Bottom
+356 n.Properties.Height += p.Top
+357 n.Properties.Height += p.Bottom
+358 }
+359
+360 }
+361 }
+362
+363 // Sorting the array by the Level field
+364 sort.Slice(plugins, func(i, j int) bool {
+365 return plugins[i].Level < plugins[j].Level
+366 })
+367
+368 for _, v := range plugins {
+369 matches := true
+370 for name, value := range v.Styles {
+371 if styleMap[name] != value && !(value == "*") {
+372 matches = false
+373 }
+374 }
+375 if matches {
+376 v.Handler(n)
+377 }
+378 }
+379
+380 return n
+381}
+382
+383func initNodes(n *element.Node, c CSS) element.Node {
+384 n = InitNode(n, c)
+385 for i, ch := range n.Children {
+386 // if ch.Properties.Type == html.ElementNode {
+387 ch.Parent = n
+388 cn := initNodes(&ch, c)
+389
+390 n.Children[i] = cn
@@ -425,31 +428,31 @@
-392func parseBorderShorthand(borderShorthand string) (element.Border, error) {
-393 // Split the shorthand into components
-394 borderComponents := strings.Fields(borderShorthand)
-395
-396 // Ensure there are at least 1 component (width or style or color)
-397 if len(borderComponents) >= 1 {
-398 width := "0px" // Default width
-399 style := "solid"
-400 borderColor := "#000000" // Default color
-401
-402 // Extract style and color if available
-403 if len(borderComponents) >= 1 {
-404 width = borderComponents[0]
-405 }
-406
-407 // Extract style and color if available
-408 if len(borderComponents) >= 2 {
-409 style = borderComponents[1]
-410 }
-411 if len(borderComponents) >= 3 {
-412 borderColor = borderComponents[2]
-413 }
-414
-415 parsedColor, _ := color.Color(borderColor)
-416
-417 return element.Border{
-418 Width: width,
-419 Style: style,
-420 Color: parsedColor,
-421 Radius: "", // Default radius
-422 }, nil
+392 // }
+393 }
+394
+395 return *n
+396}
+397
+398func InitNode(n *element.Node, c CSS) *element.Node {
+399 n.Style = c.GetStyles(*n)
+400 border, err := CompleteBorder(n.Style)
+401 if err == nil {
+402 n.Properties.Border = border
+403 }
+404
+405 fs, _ := utils.ConvertToPixels(n.Style["font-size"], n.Parent.Properties.EM, n.Parent.Properties.Width)
+406 n.Properties.EM = fs
+407
+408 width, _ := utils.ConvertToPixels(n.Style["width"], n.Properties.EM, n.Parent.Properties.Width)
+409 if n.Style["min-width"] != "" {
+410 minWidth, _ := utils.ConvertToPixels(n.Style["min-width"], n.Properties.EM, n.Parent.Properties.Width)
+411 width = utils.Max(width, minWidth)
+412 }
+413
+414 if n.Style["max-width"] != "" {
+415 maxWidth, _ := utils.ConvertToPixels(n.Style["max-width"], n.Properties.EM, n.Parent.Properties.Width)
+416 width = utils.Min(width, maxWidth)
+417 }
+418
+419 height, _ := utils.ConvertToPixels(n.Style["height"], n.Properties.EM, n.Parent.Properties.Height)
+420 if n.Style["min-height"] != "" {
+421 minHeight, _ := utils.ConvertToPixels(n.Style["min-height"], n.Properties.EM, n.Parent.Properties.Height)
+422 height = utils.Max(height, minHeight)
@@ -458,9 +461,9 @@
-425 return element.Border{}, fmt.Errorf("invalid border shorthand format")
-426}
-427
-428func CompleteBorder(cssProperties map[string]string) (element.Border, error) {
-429 border, err := parseBorderShorthand(cssProperties["border"])
-430 border.Radius = cssProperties["border-radius"]
-431
-432 return border, err
-433}
+425 if n.Style["max-height"] != "" {
+426 maxHeight, _ := utils.ConvertToPixels(n.Style["max-height"], n.Properties.EM, n.Parent.Properties.Height)
+427 height = utils.Min(height, maxHeight)
+428 }
+429
+430 n.Properties.Width = width
+431 n.Properties.Height = height
+432
+433 bold, italic := false, false
@@ -468,3 +471,3 @@
-435func flatten(n element.Node) []element.Node {
-436 var nodes []element.Node
-437 nodes = append(nodes, n)
+435 if n.Style["font-weight"] == "bold" {
+436 bold = true
+437 }
@@ -472,33 +475,33 @@
-439 children := n.Children
-440 if len(children) > 0 {
-441 for _, ch := range children {
-442 chNodes := flatten(ch)
-443 nodes = append(nodes, chNodes...)
-444 }
-445 }
-446 return nodes
-447}
-448
-449func genTextNode(n *element.Node, width, height *float32, p utils.MarginPadding) {
-450 wb := " "
-451
-452 if n.Style["word-wrap"] == "break-word" {
-453 wb = ""
-454 }
-455
-456 if n.Style["text-wrap"] == "wrap" || n.Style["text-wrap"] == "balance" {
-457 wb = ""
-458 }
-459
-460 letterSpacing, _ := utils.ConvertToPixels(n.Style["letter-spacing"], n.Properties.EM, *width)
-461 wordSpacing, _ := utils.ConvertToPixels(n.Style["word-spacing"], n.Properties.EM, *width)
-462
-463 var dt float32
-464
-465 if n.Style["text-decoration-thickness"] == "auto" || n.Style["text-decoration-thickness"] == "" {
-466 dt = 2
-467 } else {
-468 dt, _ = utils.ConvertToPixels(n.Style["text-decoration-thickness"], n.Properties.EM, *width)
-469 }
-470
-471 col := color.Parse(n.Style, "font")
+439 if n.Style["font-style"] == "italic" {
+440 italic = true
+441 }
+442
+443 f, _ := font.LoadFont(n.Style["font-family"], int(n.Properties.EM), bold, italic)
+444 letterSpacing, _ := utils.ConvertToPixels(n.Style["letter-spacing"], n.Properties.EM, width)
+445 wordSpacing, _ := utils.ConvertToPixels(n.Style["word-spacing"], n.Properties.EM, width)
+446 lineHeight, _ := utils.ConvertToPixels(n.Style["line-height"], n.Properties.EM, width)
+447 if lineHeight == 0 {
+448 lineHeight = n.Properties.EM + 3
+449 }
+450
+451 n.Properties.Text.LineHeight = int(lineHeight)
+452 n.Properties.Text.Font = f
+453 n.Properties.Text.WordSpacing = int(wordSpacing)
+454 n.Properties.Text.LetterSpacing = int(letterSpacing)
+455 return n
+456}
+457
+458func parseBorderShorthand(borderShorthand string) (element.Border, error) {
+459 // Split the shorthand into components
+460 borderComponents := strings.Fields(borderShorthand)
+461
+462 // Ensure there are at least 1 component (width or style or color)
+463 if len(borderComponents) >= 1 {
+464 width := "0px" // Default width
+465 style := "solid"
+466 borderColor := "#000000" // Default color
+467
+468 // Extract style and color if available
+469 if len(borderComponents) >= 1 {
+470 width = borderComponents[0]
+471 }
@@ -506,31 +509,97 @@
-473 n.Properties.Text.Color = col
-474 n.Properties.Text.Align = n.Style["text-align"]
-475 n.Properties.Text.WordBreak = wb
-476 n.Properties.Text.WordSpacing = int(wordSpacing)
-477 n.Properties.Text.LetterSpacing = int(letterSpacing)
-478 n.Properties.Text.WhiteSpace = n.Style["white-space"]
-479 n.Properties.Text.DecorationThickness = int(dt)
-480 n.Properties.Text.Overlined = n.Style["text-decoration"] == "overline"
-481 n.Properties.Text.Underlined = n.Style["text-decoration"] == "underline"
-482 n.Properties.Text.LineThrough = n.Style["text-decoration"] == "linethrough"
-483 n.Properties.Text.EM = int(n.Properties.EM)
-484 n.Properties.Text.Width = int(n.Parent.Properties.Width)
-485
-486 if n.Style["word-spacing"] == "" {
-487 n.Properties.Text.WordSpacing = font.MeasureSpace(&n.Properties.Text)
-488 }
-489 if n.Parent.Properties.Width != 0 && n.Style["display"] != "inline" && n.Style["width"] == "" {
-490 *width = (n.Parent.Properties.Width - p.Right) - p.Left
-491 } else if n.Style["width"] == "" {
-492 *width = utils.Max(*width, float32(font.MeasureLongest(n)))
-493 } else if n.Style["width"] != "" {
-494 *width, _ = utils.ConvertToPixels(n.Style["width"], n.Properties.EM, n.Parent.Properties.Width)
-495 }
-496
-497 n.Properties.Text.Width = int(*width)
-498 h := font.Render(n)
-499 if n.Style["height"] == "" {
-500 *height = h
-501 }
-502
-503}
+473 // Extract style and color if available
+474 if len(borderComponents) >= 2 {
+475 style = borderComponents[1]
+476 }
+477 if len(borderComponents) >= 3 {
+478 borderColor = borderComponents[2]
+479 }
+480
+481 parsedColor, _ := color.Color(borderColor)
+482
+483 return element.Border{
+484 Width: width,
+485 Style: style,
+486 Color: parsedColor,
+487 Radius: "", // Default radius
+488 }, nil
+489 }
+490
+491 return element.Border{}, fmt.Errorf("invalid border shorthand format")
+492}
+493
+494func CompleteBorder(cssProperties map[string]string) (element.Border, error) {
+495 border, err := parseBorderShorthand(cssProperties["border"])
+496 border.Radius = cssProperties["border-radius"]
+497
+498 return border, err
+499}
+500
+501func flatten(n element.Node) []element.Node {
+502 var nodes []element.Node
+503 nodes = append(nodes, n)
+504
+505 children := n.Children
+506 if len(children) > 0 {
+507 for _, ch := range children {
+508 chNodes := flatten(ch)
+509 nodes = append(nodes, chNodes...)
+510 }
+511 }
+512 return nodes
+513}
+514
+515func genTextNode(n *element.Node, width, height *float32, p utils.MarginPadding) {
+516 wb := " "
+517
+518 if n.Style["word-wrap"] == "break-word" {
+519 wb = ""
+520 }
+521
+522 if n.Style["text-wrap"] == "wrap" || n.Style["text-wrap"] == "balance" {
+523 wb = ""
+524 }
+525
+526 letterSpacing, _ := utils.ConvertToPixels(n.Style["letter-spacing"], n.Properties.EM, *width)
+527 wordSpacing, _ := utils.ConvertToPixels(n.Style["word-spacing"], n.Properties.EM, *width)
+528
+529 var dt float32
+530
+531 if n.Style["text-decoration-thickness"] == "auto" || n.Style["text-decoration-thickness"] == "" {
+532 dt = 2
+533 } else {
+534 dt, _ = utils.ConvertToPixels(n.Style["text-decoration-thickness"], n.Properties.EM, *width)
+535 }
+536
+537 col := color.Parse(n.Style, "font")
+538
+539 n.Properties.Text.Color = col
+540 n.Properties.Text.Align = n.Style["text-align"]
+541 n.Properties.Text.WordBreak = wb
+542 n.Properties.Text.WordSpacing = int(wordSpacing)
+543 n.Properties.Text.LetterSpacing = int(letterSpacing)
+544 n.Properties.Text.WhiteSpace = n.Style["white-space"]
+545 n.Properties.Text.DecorationThickness = int(dt)
+546 n.Properties.Text.Overlined = n.Style["text-decoration"] == "overline"
+547 n.Properties.Text.Underlined = n.Style["text-decoration"] == "underline"
+548 n.Properties.Text.LineThrough = n.Style["text-decoration"] == "linethrough"
+549 n.Properties.Text.EM = int(n.Properties.EM)
+550 n.Properties.Text.Width = int(n.Parent.Properties.Width)
+551
+552 if n.Style["word-spacing"] == "" {
+553 n.Properties.Text.WordSpacing = font.MeasureSpace(&n.Properties.Text)
+554 }
+555 if n.Parent.Properties.Width != 0 && n.Style["display"] != "inline" && n.Style["width"] == "" {
+556 *width = (n.Parent.Properties.Width - p.Right) - p.Left
+557 } else if n.Style["width"] == "" {
+558 *width = utils.Max(*width, float32(font.MeasureLongest(n)))
+559 } else if n.Style["width"] != "" {
+560 *width, _ = utils.ConvertToPixels(n.Style["width"], n.Properties.EM, n.Parent.Properties.Width)
+561 }
+562
+563 n.Properties.Text.Width = int(*width)
+564 h := font.Render(n)
+565 if n.Style["height"] == "" {
+566 *height = h
+567 }
+568
+569}