about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/layout/engine.nim82
1 files changed, 35 insertions, 47 deletions
diff --git a/src/layout/engine.nim b/src/layout/engine.nim
index 66e0589b..c4328fc9 100644
--- a/src/layout/engine.nim
+++ b/src/layout/engine.nim
@@ -118,10 +118,10 @@ func px(l: CSSLength, lctx: LayoutState, p: Option[LayoutUnit]):
   return some(px(l, lctx.attrs, p.get(0)))
 
 func canpx(l: CSSLength, sc: SizeConstraint): bool =
-  return l.unit != UNIT_PERC or sc.isDefinite()
+  return not l.auto and (l.unit != UNIT_PERC or sc.isDefinite())
 
 func canpx(l: CSSLength, p: Option[LayoutUnit]): bool =
-  return l.unit != UNIT_PERC or p.isSome
+  return not l.auto and (l.unit != UNIT_PERC or p.isSome)
 
 # Note: for margins only
 # For percentages, use 0 for indefinite, and containing box's size for
@@ -910,7 +910,7 @@ proc resolveBlockWidth(sizes: var ResolvedSizes,
   let width = computed{"width"}
   let padding = sizes.padding.left + sizes.padding.right
   var widthpx: LayoutUnit = 0
-  if not width.auto and width.canpx(containingWidth):
+  if width.canpx(containingWidth):
     widthpx = width.spx(lctx, containingWidth, computed, padding)
     sizes.space.w = stretch(widthpx)
   sizes.resolveContentWidth(widthpx, containingWidth, computed, width.auto)
@@ -948,7 +948,7 @@ proc resolveBlockHeight(sizes: var ResolvedSizes,
   let height = computed{"height"}
   let padding = sizes.padding.top + sizes.padding.bottom
   var heightpx: LayoutUnit = 0
-  if not height.auto and height.canpx(percHeight):
+  if height.canpx(percHeight):
     heightpx = height.spx(lctx, percHeight, computed, padding).get
     sizes.space.h = stretch(heightpx)
   if not computed{"max-height"}.auto:
@@ -1091,7 +1091,7 @@ proc resolveFloatSizes(lctx: LayoutState, containingWidth,
   else:
     high(LayoutUnit)
   let width = computed{"width"}
-  if not width.auto and width.canpx(containingWidth):
+  if width.canpx(containingWidth):
     let widthpx = width.spx(lctx, containingWidth, computed, inlinePadding)
     space.w = stretch(clamp(widthpx, minWidth, maxWidth))
   elif containingWidth.isDefinite():
@@ -1106,7 +1106,7 @@ proc resolveFloatSizes(lctx: LayoutState, containingWidth,
   else:
     high(LayoutUnit)
   let height = computed{"height"}
-  if not height.auto and height.canpx(containingHeight):
+  if height.canpx(containingHeight):
     let heightpx = height.px(lctx, containingHeight)
     space.h = stretch(clamp(heightpx, minHeight, maxHeight))
   elif containingHeight.isDefinite():
@@ -1143,29 +1143,6 @@ proc resolveSizes(lctx: LayoutState, containingWidth,
     return lctx.resolveBlockSizes(containingWidth, containingHeight,
       percHeight, computed)
 
-proc resolveTableCellSizes(lctx: LayoutState, containingWidth,
-    containingHeight: SizeConstraint, override: bool,
-    computed: CSSComputedValues): ResolvedSizes =
-  var sizes = ResolvedSizes(
-    padding: resolvePadding(containingWidth, lctx, computed),
-    space: AvailableSpace(w: containingWidth, h: containingHeight),
-    minWidth: 0,
-    maxWidth: high(LayoutUnit),
-    minHeight: 0,
-    maxHeight: high(LayoutUnit)
-  )
-  if not override:
-    let width = computed{"width"}
-    if not width.auto and width.unit != UNIT_PERC:
-      sizes.space.w = stretch(width.px(lctx))
-  sizes.space.w.u -= sizes.padding.left
-  sizes.space.w.u -= sizes.padding.right
-  if not override:
-    let height = computed{"height"}
-    if not height.auto and height.unit != UNIT_PERC:
-      sizes.space.h = stretch(height.px(lctx))
-  return sizes
-
 func toPercSize(sc: SizeConstraint): Option[LayoutUnit] =
   if sc.isDefinite():
     return some(sc.u)
@@ -1707,11 +1684,22 @@ proc buildTableCaption(lctx: LayoutState, builder: TableCaptionBoxBuilder,
   box.size.h += bctx.marginTodo.sum()
   return box
 
-proc buildTableCell(lctx: LayoutState, builder: TableCellBoxBuilder,
-    availableWidth, availableHeight: SizeConstraint, override: bool):
-    BlockBox =
-  let sizes = lctx.resolveTableCellSizes(availableWidth, availableHeight,
-    override, builder.computed)
+proc buildTableCell(lctx: LayoutState; builder: TableCellBoxBuilder;
+    availWidth, availHeight: SizeConstraint): BlockBox =
+  var sizes = ResolvedSizes(
+    padding: resolvePadding(availWidth, lctx, builder.computed),
+    space: AvailableSpace(w: availWidth, h: availHeight),
+    minWidth: 0,
+    maxWidth: high(LayoutUnit),
+    minHeight: 0,
+    maxHeight: high(LayoutUnit)
+  )
+  if sizes.space.w.isDefinite():
+    sizes.space.w.u -= sizes.padding.left
+    sizes.space.w.u -= sizes.padding.right
+  if sizes.space.h.isDefinite():
+    sizes.space.h.u -= sizes.padding.top
+    sizes.space.h.u -= sizes.padding.bottom
   let box = BlockBox(
     computed: builder.computed,
     node: builder.node,
@@ -1776,15 +1764,17 @@ proc preBuildTableRow(pctx: var TableContext, box: TableRowBoxBuilder,
     let cellbuilder = TableCellBoxBuilder(child)
     let colspan = cellbuilder.computed{"-cha-colspan"}
     let rowspan = min(cellbuilder.computed{"-cha-rowspan"}, numrows - rowi)
-    let computedWidth = cellbuilder.computed{"width"}
-    let cw = if not computedWidth.auto:
-      stretch(computedWidth.px(pctx.lctx, pctx.space.w))
+    let availWidth = if cellbuilder.computed{"width"}.canpx(pctx.space.w):
+      stretch(cellbuilder.computed{"width"}.px(pctx.lctx, pctx.space.w))
+    else:
+      maxContent()
+    let availHeight = if cellbuilder.computed{"height"}.canpx(pctx.space.h):
+      stretch(cellbuilder.computed{"height"}.px(pctx.lctx, pctx.space.h))
     else:
       maxContent()
     #TODO specified table height should be distributed among rows.
     # Allow the table cell to use its specified width.
-    let box = pctx.lctx.buildTableCell(cellbuilder, cw, maxContent(),
-      override = false)
+    let box = pctx.lctx.buildTableCell(cellbuilder, availWidth, availHeight)
     let wrapper = CellWrapper(
       box: box,
       builder: cellbuilder,
@@ -1813,23 +1803,21 @@ proc preBuildTableRow(pctx: var TableContext, box: TableRowBoxBuilder,
       # 4. neither of colwidth or cell width are fixed: take maximum
       if ctx.reflow.len <= i: ctx.reflow.setLen(i + 1)
       if pctx.cols[i].wspecified:
-        if not computedWidth.auto:
-          let ww = computedWidth.px(pctx.lctx, pctx.space.w)
+        if availWidth.isDefinite():
           # A specified column already exists; we take the larger width.
-          if ww > pctx.cols[i].width:
-            pctx.cols[i].width = ww
+          if availWidth.u > pctx.cols[i].width:
+            pctx.cols[i].width = availWidth.u
             ctx.reflow[i] = true
         else:
           if pctx.cols[i].width < w:
             wrapper.reflow = true
       else:
-        if not computedWidth.auto:
-          let ww = computedWidth.px(pctx.lctx, pctx.space.w)
+        if availWidth.isDefinite():
           # This is the first specified column. Replace colwidth with whatever
           # we have.
           ctx.reflow[i] = true
           pctx.cols[i].wspecified = true
-          pctx.cols[i].width = ww
+          pctx.cols[i].width = availWidth.u
         else:
           if pctx.cols[i].width < w:
             pctx.cols[i].width = w
@@ -1896,7 +1884,7 @@ proc buildTableRow(pctx: TableContext, ctx: RowContext, parent: BlockBox,
       # </TABLE>
       # the TD with a width of 5ch should be 9ch wide as well.
       cellw.box = pctx.lctx.buildTableCell(cellw.builder, stretch(w),
-        maxContent(), override = true)
+        maxContent())
       w = max(w, cellw.box.size.w)
     let cell = cellw.box
     x += pctx.inlinespacing
mmit/src/layout/box.nim?id=075efc13165c5e5f24d1672c9830db53e41be1e6'>075efc13 ^
dd9cb39c ^
075efc13 ^
b2bf6774 ^

dd9cb39c ^
cc92092f ^
d54e0258 ^

77fe3c3e ^



be10c6a2 ^
77fe3c3e ^








04403976 ^
876f5e9c ^
270628aa ^

31162225 ^
d54e0258 ^
dd9cb39c ^
85ec984f ^



04403976 ^
8756b053 ^
270628aa ^
77fe3c3e ^

04403976 ^
bf3b8804 ^
b6b4e896 ^
1c6ce089 ^
1c6ce089 ^
f0b013e7 ^
270628aa ^
95c5438a ^




f9979334 ^
1c6ce089 ^
04403976 ^
062027c8 ^
b4798a6b ^
7146419b ^
062027c8 ^
ca5aea89 ^
616e60b7 ^
b9c13c00 ^
32a94cec ^
1c6ce089 ^













bf3b8804 ^
3496b5e5 ^


270628aa ^
24e908ef ^



32a94cec ^


1c6ce089 ^
32a94cec ^
95c5438a ^




062027c8 ^
7addf30a ^
b9c13c00 ^
3496b5e5 ^




























1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179

              
                     
                 
                        
                  

    
                  



                  

                  
 



                                                            
                                               








                                                                       

                                     
                       
                                
                     
 

                                              
                  

                     

                                             

                                                    



                                                
 
                                                          
 
                                                     
 
                                                      

                                                  
                                            
 

                                                         



                                                             
                   








                                      
 
                              

                            
                                           
                     
                     



                                                                           
 
                       
                           

                        
 
                             
                   
                       
                      
                        
 




                                    
                                 
                         
 
                                   
                          
                     
                          
                                
                   
 
                                       













                                   
 


                                    
 



                       


                                                                           
                          
 




                                                       
                                       
                          
 




























                                                      
import options

import css/stylednode
import css/values
import layout/layoutunit
import types/color

type
  Offset* = object
    x*: LayoutUnit
    y*: LayoutUnit

  Size* = object
    w*: LayoutUnit
    h*: LayoutUnit

  # min-content: box width is longest word's width
  # max-content: box width is content width without wrapping
  # stretch: box width is n px wide
  # fit-content: also known as shrink-to-fit, box width is
  #   min(max-content, stretch(availableWidth))
  #   in other words, as wide as needed, but wrap if wider than allowed
  # (note: I write width here, but it can apply for any constraint)
  SizeConstraintType* = enum
    STRETCH, FIT_CONTENT, MIN_CONTENT, MAX_CONTENT

  SizeConstraint* = object
    t*: SizeConstraintType
    u*: LayoutUnit

  BoxBuilder* = ref object of RootObj
    children*: seq[BoxBuilder]
    inlinelayout*: bool
    computed*: CSSComputedValues
    node*: StyledNode

  InlineBoxBuilder* = ref object of BoxBuilder
    text*: seq[string]
    newline*: bool
    splitstart*: bool
    splitend*: bool

  BlockBoxBuilder* = ref object of BoxBuilder

  MarkerBoxBuilder* = ref object of InlineBoxBuilder

  ListItemBoxBuilder* = ref object of BoxBuilder
    marker*: MarkerBoxBuilder
    content*: BlockBoxBuilder

  TableRowGroupBoxBuilder* = ref object of BlockBoxBuilder

  TableRowBoxBuilder* = ref object of BlockBoxBuilder

  TableCellBoxBuilder* = ref object of BlockBoxBuilder

  TableBoxBuilder* = ref object of BlockBoxBuilder
    rowgroups*: seq[TableRowGroupBoxBuilder]

  TableCaptionBoxBuilder* = ref object of BlockBoxBuilder

  InlineAtomType* = enum
    INLINE_SPACING, INLINE_PADDING, INLINE_WORD, INLINE_BLOCK

  InlineAtom* = ref object
    offset*: Offset
    size*: Size
    case t*: InlineAtomType
    of INLINE_SPACING, INLINE_PADDING:
      sformat*: ComputedFormat
    of INLINE_WORD:
      wformat*: ComputedFormat
      str*: string
    of INLINE_BLOCK:
      innerbox*: BlockBox

  ComputedFormat* = ref object
    fontstyle*: CSSFontStyle
    fontweight*: int
    textdecoration*: set[CSSTextDecoration]
    color*: RGBAColor
    node*: StyledNode
    #TODO: background color should not be stored in inline words. Instead,
    # inline box fragments should be passed on to the renderer, which could
    # then properly blend them.
    bgcolor*: RGBAColor

  LineBox* = ref object
    atoms*: seq[InlineAtom]
    offsety*: LayoutUnit
    size*: Size

  InlineContext* = ref object
    offset*: Offset
    height*: LayoutUnit
    width*: LayoutUnit
    lines*: seq[LineBox]

    # baseline of the first line box
    firstBaseline*: LayoutUnit
    # baseline of the last line box
    baseline*: LayoutUnit

    # this is actually xminwidth.
    minwidth*: LayoutUnit

  BlockBox* = ref object of RootObj
    inline*: InlineContext
    node*: StyledNode
    nested*: seq[BlockBox]
    computed*: CSSComputedValues
    offset*: Offset

    # This is the padding width/height.
    width*: LayoutUnit
    height*: LayoutUnit
    margin_top*: LayoutUnit
    margin_bottom*: LayoutUnit
    margin_left*: LayoutUnit
    margin_right*: LayoutUnit
    padding_top*: LayoutUnit
    padding_bottom*: LayoutUnit
    padding_left*: LayoutUnit
    padding_right*: LayoutUnit
    min_width*: Option[LayoutUnit]
    max_width*: Option[LayoutUnit]
    min_height*: Option[LayoutUnit]
    max_height*: Option[LayoutUnit]

    # width and height constraints
    availableWidth*: SizeConstraint
    availableHeight*: SizeConstraint

    positioned*: bool
    x_positioned*: bool
    y_positioned*: bool

    # very bad name. basically the minimum content width after the contents
    # have been positioned (usually the width of the shortest word.) used
    # in table cells.
    xminwidth*: LayoutUnit

    # baseline of the first line box of all descendants
    firstBaseline*: LayoutUnit
    # baseline of the last line box of all descendants
    baseline*: LayoutUnit

  ListItemBox* = ref object of BlockBox
    marker*: InlineContext

func minContent*(): SizeConstraint =
  return SizeConstraint(t: MIN_CONTENT)

func maxContent*(): SizeConstraint =
  return SizeConstraint(t: MAX_CONTENT)

func stretch*(u: LayoutUnit): SizeConstraint =
  return SizeConstraint(t: STRETCH, u: u)

func fitContent*(u: LayoutUnit): SizeConstraint =
  return SizeConstraint(t: FIT_CONTENT, u: u)

#TODO ?
func stretch*(sc: SizeConstraint): SizeConstraint =
  case sc.t
  of MIN_CONTENT, MAX_CONTENT:
    return SizeConstraint(t: sc.t, u: sc.u)
  of STRETCH, FIT_CONTENT:
    return SizeConstraint(t: STRETCH, u: sc.u)

func fitContent*(sc: SizeConstraint): SizeConstraint =
  case sc.t
  of MIN_CONTENT, MAX_CONTENT:
    return SizeConstraint(t: sc.t)
  of STRETCH, FIT_CONTENT:
    return SizeConstraint(t: FIT_CONTENT, u: sc.u)

func isDefinite*(sc: SizeConstraint): bool =
  return sc.t in {STRETCH, FIT_CONTENT}