about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/css/values.nim25
-rw-r--r--src/layout/engine.nim51
2 files changed, 60 insertions, 16 deletions
diff --git a/src/css/values.nim b/src/css/values.nim
index 4d7c3e28..2a5b85eb 100644
--- a/src/css/values.nim
+++ b/src/css/values.nim
@@ -40,7 +40,7 @@ type
     PROPERTY_COUNTER_RESET, PROPERTY_MAX_WIDTH, PROPERTY_MAX_HEIGHT,
     PROPERTY_MIN_WIDTH, PROPERTY_MIN_HEIGHT, PROPERTY_BACKGROUND_IMAGE,
     PROPERTY_CHA_COLSPAN, PROPERTY_CHA_ROWSPAN, PROPERTY_FLOAT,
-    PROPERTY_VISIBILITY
+    PROPERTY_VISIBILITY, PROPERTY_BOX_SIZING
 
   CSSValueType* = enum
     VALUE_NONE, VALUE_LENGTH, VALUE_COLOR, VALUE_CONTENT, VALUE_DISPLAY,
@@ -48,7 +48,8 @@ type
     VALUE_WORD_BREAK, VALUE_LIST_STYLE_TYPE, VALUE_VERTICAL_ALIGN,
     VALUE_TEXT_ALIGN, VALUE_LIST_STYLE_POSITION, VALUE_POSITION,
     VALUE_CAPTION_SIDE, VALUE_LENGTH2, VALUE_BORDER_COLLAPSE, VALUE_QUOTES,
-    VALUE_COUNTER_RESET, VALUE_IMAGE, VALUE_FLOAT, VALUE_VISIBILITY
+    VALUE_COUNTER_RESET, VALUE_IMAGE, VALUE_FLOAT, VALUE_VISIBILITY,
+    VALUE_BOX_SIZING
 
   CSSGlobalValueType* = enum
     VALUE_NOGLOBAL, VALUE_INITIAL, VALUE_INHERIT, VALUE_REVERT, VALUE_UNSET
@@ -123,6 +124,9 @@ type
   CSSVisibility* = enum
     VISIBILITY_VISIBLE, VISIBILITY_HIDDEN, VISIBILITY_COLLAPSE
 
+  CSSBoxSizing* = enum
+    BOX_SIZING_CONTENT_BOX, BOX_SIZING_BORDER_BOX
+
 const RowGroupBox* = {DISPLAY_TABLE_ROW_GROUP, DISPLAY_TABLE_HEADER_GROUP,
                       DISPLAY_TABLE_FOOTER_GROUP}
 const ProperTableChild* = {DISPLAY_TABLE_ROW, DISPLAY_TABLE_COLUMN,
@@ -204,6 +208,8 @@ type
       float*: CSSFloat
     of VALUE_VISIBILITY:
       visibility*: CSSVisibility
+    of VALUE_BOX_SIZING:
+      boxsizing*: CSSBoxSizing
     of VALUE_NONE: discard
 
   CSSComputedValues* = ref array[CSSPropertyType, CSSComputedValue]
@@ -277,7 +283,8 @@ const PropertyNames = {
   "-cha-colspan": PROPERTY_CHA_COLSPAN,
   "-cha-rowspan": PROPERTY_CHA_ROWSPAN,
   "float": PROPERTY_FLOAT,
-  "visibility": PROPERTY_VISIBILITY
+  "visibility": PROPERTY_VISIBILITY,
+  "box-sizing": PROPERTY_BOX_SIZING
 }.toTable()
 
 const ValueTypes* = [
@@ -325,7 +332,8 @@ const ValueTypes* = [
   PROPERTY_CHA_COLSPAN: VALUE_INTEGER,
   PROPERTY_CHA_ROWSPAN: VALUE_INTEGER,
   PROPERTY_FLOAT: VALUE_FLOAT,
-  PROPERTY_VISIBILITY: VALUE_VISIBILITY
+  PROPERTY_VISIBILITY: VALUE_VISIBILITY,
+  PROPERTY_BOX_SIZING: VALUE_BOX_SIZING
 ]
 
 const InheritedProperties = {
@@ -1059,6 +1067,13 @@ func cssVisibility(cval: CSSComponentValue): Result[CSSVisibility, string] =
   }
   return cssIdent(VisibilityMap, cval)
 
+func cssBoxSizing(cval: CSSComponentValue): Result[CSSBoxSizing, string] =
+  const BoxSizingMap = {
+    "border-box": BOX_SIZING_BORDER_BOX,
+    "content-box": BOX_SIZING_CONTENT_BOX
+  }
+  return cssIdent(BoxSizingMap, cval)
+
 proc getValueFromDecl(val: CSSComputedValue, d: CSSDeclaration,
     vtype: CSSValueType, ptype: CSSPropertyType): Err[string] =
   var i = 0
@@ -1135,6 +1150,8 @@ proc getValueFromDecl(val: CSSComputedValue, d: CSSDeclaration,
     val.float = ?cssFloat(cval)
   of VALUE_VISIBILITY:
     val.visibility = ?cssVisibility(cval)
+  of VALUE_BOX_SIZING:
+    val.boxsizing = ?cssBoxSizing(cval)
   of VALUE_NONE:
     discard
   return ok()
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index ce46361d..98c60f57 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -795,10 +795,16 @@ proc resolveBlockWidth(sizes: var ResolvedSizes,
   var widthpx: LayoutUnit = 0
   if not width.auto and width.canpx(containingWidth):
     widthpx = width.px(lctx, containingWidth)
+    if computed{"box-sizing"} == BOX_SIZING_BORDER_BOX:
+      widthpx = widthpx - sizes.padding.left - sizes.padding.right
+    widthpx = max(widthpx, 0)
     sizes.space.w = stretch(widthpx)
   sizes.resolveContentWidth(widthpx, containingWidth, computed, width.auto)
   if not computed{"max-width"}.auto:
-    let max_width = computed{"max-width"}.px(lctx, containingWidth)
+    var max_width = computed{"max-width"}.px(lctx, containingWidth)
+    if computed{"box-sizing"} == BOX_SIZING_BORDER_BOX:
+      max_width = max_width - sizes.padding.left - sizes.padding.right
+    max_width = max(max_width, 0)
     sizes.max_width = some(max_width)
     if sizes.space.w.t in {STRETCH, FIT_CONTENT} and
         max_width < sizes.space.w.u or
@@ -812,7 +818,10 @@ proc resolveBlockWidth(sizes: var ResolvedSizes,
         sizes.space.w = fitContent(max_width)
       sizes.resolveContentWidth(max_width, containingWidth, computed)
   if not computed{"min-width"}.auto:
-    let min_width = computed{"min-width"}.px(lctx, containingWidth)
+    var min_width = computed{"min-width"}.px(lctx, containingWidth)
+    if computed{"box-sizing"} == BOX_SIZING_BORDER_BOX:
+      min_width = min_width - sizes.padding.left - sizes.padding.right
+    min_width = max(min_width, 0)
     sizes.min_width = some(min_width)
     if sizes.space.w.t in {STRETCH, FIT_CONTENT} and
         min_width > sizes.space.w.u or
@@ -832,28 +841,40 @@ proc resolveBlockHeight(sizes: var ResolvedSizes,
   var heightpx: LayoutUnit = 0
   if not height.auto and height.canpx(percHeight):
     heightpx = height.px(lctx, percHeight).get
+    if computed{"box-sizing"} == BOX_SIZING_BORDER_BOX:
+      heightpx = heightpx - sizes.padding.top - sizes.padding.bottom
+    heightpx = max(heightpx, 0)
     sizes.space.h = stretch(heightpx)
   if not computed{"max-height"}.auto:
-    let max_height = computed{"max-height"}.px(lctx, percHeight)
+    var max_height = computed{"max-height"}.px(lctx, percHeight)
     sizes.max_height = max_height
     if max_height.isSome:
+      var max_height = max_height.get
+      if computed{"box-sizing"} == BOX_SIZING_BORDER_BOX:
+        max_height = max_height - sizes.padding.top - sizes.padding.bottom
+      sizes.max_height = some(max(max_height, 0))
       if sizes.space.h.t in {STRETCH, FIT_CONTENT} and
-          max_height.get < sizes.space.h.u or
+          max_height < sizes.space.h.u or
           sizes.space.h.t == MAX_CONTENT:
         # same reasoning as for width.
         if sizes.space.h.t == STRETCH:
-          sizes.space.h = stretch(max_height.get)
+          sizes.space.h = stretch(max_height)
         else: # FIT_CONTENT
-          sizes.space.h = fitContent(max_height.get)
+          sizes.space.h = fitContent(max_height)
   if not computed{"min-height"}.auto:
-    let min_height = computed{"min-height"}.px(lctx, percHeight)
+    var min_height = computed{"min-height"}.px(lctx, percHeight)
+    min_height = min_height
     if min_height.isSome:
-      sizes.min_height = min_height
+      var min_height = min_height.get
+      if computed{"box-sizing"} == BOX_SIZING_BORDER_BOX:
+        min_height = min_height - sizes.padding.top - sizes.padding.bottom
+      min_height = max(min_height, 0)
+      sizes.min_height = some(min_height)
       if sizes.space.h.t in {STRETCH, FIT_CONTENT} and
-          min_height.get > sizes.space.h.u or
+          min_height > sizes.space.h.u or
           sizes.space.h.t == MIN_CONTENT:
         # same reasoning as for width.
-        sizes.space.h = stretch(min_height.get)
+        sizes.space.h = stretch(min_height)
 
 proc resolveAbsoluteWidth(sizes: var ResolvedSizes,
     containingWidth: SizeConstraint, computed: CSSComputedValues,
@@ -880,7 +901,10 @@ proc resolveAbsoluteWidth(sizes: var ResolvedSizes,
       # solve left/right yet.
       sizes.space.w = fitContent(containingWidth)
   else:
-    let widthpx = width.px(lctx, containingWidth)
+    var widthpx = width.px(lctx, containingWidth)
+    if computed{"box-sizing"} == BOX_SIZING_BORDER_BOX:
+      widthpx = widthpx - sizes.padding.left - sizes.padding.right
+    widthpx = max(widthpx, 0)
     # We could solve for left/right here, as available width is known.
     # Nevertheless, it is only needed for positioning, so we do not solve
     # them yet.
@@ -910,7 +934,10 @@ proc resolveAbsoluteHeight(sizes: var ResolvedSizes,
     else:
       sizes.space.h = fitContent(containingHeight)
   else:
-    let heightpx = height.px(lctx, containingHeight)
+    var heightpx = height.px(lctx, containingHeight)
+    if computed{"box-sizing"} == BOX_SIZING_BORDER_BOX:
+      heightpx = heightpx - sizes.padding.top - sizes.padding.bottom
+    heightpx = max(heightpx, 0)
     sizes.space.h = stretch(heightpx)
 
 proc resolveBlockSizes(lctx: LayoutState, containingWidth,