about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--res/quirk.css10
-rw-r--r--res/ua.css32
-rw-r--r--src/css/cascade.nim44
-rw-r--r--src/css/values.nim23
-rw-r--r--src/layout/engine.nim6
-rw-r--r--src/render/renderdocument.nim7
-rw-r--r--src/types/color.nim45
7 files changed, 143 insertions, 24 deletions
diff --git a/res/quirk.css b/res/quirk.css
new file mode 100644
index 00000000..0515f028
--- /dev/null
+++ b/res/quirk.css
@@ -0,0 +1,10 @@
+
+table {
+	font-weight: initial;
+	font-style: initial;
+	font-variant: initial;
+	font-size: initial;
+	line-height: initial;
+	white-space: initial;
+	text-align: initial;
+}
diff --git a/res/ua.css b/res/ua.css
index 920232d7..3c2b4daa 100644
--- a/res/ua.css
+++ b/res/ua.css
@@ -46,6 +46,26 @@ colgroup {
 	display: table-column-group;
 }
 
+tr {
+	display: table-row;
+}
+
+col {
+	display: table-column;
+}
+
+th {
+	display: table-cell;
+	font-weight: bold;
+	vertical-align: inherit;
+}
+
+td {
+	display: table-cell;
+	text-align: unset;
+	vertical-align: inherit;
+}
+
 input {
 	margin-right: 1ch;
 	white-space: pre;
@@ -92,18 +112,6 @@ input:is([type="submit"], [type="button"], [type="reset"])::after {
 	color: red;
 }
 
-tr {
-	display: table-row;
-}
-
-col {
-	display: table-column;
-}
-
-th, td {
-	display: table-cell;
-}
-
 li {
 	display: list-item;
 }
diff --git a/src/css/cascade.nim b/src/css/cascade.nim
index bb4872fd..bc8db4d7 100644
--- a/src/css/cascade.nim
+++ b/src/css/cascade.nim
@@ -1,4 +1,5 @@
 import algorithm
+import options
 import streams
 import sugar
 
@@ -11,6 +12,7 @@ import css/stylednode
 import css/values
 import html/dom
 import html/tags
+import types/color
 
 type
   DeclarationList* = array[PseudoElem, seq[CSSDeclaration]]
@@ -68,6 +70,44 @@ func calcRules(styledNode: StyledNode, sheet: CSSStylesheet): DeclarationList =
       for item in tosorts[i]:
         for dl in item[1]:
           dl
+
+func calcPresentationalHints(element: Element): CSSComputedValues =
+  template set_cv(a, b, c: untyped) =
+    if result == nil:
+      new(result)
+    result[a] = CSSComputedValue(t: a, v: ValueTypes[a], b: c)
+  template map_width =
+    let s = parseDimensionValues(element.attr("width"))
+    if s.isSome:
+      set_cv(PROPERTY_WIDTH, length, s.get)
+  template map_height =
+    let s = parseDimensionValues(element.attr("height"))
+    if s.isSome:
+      set_cv(PROPERTY_HEIGHT, length, s.get)
+  template map_width_nozero =
+    let s = parseDimensionValues(element.attr("width"))
+    if s.isSome and s.get.num != 0:
+      set_cv(PROPERTY_WIDTH, length, s.get)
+  template map_height_nozero =
+    let s = parseDimensionValues(element.attr("height"))
+    if s.isSome and s.get.num != 0:
+      set_cv(PROPERTY_HEIGHT, length, s.get)
+  template map_bgcolor =
+    let c = parseLegacyColor(element.attr("bgcolor"))
+    if c.isSome:
+      set_cv(PROPERTY_BACKGROUND_COLOR, color, c.get)
+
+  case element.tagType
+  of TAG_TABLE, TAG_TD, TAG_TH:
+    map_height_nozero
+    map_width_nozero
+    map_bgcolor
+  of TAG_THEAD, TAG_TBODY, TAG_TFOOT, TAG_TR:
+    map_height
+    map_bgcolor
+  of TAG_COL:
+    map_width
+  else: discard
  
 proc applyDeclarations(styledNode: StyledNode, parent: CSSComputedValues, ua, user: DeclarationList, author: seq[DeclarationList]) =
   let pseudo = PSEUDO_NONE
@@ -78,10 +118,12 @@ proc applyDeclarations(styledNode: StyledNode, parent: CSSComputedValues, ua, us
   for rule in author:
     builder.addValues(rule[pseudo], ORIGIN_AUTHOR)
   if styledNode.node != nil:
-    let style = Element(styledNode.node).attr("style")
+    let element = Element(styledNode.node)
+    let style = element.attr("style")
     if style.len > 0:
       let inline_rules = newStringStream(style).parseListOfDeclarations2()
       builder.addValues(inline_rules, ORIGIN_AUTHOR)
+    builder.preshints = element.calcPresentationalHints()
 
   styledNode.computed = builder.buildComputedValues()
 
diff --git a/src/css/values.nim b/src/css/values.nim
index 67200532..1e82fe3c 100644
--- a/src/css/values.nim
+++ b/src/css/values.nim
@@ -87,9 +87,7 @@ type
     unit*: CSSUnit
     auto*: bool
 
-  CSSColor* = object
-    rgba*: RGBAColor
-    termcolor: int
+  CSSColor* = RGBAColor
 
   CSSVerticalAlign* = object
     length*: CSSLength
@@ -143,6 +141,7 @@ type
     parent: CSSComputedValues
     normalProperties: array[CSSOrigin, CSSComputedValueBuilders]
     importantProperties: array[CSSOrigin, CSSComputedValueBuilders]
+    preshints*: CSSComputedValues
 
   CSSValueError* = object of ValueError
 
@@ -177,7 +176,7 @@ const PropertyNames = {
   "background-color": PROPERTY_BACKGROUND_COLOR,
 }.toTable()
 
-const ValueTypes = [
+const ValueTypes* = [
   PROPERTY_NONE: VALUE_NONE,
   PROPERTY_ALL: VALUE_NONE,
   PROPERTY_COLOR: VALUE_COLOR,
@@ -293,8 +292,8 @@ func listMarker*(t: CSSListStyleType, i: int): string =
 
 const Colors: Table[string, CSSColor] = ((func (): Table[string, CSSColor] =
   for name, rgb in ColorsRGB:
-    result[name] = CSSColor(rgba: rgb)
-  result["transparent"] = CSSColor(rgba: rgba(0x00, 0x00, 0x00, 0x00))
+    result[name] = CSSColor(rgb)
+  result["transparent"] = CSSColor(rgba(0x00, 0x00, 0x00, 0x00))
 )())
 
 const Units = {
@@ -346,10 +345,10 @@ func parseDimensionValues*(s: string): Option[CSSLength] =
   return some(CSSLength(num: n, unit: UNIT_PX))
 
 func color(r, g, b: int): CSSColor =
-  return CSSColor(rgba: rgba(r, g, b, 256))
+  return CSSColor(rgba(r, g, b, 256))
 
 func color(r, g, b, a: int): CSSColor =
-  return CSSColor(rgba: rgba(r, g, b, a))
+  return CSSColor(rgba(r, g, b, a))
 
 func cssColor(d: CSSDeclaration): CSSColor =
   if d.value.len > 0:
@@ -359,7 +358,7 @@ func cssColor(d: CSSDeclaration): CSSColor =
       of CSS_HASH_TOKEN:
         let c = parseHexColor(tok.value)
         if c.isSome:
-          return CSSColor(rgba: c.get)
+          return CSSColor(c.get)
         else:
           raise newException(CSSValueError, "Invalid color")
       of CSS_IDENT_TOKEN:
@@ -400,7 +399,7 @@ func cssColor(d: CSSDeclaration): CSSColor =
   raise newException(CSSValueError, "Invalid color")
 
 func cellColor*(color: CSSColor): CellColor =
-  return CellColor(rgb: true, rgbcolor: RGBColor(color.rgba))
+  return CellColor(rgb: true, rgbcolor: RGBColor(color))
 
 func isToken(d: CSSDeclaration): bool {.inline.} = d.value.len > 0 and d.value[0] of CSSToken
 
@@ -854,6 +853,10 @@ func buildComputedValues*(builder: CSSComputedValuesBuilder): CSSComputedValues
       result.buildComputedValue(builder.parent, nil, build)
     # important, so no need to save origins
   # set defaults
+  if builder.preshints != nil:
+    for prop in CSSPropertyType:
+      if result[prop] == nil:
+        result[prop] = builder.preshints[prop]
   for prop in CSSPropertyType:
     if result[prop] == nil:
       if inherited(prop) and builder.parent != nil and builder.parent[prop] != nil:
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index 1f2fef98..0fa1c156 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -856,10 +856,12 @@ proc generateFromElem(styledNode: StyledNode, blockgroup: var BlockGroup, viewpo
 
   case styledNode.computed{"display"}
   of DISPLAY_BLOCK:
+    flush_ibox
     blockgroup.flush()
     let childbox = styledNode.generateBlockBox(viewport)
     box.children.add(childbox)
   of DISPLAY_LIST_ITEM:
+    flush_ibox
     blockgroup.flush()
     let childbox = getListItemBox(styledNode.computed, blockgroup.listItemCounter)
     if childbox.computed{"list-style-position"} == LIST_STYLE_POSITION_INSIDE:
@@ -878,18 +880,22 @@ proc generateFromElem(styledNode: StyledNode, blockgroup: var BlockGroup, viewpo
     childbox.content = styledNode.generateBlockBox(viewport)
     blockgroup.add(childbox)
   of DISPLAY_TABLE:
+    flush_ibox
     blockgroup.flush()
     let childbox = styledNode.generateTableBox(viewport)
     box.children.add(childbox)
   of DISPLAY_TABLE_ROW:
+    flush_ibox
     blockgroup.flush()
     let childbox = styledNode.generateTableRowBox(viewport)
     box.children.add(childbox)
   of DISPLAY_TABLE_ROW_GROUP:
+    flush_ibox
     blockgroup.flush()
     let childbox = styledNode.generateTableRowGroupBox(viewport)
     box.children.add(childbox)
   of DISPLAY_TABLE_CELL:
+    flush_ibox
     blockgroup.flush()
     let childbox = styledNode.generateTableCellBox(viewport)
     box.children.add(childbox)
diff --git a/src/render/renderdocument.nim b/src/render/renderdocument.nim
index e1342dbb..a039cc71 100644
--- a/src/render/renderdocument.nim
+++ b/src/render/renderdocument.nim
@@ -270,7 +270,7 @@ proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockBox, x, y: int, window
     x += ctx.offset.x
     y += ctx.offset.y
 
-    if ctx.computed{"background-color"}.rgba.a != 0: #TODO color blending
+    if ctx.computed{"background-color"}.a != 0: #TODO color blending
       grid.paintBackground(ctx.computed{"background-color"}, x, y, x + ctx.width, y + ctx.height, window)
 
     if ctx of ListItemBox:
@@ -287,7 +287,12 @@ proc renderBlockContext(grid: var FlexibleGrid, ctx: BlockBox, x, y: int, window
 
 const css = staticRead"res/ua.css"
 let uastyle = css.parseStylesheet()
+const quirk = css & staticRead"res/quirk.css"
+let quirkstyle = quirk.parseStylesheet()
 proc renderDocument*(document: Document, window: WindowAttributes, userstyle: CSSStylesheet, layout: var Viewport, previousStyled: StyledNode): (FlexibleGrid, StyledNode) =
+  var uastyle = uastyle
+  if document.mode == QUIRKS:
+    uastyle = quirkstyle
   let styledNode = document.applyStylesheets(uastyle, userstyle, previousStyled)
   result[1] = styledNode
   layout.renderLayout(document, styledNode)
diff --git a/src/types/color.nim b/src/types/color.nim
index 9d3994ff..e85a254e 100644
--- a/src/types/color.nim
+++ b/src/types/color.nim
@@ -1,5 +1,6 @@
 import options
 import sequtils
+import strutils
 import sugar
 import tables
 
@@ -242,6 +243,50 @@ func parseRGBAColor*(s: string): Option[RGBAColor] =
     return parseHexColor(s[2..^1])
   return parseHexColor(s)
 
+func parseLegacyColor*(s: string): Option[RGBColor] =
+  if s == "": return
+  let s = s.strip(chars = AsciiWhitespace)
+  if s == "transparent": return
+  if s in ColorsRGB:
+    return some(ColorsRGB[s])
+  block hex:
+    if s.len == 4:
+      for c in s:
+        if hexValue(c) == -1:
+          break hex
+      let c = (hexValue(s[0]) * 17 shl 16) or
+        (hexValue(s[1]) * 17 shl 8) or
+        (hexValue(s[2]) * 17)
+      return some(RGBColor(c))
+  block sane:
+    var c: Option[RGBAColor]
+    for c in s:
+      if hexValue(c) == -1:
+        break sane
+    if s[0] == '#' and s.len == 8:
+      c = parseHexColor(s[1..^1])
+    elif s.len == 8:
+      c = parseHexColor(s)
+    else:
+      break sane
+    if c.isSome:
+      return some(RGBColor(c.get))
+  # Seriously, what the hell.
+  var s2 = if s[0] == '#':
+    s.substr(1)
+  else:
+    s
+  while s2.len == 0 or s2.len mod 3 != 0:
+    s2 &= '0'
+  var l = s2.len div 3
+  let c1 = s2[0..<min(l,2)]
+  let c2 = s2[l..<min(l*2,l+2)]
+  let c3 = s2[l*2..<min(l*3,l*2+2)]
+  let c = (hexValue(c1[0]) shl 20) or (hexValue(c1[1]) shl 16) or
+          (hexValue(c2[0]) shl 12) or (hexValue(c2[1]) shl 8) or
+          (hexValue(c3[0]) shl 4) or hexValue(c3[1])
+  return some(RGBColor(c))
+
 func r*(c: RGBAColor): int =
   return int(c) shr 16 and 0xff