diff options
-rw-r--r-- | res/quirk.css | 10 | ||||
-rw-r--r-- | res/ua.css | 32 | ||||
-rw-r--r-- | src/css/cascade.nim | 44 | ||||
-rw-r--r-- | src/css/values.nim | 23 | ||||
-rw-r--r-- | src/layout/engine.nim | 6 | ||||
-rw-r--r-- | src/render/renderdocument.nim | 7 | ||||
-rw-r--r-- | src/types/color.nim | 45 |
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 |