about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/css/cascade.nim9
-rw-r--r--src/css/cssvalues.nim110
-rw-r--r--src/css/layout.nim59
-rw-r--r--src/css/mediaquery.nim8
-rw-r--r--src/css/render.nim7
5 files changed, 102 insertions, 91 deletions
diff --git a/src/css/cascade.nim b/src/css/cascade.nim
index 0c26e67e..47e7fcfa 100644
--- a/src/css/cascade.nim
+++ b/src/css/cascade.nim
@@ -147,7 +147,7 @@ func calcPresentationalHints(element: Element): CSSComputedValues =
   template map_size =
     let s = element.attrul(satSize)
     if s.isSome:
-      set_cv "width", CSSLength(num: float64(s.get), unit: cuCh)
+      set_cv "width", CSSLength(num: float64(s.get), u: cuCh)
   template map_text =
     let s = element.attr(satText)
     if s != "":
@@ -207,8 +207,8 @@ func calcPresentationalHints(element: Element): CSSComputedValues =
     let textarea = HTMLTextAreaElement(element)
     let cols = textarea.attrul(satCols).get(20)
     let rows = textarea.attrul(satRows).get(1)
-    set_cv "width", CSSLength(unit: cuCh, num: float64(cols))
-    set_cv "height", CSSLength(unit: cuEm, num: float64(rows))
+    set_cv "width", CSSLength(u: cuCh, num: float64(cols))
+    set_cv "height", CSSLength(u: cuEm, num: float64(rows))
   of TAG_FONT:
     map_color
   of TAG_INPUT:
@@ -405,10 +405,8 @@ proc applyRulesFrameInvalid(frame: CascadeFrame; ua, user: CSSStylesheet;
         styledText.pseudo = pseudo
         styledParent.children.add(styledText)
     of peImage:
-      let src = Element(styledParent.node).attr(satSrc)
       let content = CSSContent(
         t: ContentImage,
-        s: src,
         bmp: HTMLImageElement(styledParent.node).bitmap
       )
       let styledText = styledParent.newStyledReplacement(content, pseudo)
@@ -418,7 +416,6 @@ proc applyRulesFrameInvalid(frame: CascadeFrame; ua, user: CSSStylesheet;
       if bmp != nil and bmp.cacheId != 0:
         let content = CSSContent(
           t: ContentImage,
-          s: "canvas://",
           bmp: bmp
         )
         let styledText = styledParent.newStyledReplacement(content, pseudo)
diff --git a/src/css/cssvalues.nim b/src/css/cssvalues.nim
index 1715511c..b89e1dad 100644
--- a/src/css/cssvalues.nim
+++ b/src/css/cssvalues.nim
@@ -27,6 +27,7 @@ type
     cstFlexFlow = "flex-flow"
 
   CSSUnit* = enum
+    cuAuto = ""
     cuCm = "cm"
     cuMm = "mm"
     cuIn = "in"
@@ -134,7 +135,7 @@ type
     cvtOverflow = "overflow"
 
   CSSGlobalType = enum
-    cgtNoglobal = ""
+    cgtNone = ""
     cgtInitial = "initial"
     cgtInherit = "inherit"
     cgtRevert = "revert"
@@ -252,9 +253,9 @@ type
     BorderCollapseCollapse = "collapse"
 
   CSSContentType* = enum
-    ContentString, ContentOpenQuote, ContentCloseQuote,
-    ContentNoOpenQuote, ContentNoCloseQuote, ContentImage,
-    ContentVideo, ContentAudio, ContentNewline
+    ContentNone, ContentString, ContentOpenQuote, ContentCloseQuote,
+    ContentNoOpenQuote, ContentNoCloseQuote, ContentImage, ContentVideo,
+    ContentAudio, ContentNewline
 
   CSSFloat* = enum
     FloatNone = "none"
@@ -307,18 +308,21 @@ type
 
 type
   CSSLength* = object
+    u*: CSSUnit
     num*: float64
-    unit*: CSSUnit
-    auto*: bool
 
   CSSVerticalAlign* = object
-    length*: CSSLength
     keyword*: CSSVerticalAlign2
+    # inlined CSSLength so that this object fits into 2 words
+    u*: CSSUnit
+    num*: float64
 
   CSSContent* = object
-    t*: CSSContentType
-    s*: string
-    bmp*: NetworkBitmap
+    case t*: CSSContentType
+    of ContentImage:
+      bmp*: NetworkBitmap
+    else:
+      s*: string
 
   CSSQuotes* = object
     auto*: bool
@@ -328,6 +332,10 @@ type
     name*: string
     num*: int
 
+  CSSLength2* = ref object
+    a*: CSSLength
+    b*: CSSLength
+
   CSSComputedValue* = ref object
     case v*: CSSValueType
     of cvtColor:
@@ -365,7 +373,7 @@ type
     of cvtCaptionSide:
       captionSide*: CSSCaptionSide
     of cvtLength2:
-      length2*: tuple[a, b: CSSLength]
+      length2*: CSSLength2
     of cvtBorderCollapse:
       borderCollapse*: CSSBorderCollapse
     of cvtCounterReset:
@@ -486,9 +494,9 @@ func isSupportedProperty*(s: string): bool =
   return propertyType(s) != cptNone
 
 func `$`*(length: CSSLength): string =
-  if length.auto:
+  if length.u == cuAuto:
     return "auto"
-  return $length.num & $length.unit
+  return $length.num & $length.u
 
 func `$`*(content: CSSContent): string =
   if content.s != "":
@@ -575,7 +583,8 @@ func ex_to_px(ex: float64; window: WindowAttributes): LayoutUnit =
   (ex * float64(window.ppc) / 2).toLayoutUnit()
 
 func px*(l: CSSLength; window: WindowAttributes; p: LayoutUnit): LayoutUnit =
-  case l.unit
+  return case l.u
+  of cuAuto: LayoutUnit(0)
   of cuEm, cuRem: em_to_px(l.num, window)
   of cuCh: ch_to_px(l.num, window)
   of cuIc: ic_to_px(l.num, window)
@@ -788,11 +797,11 @@ func parseIdent[T: enum](cval: CSSComponentValue): Opt[T] =
     return ok(T(i))
   return err()
 
-func cssLength(val: float64; unit: string): Opt[CSSLength] =
-  let u = ?parseEnumNoCase[CSSUnit](unit)
-  return ok(CSSLength(num: val, unit: u))
+func cssLength(val: float64; u: string): Opt[CSSLength] =
+  let u = ?parseEnumNoCase[CSSUnit](u)
+  return ok(CSSLength(num: val, u: u))
 
-const CSSLengthAuto* = CSSLength(auto: true)
+const CSSLengthAuto* = CSSLength(u: cuAuto)
 
 func parseDimensionValues*(s: string): Option[CSSLength] =
   var i = s.skipBlanks(0)
@@ -804,19 +813,19 @@ func parseDimensionValues*(s: string): Option[CSSLength] =
     n += float64(decValue(s[i]))
     inc i
     if i >= s.len:
-      return some(CSSLength(num: n, unit: cuPx))
+      return some(CSSLength(num: n, u: cuPx))
   if s[i] == '.':
     inc i
     if i >= s.len:
-      return some(CSSLength(num: n, unit: cuPx))
+      return some(CSSLength(num: n, u: cuPx))
     var d = 1
     while i < s.len and s[i] in AsciiDigit:
       n += float64(decValue(s[i])) / float64(d)
       inc d
       inc i
   if i < s.len and s[i] == '%':
-    return some(CSSLength(num: n, unit: cuPerc))
-  return some(CSSLength(num: n, unit: cuPx))
+    return some(CSSLength(num: n, u: cuPerc))
+  return some(CSSLength(num: n, u: cuPx))
 
 func skipWhitespace(vals: openArray[CSSComponentValue]; i: var int) =
   while i < vals.len:
@@ -937,7 +946,7 @@ func cssLength*(val: CSSComponentValue; has_auto = true; allow_negative = true):
     case tok.tokenType
     of cttNumber:
       if tok.nvalue == 0:
-        return ok(CSSLength(num: 0, unit: cuPx))
+        return ok(CSSLength(num: 0, u: cuPx))
     of cttPercentage:
       if not allow_negative:
         if tok.nvalue < 0:
@@ -961,7 +970,7 @@ func cssAbsoluteLength(val: CSSComponentValue): Opt[CSSLength] =
     case tok.tokenType
     of cttNumber:
       if tok.nvalue == 0:
-        return ok(CSSLength(num: 0, unit: cuPx))
+        return ok(CSSLength(num: 0, u: cuPx))
     of cttDimension:
       if tok.nvalue >= 0:
         return cssLength(tok.nvalue, tok.unit)
@@ -969,7 +978,7 @@ func cssAbsoluteLength(val: CSSComponentValue): Opt[CSSLength] =
   return err()
 
 func cssGlobal(cval: CSSComponentValue): CSSGlobalType =
-  return parseIdent[CSSGlobalType](cval).get(cgtNoglobal)
+  return parseIdent[CSSGlobalType](cval).get(cgtNone)
 
 func cssQuotes(cvals: openArray[CSSComponentValue]): Opt[CSSQuotes] =
   template die =
@@ -1067,9 +1076,11 @@ func cssVerticalAlign(cval: CSSComponentValue): Opt[CSSVerticalAlign] =
       let va2 = ?parseIdent[CSSVerticalAlign2](cval)
       return ok(CSSVerticalAlign(keyword: va2))
     else:
+      let length = ?cssLength(tok, has_auto = false)
       return ok(CSSVerticalAlign(
         keyword: VerticalAlignBaseline,
-        length: ?cssLength(tok, has_auto = false)
+        u: length.u,
+        num: length.num
       ))
   return err()
 
@@ -1138,10 +1149,11 @@ func cssImage(cval: CSSComponentValue): Opt[CSSContent] =
     #TODO bg-image only
     let tok = getToken(cval)
     if tok.tokenType == cttIdent and tok.value.equalsIgnoreCase("none"):
-      return ok(CSSContent(t: ContentImage, s: ""))
+      return ok(CSSContent(t: ContentNone))
   let url = cssURL(cval)
   if url.isSome:
-    return ok(CSSContent(t: ContentImage, s: url.get))
+    #TODO do something with the URL
+    return ok(CSSContent(t: ContentImage))
   return err()
 
 func cssInteger(cval: CSSComponentValue; range: Slice[int]): Opt[int] =
@@ -1209,7 +1221,7 @@ proc parseValue(cvals: openArray[CSSComponentValue]; t: CSSPropertyType):
     let a = ?cssAbsoluteLength(cval)
     cvals.skipWhitespace(i)
     let b = if i >= cvals.len: a else: ?cssAbsoluteLength(cvals[i])
-    return_new length2, (a, b)
+    return_new length2, CSSLength2(a: a, b: b)
   of cvtQuotes: return_new quotes, ?cssQuotes(cvals)
   of cvtCounterReset: return_new counterReset, ?cssCounterReset(cvals)
   of cvtImage: return_new image, ?cssImage(cval)
@@ -1238,7 +1250,7 @@ func getInitialLength(t: CSSPropertyType): CSSLength =
       cptMaxHeight, cptMinWidth, cptMinHeight, cptFlexBasis:
     return CSSLengthAuto
   else:
-    return CSSLength(auto: false, unit: cuPx, num: 0)
+    return CSSLength(u: cuPx, num: 0)
 
 func getInitialInteger(t: CSSPropertyType): int =
   case t
@@ -1290,7 +1302,7 @@ func lengthShorthand(cvals: openArray[CSSComponentValue];
     props: array[4, CSSPropertyType]; global: CSSGlobalType; has_auto = true):
     Opt[seq[CSSComputedEntry]] =
   var res: seq[CSSComputedEntry] = @[]
-  if global != cgtNoglobal:
+  if global != cgtNone:
     for t in props:
       res.add((t, nil, global))
     return ok(res)
@@ -1305,10 +1317,10 @@ func lengthShorthand(cvals: openArray[CSSComponentValue];
   case lengths.len
   of 1: # top, bottom, left, right
     for i, t in props:
-      res.add((t, lengths[0], cgtNoglobal))
+      res.add((t, lengths[0], cgtNone))
   of 2: # top, bottom | left, right
     for i, t in props:
-      res.add((t, lengths[i mod 2], cgtNoglobal))
+      res.add((t, lengths[i mod 2], cgtNone))
   of 3: # top | left, right | bottom
     for i, t in props:
       let j = if i == 0:
@@ -1317,10 +1329,10 @@ func lengthShorthand(cvals: openArray[CSSComponentValue];
         2 # bottom
       else:
         1 # left, right
-      res.add((t, lengths[j], cgtNoglobal))
+      res.add((t, lengths[j], cgtNone))
   of 4: # top | right | bottom | left
     for i, t in props:
-      res.add((t, lengths[i], cgtNoglobal))
+      res.add((t, lengths[i], cgtNone))
   else:
     return err()
   return ok(res)
@@ -1343,12 +1355,12 @@ proc parseComputedValues*(res: var seq[CSSComputedEntry]; name: string;
   case shorthandType(name)
   of cstNone:
     let t = propertyType(name)
-    if global != cgtNoglobal:
+    if global != cgtNone:
       res.add((t, nil, global))
     else:
       res.add((t, ?cvals.parseValue(t), global))
   of cstAll:
-    if global == cgtNoglobal:
+    if global == cgtNone:
       return err()
     for t in CSSPropertyType:
       res.add((t, nil, global))
@@ -1361,7 +1373,7 @@ proc parseComputedValues*(res: var seq[CSSComputedEntry]; name: string;
     var bgcolorval = getDefault(cptBackgroundColor)
     var bgimageval = getDefault(cptBackgroundImage)
     var valid = true
-    if global == cgtNoglobal:
+    if global == cgtNone:
       for tok in cvals:
         if tok == cttWhitespace:
           continue
@@ -1380,7 +1392,7 @@ proc parseComputedValues*(res: var seq[CSSComputedEntry]; name: string;
     var positionVal = getDefault(cptListStylePosition)
     var typeVal = getDefault(cptListStyleType)
     var valid = true
-    if global == cgtNoglobal:
+    if global == cgtNone:
       for tok in cvals:
         if tok == cttWhitespace:
           continue
@@ -1402,7 +1414,7 @@ proc parseComputedValues*(res: var seq[CSSComputedEntry]; name: string;
       res.add((cptListStylePosition, positionVal, global))
       res.add((cptListStyleType, typeVal, global))
   of cstFlex:
-    if global == cgtNoglobal:
+    if global == cgtNone:
       var i = 0
       cvals.skipWhitespace(i)
       if i >= cvals.len:
@@ -1435,7 +1447,7 @@ proc parseComputedValues*(res: var seq[CSSComputedEntry]; name: string;
       else: # omitted, default to 0px
         let val = CSSComputedValue(
           v: cvtLength,
-          length: CSSLength(unit: cuPx, num: 0)
+          length: CSSLength(u: cuPx, num: 0)
         )
         res.add((cptFlexBasis, val, global))
     else:
@@ -1443,7 +1455,7 @@ proc parseComputedValues*(res: var seq[CSSComputedEntry]; name: string;
       res.add((cptFlexShrink, getDefault(cptFlexShrink), global))
       res.add((cptFlexBasis, getDefault(cptFlexBasis), global))
   of cstFlexFlow:
-    if global == cgtNoglobal:
+    if global == cgtNone:
       var i = 0
       cvals.skipWhitespace(i)
       if i >= cvals.len:
@@ -1472,14 +1484,10 @@ proc parseComputedValues*(name: string; value: seq[CSSComponentValue]):
 
 proc applyValue*(vals: CSSComputedValues; entry: CSSComputedEntry;
     parent, previousOrigin: CSSComputedValues) =
-  let parentVal = if parent != nil:
-    parent[entry.t]
-  else:
-    nil
   case entry.global
   of cgtInherit:
-    if parentVal != nil:
-      vals[entry.t] = parentVal
+    if parent != nil:
+      vals[entry.t] = parent[entry.t]
     else:
       vals[entry.t] = getDefault(entry.t)
   of cgtInitial:
@@ -1487,8 +1495,8 @@ proc applyValue*(vals: CSSComputedValues; entry: CSSComputedEntry;
   of cgtUnset:
     if inherited(entry.t):
       # inherit
-      if parentVal != nil:
-        vals[entry.t] = parentVal
+      if parent != nil:
+        vals[entry.t] = parent[entry.t]
       else:
         vals[entry.t] = getDefault(entry.t)
     else:
@@ -1499,7 +1507,7 @@ proc applyValue*(vals: CSSComputedValues; entry: CSSComputedEntry;
       vals[entry.t] = previousOrigin[entry.t]
     else:
       vals[entry.t] = getDefault(entry.t)
-  of cgtNoglobal:
+  of cgtNone:
     vals[entry.t] = entry.val
 
 func inheritProperties*(parent: CSSComputedValues): CSSComputedValues =
diff --git a/src/css/layout.nim b/src/css/layout.nim
index 39047178..7033b636 100644
--- a/src/css/layout.nim
+++ b/src/css/layout.nim
@@ -139,13 +139,13 @@ func px(l: CSSLength; lctx: LayoutContext; p: LayoutUnit = 0):
   return px(l, lctx.attrs, p)
 
 func canpx(l: CSSLength; sc: SizeConstraint): bool =
-  return not l.auto and (l.unit != cuPerc or sc.isDefinite())
+  return l.u != cuAuto and (l.u != cuPerc or sc.isDefinite())
 
 # Note: for margins only
 # For percentages, use 0 for indefinite, and containing box's size for
 # definite.
 func px(l: CSSLength; lctx: LayoutContext; p: SizeConstraint): LayoutUnit =
-  if l.unit == cuPerc:
+  if l.u == cuPerc:
     case p.t
     of scMinContent, scMaxContent:
       return 0
@@ -642,7 +642,8 @@ func getBaseline(ictx: InlineContext; iastate: InlineAtomState;
     atom: InlineAtom): LayoutUnit =
   return case iastate.vertalign.keyword
   of VerticalAlignBaseline:
-    let len = iastate.vertalign.length.px(ictx.lctx, ictx.cellHeight)
+    let length = CSSLength(u: iastate.vertalign.u, num: iastate.vertalign.num)
+    let len = length.px(ictx.lctx, ictx.cellHeight)
     iastate.baseline + len
   of VerticalAlignTop, VerticalAlignBottom:
     atom.size.h
@@ -882,11 +883,14 @@ proc resolveContentWidth(sizes: var ResolvedSizes; widthpx: LayoutUnit;
     else:
       sizes.margin[dtHorizontal].send += underflow
   elif underflow > 0:
-    if not computed{"margin-left"}.auto and not computed{"margin-right"}.auto:
+    if computed{"margin-left"}.u != cuAuto and
+        computed{"margin-right"}.u != cuAuto:
       sizes.margin[dtHorizontal].send += underflow
-    elif not computed{"margin-left"}.auto and computed{"margin-right"}.auto:
+    elif computed{"margin-left"}.u != cuAuto and
+        computed{"margin-right"}.u == cuAuto:
       sizes.margin[dtHorizontal].send = underflow
-    elif computed{"margin-left"}.auto and not computed{"margin-right"}.auto:
+    elif computed{"margin-left"}.u == cuAuto and
+        computed{"margin-right"}.u != cuAuto:
       sizes.margin[dtHorizontal].start = underflow
     else:
       sizes.margin[dtHorizontal].start = underflow div 2
@@ -967,7 +971,7 @@ proc resolveBlockWidth(sizes: var ResolvedSizes; parentWidth: SizeConstraint;
   if width.canpx(parentWidth):
     widthpx = width.spx(lctx, parentWidth, computed, inlinePadding)
     sizes.space.w = stretch(widthpx)
-  sizes.resolveContentWidth(widthpx, parentWidth, computed, width.auto)
+  sizes.resolveContentWidth(widthpx, parentWidth, computed, width.u == cuAuto)
   if sizes.space.w.isDefinite() and sizes.maxWidth < sizes.space.w.u or
       sizes.maxWidth < LayoutUnit.high and sizes.space.w.t == scMaxContent:
     if sizes.space.w.t == scStretch:
@@ -1011,9 +1015,9 @@ const CvalSizeMap = [dtHorizontal: cptWidth, dtVertical: cptHeight]
 proc resolveAbsoluteWidth(sizes: var ResolvedSizes; size: Size;
     positioned: RelativeRect; computed: CSSComputedValues;
     lctx: LayoutContext) =
-  if computed{"width"}.auto:
+  if computed{"width"}.u == cuAuto:
     let u = max(size.w - positioned[dtHorizontal].sum(), 0)
-    if not computed{"left"}.auto and not computed{"right"}.auto:
+    if computed{"left"}.u != cuAuto and computed{"right"}.u != cuAuto:
       # Both left and right are known, so we can calculate the width.
       sizes.space.w = stretch(u)
     else:
@@ -1027,9 +1031,9 @@ proc resolveAbsoluteWidth(sizes: var ResolvedSizes; size: Size;
 proc resolveAbsoluteHeight(sizes: var ResolvedSizes; size: Size;
     positioned: RelativeRect; computed: CSSComputedValues;
     lctx: LayoutContext) =
-  if computed{"height"}.auto:
+  if computed{"height"}.u == cuAuto:
     let u = max(size.w - positioned[dtVertical].sum(), 0)
-    if not computed{"top"}.auto and not computed{"bottom"}.auto:
+    if computed{"top"}.u != cuAuto and computed{"bottom"}.u != cuAuto:
       # Both top and bottom are known, so we can calculate the height.
       sizes.space.h = stretch(u)
     else:
@@ -1269,15 +1273,15 @@ proc popPositioned(lctx: LayoutContext; overflow: var Overflow; size: Size) =
       # the available width, and we must re-layout.
       sizes.space.w = stretch(child.state.xminwidth)
       marginBottom = lctx.layoutRootBlock(child, it.offset, sizes)
-    if not child.computed{"left"}.auto:
+    if child.computed{"left"}.u != cuAuto:
       child.state.offset.x = positioned.left + sizes.margin.left
-    elif not child.computed{"right"}.auto:
+    elif child.computed{"right"}.u != cuAuto:
       child.state.offset.x = size.w - positioned.right - child.state.size.w -
         sizes.margin.right
     # margin.left is added in layoutRootBlock
-    if not child.computed{"top"}.auto:
+    if child.computed{"top"}.u != cuAuto:
       child.state.offset.y = positioned.top + sizes.margin.top
-    elif not child.computed{"bottom"}.auto:
+    elif child.computed{"bottom"}.u != cuAuto:
       child.state.offset.y = size.h - positioned.bottom - child.state.size.h -
         sizes.margin.bottom
     else:
@@ -1613,8 +1617,8 @@ proc addInlineImage(ictx: var InlineContext; state: var InlineState;
     # parent size yet. e.g. <img width=100% ...> with an indefinite containing
     # size (i.e. the first table cell pass) would resolve to an xminwidth of
     # image.width, stretching out the table to an uncomfortably large size.
-    if ictx.space.w.isDefinite() or computed{"width"}.unit != cuPerc and
-        computed{"min-width"}.unit != cuPerc:
+    if ictx.space.w.isDefinite() or computed{"width"}.u != cuPerc and
+        computed{"min-width"}.u != cuPerc:
       ictx.state.xminwidth = max(ictx.state.xminwidth, atom.size.w)
 
 proc layoutInline(ictx: var InlineContext; fragment: InlineFragment) =
@@ -1682,14 +1686,14 @@ proc layoutInline(ictx: var InlineContext; fragment: InlineFragment) =
 
 proc positionRelative(lctx: LayoutContext; parent, box: BlockBox) =
   let positioned = lctx.resolvePositioned(parent.state.size, box.computed)
-  if not box.computed{"left"}.auto:
+  if box.computed{"left"}.u != cuAuto:
     box.state.offset.x += positioned.left
-  elif not box.computed{"right"}.auto:
+  elif box.computed{"right"}.u != cuAuto:
     box.state.offset.x += parent.state.size.w - box.state.size.w -
       positioned.right
-  if not box.computed{"top"}.auto:
+  if box.computed{"top"}.u != cuAuto:
     box.state.offset.y += positioned.top
-  elif not box.computed{"bottom"}.auto:
+  elif box.computed{"bottom"}.u != cuAuto:
     box.state.offset.y += parent.state.size.h - box.state.size.h -
       positioned.bottom
 
@@ -2038,8 +2042,8 @@ func needsRedistribution(tctx: TableContext; computed: CSSComputedValues):
   of scStretch:
     return tctx.space.w.u != tctx.maxwidth
   of scFitContent:
-    let u = tctx.space.w.u
-    return u > tctx.maxwidth and not computed{"width"}.auto or u < tctx.maxwidth
+    return tctx.space.w.u > tctx.maxwidth and computed{"width"}.u != cuAuto or
+        tctx.space.w.u < tctx.maxwidth
 
 proc redistributeWidth(tctx: var TableContext) =
   # Remove inline spacing from distributable width.
@@ -2140,8 +2144,10 @@ proc layoutTable(tctx: var TableContext; table: BlockBox;
     sizes: ResolvedSizes) =
   let lctx = tctx.lctx
   if table.computed{"border-collapse"} != BorderCollapseCollapse:
-    tctx.inlineSpacing = table.computed{"border-spacing"}.a.px(lctx)
-    tctx.blockSpacing = table.computed{"border-spacing"}.b.px(lctx)
+    let spc = table.computed{"border-spacing"}
+    if spc != nil:
+      tctx.inlineSpacing = table.computed{"border-spacing"}.a.px(lctx)
+      tctx.blockSpacing = table.computed{"border-spacing"}.b.px(lctx)
   tctx.preLayoutTableRows(table) # first pass
   if tctx.needsRedistribution(table.computed):
     tctx.redistributeWidth()
@@ -2353,7 +2359,7 @@ proc layoutFlex(bctx: var BlockContext; box: BlockBox; sizes: ResolvedSizes) =
     var childSizes = lctx.resolveFlexItemSizes(sizes.space, dim, child.computed)
     let flexBasis = child.computed{"flex-basis"}
     lctx.layoutFlexChild(child, childSizes)
-    if not flexBasis.auto and sizes.space[dim].isDefinite:
+    if flexBasis.u != cuAuto and sizes.space[dim].isDefinite:
       # we can't skip this pass; it is needed to calculate the minimum
       # height.
       let minu = child.state.minFlexItemSize(dim)
@@ -3079,6 +3085,7 @@ proc buildFromElem(ctx: var InnerBlockContext; styledNode: StyledNode;
 proc buildReplacement(ctx: var InnerBlockContext; child, parent: StyledNode;
     computed: CSSComputedValues) =
   case child.content.t
+  of ContentNone: assert false # unreachable for `content'
   of ContentOpenQuote:
     let quotes = parent.computed{"quotes"}
     var text: string = ""
diff --git a/src/css/mediaquery.nim b/src/css/mediaquery.nim
index 73649e8f..f86ea197 100644
--- a/src/css/mediaquery.nim
+++ b/src/css/mediaquery.nim
@@ -254,10 +254,10 @@ proc parseLengthRange(parser: var MediaQueryParser; ismin, ismax: bool):
     Opt[LengthRange] =
   if ismin:
     let a = ?parser.parseLength()
-    let b = CSSLength(num: Inf, unit: cuPx)
+    let b = CSSLength(num: Inf, u: cuPx)
     return ok(LengthRange(s: a .. b, aeq: true, beq: false))
   if ismax:
-    let a = CSSLength(num: 0, unit: cuPx)
+    let a = CSSLength(num: 0, u: cuPx)
     let b = ?parser.parseLength()
     return ok(LengthRange(s: a .. b, aeq: false, beq: true))
   let comparison = ?parser.parseComparison()
@@ -267,10 +267,10 @@ proc parseLengthRange(parser: var MediaQueryParser; ismin, ismax: bool):
   of mqcEq:
     return ok(LengthRange(s: len .. len, aeq: true, beq: true))
   of mqcGt, mqcGe:
-    let b = CSSLength(num: Inf, unit: cuPx)
+    let b = CSSLength(num: Inf, u: cuPx)
     return ok(LengthRange(s: len .. b, aeq: comparison == mqcGe, beq: false))
   of mqcLt, mqcLe:
-    let a = CSSLength(num: 0, unit: cuPx)
+    let a = CSSLength(num: 0, u: cuPx)
     return ok(LengthRange(s: a .. len, aeq: false, beq: comparison == mqcLe))
 
 proc parseFeature0(parser: var MediaQueryParser; t: MediaFeatureType;
diff --git a/src/css/render.nim b/src/css/render.nim
index 9688ff30..8e8185dc 100644
--- a/src/css/render.nim
+++ b/src/css/render.nim
@@ -392,9 +392,9 @@ proc renderBlockBox(grid: var FlexibleGrid; state: var RenderState;
     return
   var offset = offset
   if position in {PositionAbsolute, PositionFixed}:
-    if not box.computed{"left"}.auto or not box.computed{"right"}.auto:
+    if box.computed{"left"}.u != cuAuto or box.computed{"right"}.u != cuAuto:
       offset.x = state.absolutePos[^1].x
-    if not box.computed{"top"}.auto or not box.computed{"bottom"}.auto:
+    if box.computed{"top"}.u != cuAuto or box.computed{"bottom"}.u != cuAuto:
       offset.y = state.absolutePos[^1].y
   offset += box.state.offset
   box.render.offset = offset
@@ -415,8 +415,7 @@ proc renderBlockBox(grid: var FlexibleGrid; state: var RenderState;
       let iex = toInt(e.x)
       let iey = toInt(e.y)
       grid.paintBackground(state, bgcolor, ix, iy, iex, iey, box.node)
-    if box.computed{"background-image"}.t == ContentImage and
-        box.computed{"background-image"}.s != "":
+    if box.computed{"background-image"}.t == ContentImage:
       # ugly hack for background-image display... TODO actually display images
       let s = "[img]"
       let w = s.len * state.attrs.ppc