| 1 |
lars |
1 |
% Definition of float context "class"
|
|
|
2 |
|
|
|
3 |
/context-add-absolute-positioned { % => Box Context
|
|
|
4 |
dup /AbsolutePositioned get % => Box Context AB
|
|
|
5 |
2 index exch
|
|
|
6 |
array-prepend % => Box Context AB'
|
|
|
7 |
/AbsolutePositioned exch put % => Box
|
|
|
8 |
pop
|
|
|
9 |
} def
|
|
|
10 |
|
|
|
11 |
/context-add-fixed-positioned { % => Box Context
|
|
|
12 |
dup /FixedPositioned get % => Box Context AB
|
|
|
13 |
2 index exch
|
|
|
14 |
array-prepend % => Box Context AB'
|
|
|
15 |
/FixedPositioned exch put % => Box
|
|
|
16 |
pop
|
|
|
17 |
} def
|
|
|
18 |
|
|
|
19 |
/context-add-float { % => Float Context
|
|
|
20 |
dup /Floats get % => Float Context Floats
|
|
|
21 |
dup 0 get % => Float Context Floats Floats[0]
|
|
|
22 |
3 index exch array-prepend % => Float Context Floats Floats[0]'
|
|
|
23 |
|
|
|
24 |
pop pop
|
|
|
25 |
} def
|
|
|
26 |
|
|
|
27 |
/context-container-uid { % => Context
|
|
|
28 |
/ContainerUID get 0 get
|
|
|
29 |
} def
|
|
|
30 |
|
|
|
31 |
/context-create { % =>
|
|
|
32 |
<<
|
|
|
33 |
/ContainerUID [1]
|
|
|
34 |
/AbsolutePositioned []
|
|
|
35 |
/FixedPositioned []
|
|
|
36 |
/Floats [[]]
|
|
|
37 |
/Margin [0 0]
|
|
|
38 |
/Viewport []
|
|
|
39 |
>>
|
|
|
40 |
} def
|
|
|
41 |
|
|
|
42 |
% Find the minimal X at the given Y coordinate suitable for float placement
|
|
|
43 |
%
|
|
|
44 |
/context-float-left-x { % => Y X Context
|
|
|
45 |
3 copy dup
|
|
|
46 |
context-floats % => Y X Context Y X Context Floats
|
|
|
47 |
context-float-left-x-rec % => Y X Context X
|
|
|
48 |
|
|
|
49 |
% Clear the stack
|
|
|
50 |
exch pop
|
|
|
51 |
exch pop
|
|
|
52 |
exch pop
|
|
|
53 |
} def
|
|
|
54 |
|
|
|
55 |
/context-float-left-x-rec { % => Y X Context Floats
|
|
|
56 |
dup length 0 gt {
|
|
|
57 |
dup 0 get % => Y X Context Floats Float
|
|
|
58 |
|
|
|
59 |
dup /float get-css-value
|
|
|
60 |
/left eq {
|
|
|
61 |
|
|
|
62 |
% Check if this float contains given Y-coordinate
|
|
|
63 |
%
|
|
|
64 |
% Note that top margin coordinate is inclusive but
|
|
|
65 |
% bottom margin coordinate is exclusive! The cause is following:
|
|
|
66 |
% - if we have several floats in one line, their top margin edge Y coordinates will be equal,
|
|
|
67 |
% so we must use agreater or equal sign to avod placing all floats at one X coordinate
|
|
|
68 |
% - on the other side, if we place one float under the other, the top margin Y coordinate
|
|
|
69 |
% of bottom float will be equal to bottom margin Y coordinate of the top float and
|
|
|
70 |
% we should NOT offset tho bottom float in this case
|
|
|
71 |
|
|
|
72 |
dup get-top-margin % => Y X Context Floats Float FTM
|
|
|
73 |
rounding-epsilon add
|
|
|
74 |
5 index % => Y X Context Floats Float FTM Y
|
|
|
75 |
ge % => Y X Context Floats Float FTM>=Y
|
|
|
76 |
|
|
|
77 |
1 index get-bottom-margin % => Y X Context Floats Float FTM>=Y FBM
|
|
|
78 |
6 index % => Y X Context Floats Float FTM>=Y FBM Y
|
|
|
79 |
lt % => Y X Context Floats Float FTM>=Y FBM<Y
|
|
|
80 |
|
|
|
81 |
and { % => Y X Context Floats Float
|
|
|
82 |
dup get-right-margin % => Y X Context Floats Float FRM
|
|
|
83 |
4 index max % => Y X Context Floats Float X'=MAX(FRM,X)
|
|
|
84 |
exch pop % => Y X Context Floats X'
|
|
|
85 |
4 3 roll pop % => Y Context Floats X'
|
|
|
86 |
3 1 roll % => Y X' Context Floats
|
|
|
87 |
array-pop-first
|
|
|
88 |
context-float-left-x-rec % => X
|
|
|
89 |
} {
|
|
|
90 |
pop
|
|
|
91 |
array-pop-first
|
|
|
92 |
context-float-left-x-rec
|
|
|
93 |
} ifelse
|
|
|
94 |
} {
|
|
|
95 |
pop
|
|
|
96 |
array-pop-first
|
|
|
97 |
context-float-left-x-rec
|
|
|
98 |
} ifelse
|
|
|
99 |
} {
|
|
|
100 |
% no more floats
|
|
|
101 |
pop pop exch pop
|
|
|
102 |
} ifelse
|
|
|
103 |
} def % => X
|
|
|
104 |
|
|
|
105 |
% Calculates position of left floating box (taking into account the possibility
|
|
|
106 |
% of "wrapping" float to next line in case we have not enough space at current level (Y coordinate)
|
|
|
107 |
%
|
|
|
108 |
% @param parent reference to a parent box
|
|
|
109 |
% @param width width of float being placed. Full width! so, extra horizontal space (padding, margins and borders) is added here too
|
|
|
110 |
% @param $y Starting Y-coordinate
|
|
|
111 |
% @return X X coordinate of float upper-left corner
|
|
|
112 |
% @return Y Y coordinate of float upper-left corner
|
|
|
113 |
%
|
|
|
114 |
/context-float-left-xy { % => Parent Width Y Context
|
|
|
115 |
% Prepare information about the float bottom corrdinates
|
|
|
116 |
dup context-floats % => Parent Width Y Context Floats
|
|
|
117 |
make-sorted-bottom-y-list % => Parent Width Y Context FloatBottoms
|
|
|
118 |
|
|
|
119 |
context-float-left-xy-rec % => Y X
|
|
|
120 |
} def % => Y X
|
|
|
121 |
|
|
|
122 |
/context-float-left-xy-rec { % => Parent Width Y Context FloatBottoms
|
|
|
123 |
4 index get-left
|
|
|
124 |
3 index % => Parent Width Y Context FloatBottoms X Y
|
|
|
125 |
exch % => Parent Width Y Context FloatBottoms Y X
|
|
|
126 |
3 index
|
|
|
127 |
context-float-left-x % => Parent Width Y Context FloatBottoms X
|
|
|
128 |
|
|
|
129 |
% Check if current float will fit into the parent box
|
|
|
130 |
dup 5 index add % => Parent Width Y Context FloatBottoms X FloatRight
|
|
|
131 |
6 index get-right
|
|
|
132 |
rounding-epsilon add
|
|
|
133 |
le { % => Parent Width Y Context FloatBottoms X
|
|
|
134 |
% will fit
|
|
|
135 |
exch pop % => Parent Width Y Context X
|
|
|
136 |
exch pop % => Parent Width Y X
|
|
|
137 |
4 2 roll % => Y X Parent Width
|
|
|
138 |
pop pop exch % => X Y
|
|
|
139 |
} {
|
|
|
140 |
pop % => Parent Width Y Context FloatBottoms
|
|
|
141 |
% Check if all floats have been already cleared
|
|
|
142 |
dup length 0 eq {
|
|
|
143 |
% All floats are cleared; fall back to the leftmost X coordinate
|
|
|
144 |
pop pop exch pop % => Parent Y
|
|
|
145 |
exch % => Y Parent
|
|
|
146 |
get-left exch % => X Y
|
|
|
147 |
} {
|
|
|
148 |
% No, float does not fit at current level, let's try to 'clear' some previous floats
|
|
|
149 |
dup 0 get % => Parent Width Y Context FloatBottoms Bottom0
|
|
|
150 |
3 index min % => Parent Width Y Context FloatBottoms Y'
|
|
|
151 |
4 3 roll pop % => Parent Width Context FloatBottoms Y'
|
|
|
152 |
3 1 roll
|
|
|
153 |
array-pop-first % => Parent Width Y' Context FloatBottoms'
|
|
|
154 |
context-float-left-xy-rec % => X Y
|
|
|
155 |
} ifelse
|
|
|
156 |
} ifelse
|
|
|
157 |
} def % => X Y
|
|
|
158 |
|
|
|
159 |
% Find the minimal X at the given Y coordinate suitable for float placement
|
|
|
160 |
%
|
|
|
161 |
/context-float-right-x { % => Y X Context
|
|
|
162 |
3 copy dup
|
|
|
163 |
context-floats % => Y X Context Y X Context Floats
|
|
|
164 |
context-float-right-x-rec % => Y X Context X
|
|
|
165 |
|
|
|
166 |
% Clear the stack
|
|
|
167 |
exch pop
|
|
|
168 |
exch pop
|
|
|
169 |
exch pop
|
|
|
170 |
} def
|
|
|
171 |
|
|
|
172 |
/context-float-right-x-rec { % => Y X Context Floats
|
|
|
173 |
dup length 0 gt {
|
|
|
174 |
dup 0 get % => Y X Context Floats Float
|
|
|
175 |
|
|
|
176 |
dup /float get-css-value
|
|
|
177 |
/right eq {
|
|
|
178 |
|
|
|
179 |
% Check if this float contains given Y-coordinate
|
|
|
180 |
%
|
|
|
181 |
% Note that top margin coordinate is inclusive but
|
|
|
182 |
% bottom margin coordinate is exclusive! The cause is following:
|
|
|
183 |
% - if we have several floats in one line, their top margin edge Y coordinates will be equal,
|
|
|
184 |
% so we must use agreater or equal sign to avod placing all floats at one X coordinate
|
|
|
185 |
% - on the other side, if we place one float under the other, the top margin Y coordinate
|
|
|
186 |
% of bottom float will be equal to bottom margin Y coordinate of the top float and
|
|
|
187 |
% we should NOT offset tho bottom float in this case
|
|
|
188 |
|
|
|
189 |
dup get-top-margin % => Y X Context Floats Float FTM
|
|
|
190 |
rounding-epsilon add
|
|
|
191 |
5 index % => Y X Context Floats Float FTM Y
|
|
|
192 |
ge % => Y X Context Floats Float FTM>=Y
|
|
|
193 |
|
|
|
194 |
1 index get-bottom-margin % => Y X Context Floats Float FTM>=Y FBM
|
|
|
195 |
6 index % => Y X Context Floats Float FTM>=Y FBM Y
|
|
|
196 |
lt % => Y X Context Floats Float FTM>=Y FBM<Y
|
|
|
197 |
|
|
|
198 |
and { % => Y X Context Floats Float
|
|
|
199 |
dup get-left-margin % => Y X Context Floats Float FRM
|
|
|
200 |
4 index min % => Y X Context Floats Float X'=MAX(FRM,X)
|
|
|
201 |
exch pop % => Y X Context Floats X'
|
|
|
202 |
4 3 roll pop % => Y Context Floats X'
|
|
|
203 |
3 1 roll % => Y X' Context Floats
|
|
|
204 |
array-pop-first
|
|
|
205 |
context-float-right-x-rec % => X
|
|
|
206 |
} { % => Y X Context Floats Float
|
|
|
207 |
pop % => Y X Context Floats
|
|
|
208 |
array-pop-first
|
|
|
209 |
context-float-right-x-rec % => X
|
|
|
210 |
} ifelse
|
|
|
211 |
} {
|
|
|
212 |
pop
|
|
|
213 |
array-pop-first
|
|
|
214 |
context-float-right-x-rec
|
|
|
215 |
} ifelse
|
|
|
216 |
} {
|
|
|
217 |
% no more floats
|
|
|
218 |
pop pop exch pop
|
|
|
219 |
} ifelse
|
|
|
220 |
} def % => X
|
|
|
221 |
|
|
|
222 |
% Calculates position of left floating box (taking into account the possibility
|
|
|
223 |
% of "wrapping" float to next line in case we have not enough space at current level (Y coordinate)
|
|
|
224 |
%
|
|
|
225 |
% @param parent reference to a parent box
|
|
|
226 |
% @param width width of float being placed. Full width! so, extra horizontal space (padding, margins and borders) is added here too
|
|
|
227 |
% @param $y Starting Y-coordinate
|
|
|
228 |
% @return X X coordinate of float upper-left corner
|
|
|
229 |
% @return Y Y coordinate of float upper-left corner
|
|
|
230 |
%
|
|
|
231 |
/context-float-right-xy { % => Parent Width Y Context
|
|
|
232 |
% Prepare information about the float bottom corrdinates
|
|
|
233 |
dup context-floats % => Parent Width Y Context Floats
|
|
|
234 |
make-sorted-bottom-y-list % => Parent Width Y Context FloatBottoms
|
|
|
235 |
|
|
|
236 |
context-float-right-xy-rec % => X Y
|
|
|
237 |
} def % => X Y
|
|
|
238 |
|
|
|
239 |
/context-float-right-xy-rec { % => Parent Width Y Context FloatBottoms
|
|
|
240 |
4 index get-right
|
|
|
241 |
3 index % => Parent Width Y Context FloatBottoms X Y
|
|
|
242 |
exch
|
|
|
243 |
3 index
|
|
|
244 |
context-float-right-x % => Parent Width Y Context FloatBottoms X
|
|
|
245 |
|
|
|
246 |
% Check if current float will fit into the parent box
|
|
|
247 |
dup % => Parent Width Y Context FloatBottoms X X
|
|
|
248 |
6 index get-right
|
|
|
249 |
rounding-epsilon add % => Parent Width Y Context FloatBottoms X X FRight
|
|
|
250 |
le { % => Parent Width Y Context FloatBottoms X
|
|
|
251 |
% will fit
|
|
|
252 |
exch pop exch pop % => Parent Width Y X
|
|
|
253 |
4 2 roll % => Y X Parent Width
|
|
|
254 |
pop pop exch % => X Y
|
|
|
255 |
} {
|
|
|
256 |
pop % => Parent Width Y Context FloatBottoms
|
|
|
257 |
% Check if all floats have been already cleared
|
|
|
258 |
dup length 0 eq {
|
|
|
259 |
% All floats are cleared; fall back to the leftmost X coordinate
|
|
|
260 |
pop pop exch pop % => Parent Y
|
|
|
261 |
exch % => Y Parent
|
|
|
262 |
get-left exch % => X Y
|
|
|
263 |
} {
|
|
|
264 |
% No, float does not fit at current level, let's try to 'clear' some previous floats
|
|
|
265 |
dup 0 get % => Parent Width Y Context FloatBottoms Bottom0
|
|
|
266 |
3 index min % => Parent Width Y Context FloatBottoms Y'
|
|
|
267 |
4 3 roll pop % => Parent Width Context FloatBottoms Y'
|
|
|
268 |
3 1 roll
|
|
|
269 |
array-pop-first % => Parent Width Y' Context FloatBottoms'
|
|
|
270 |
context-float-left-xy-rec % => X Y
|
|
|
271 |
} ifelse
|
|
|
272 |
} ifelse
|
|
|
273 |
} def % => X Y
|
|
|
274 |
|
|
|
275 |
/context-floats { % => Context
|
|
|
276 |
/Floats get 0 get
|
|
|
277 |
} def
|
|
|
278 |
|
|
|
279 |
/context-get-absolute-positioned { % => Context
|
|
|
280 |
/AbsolutePositioned get
|
|
|
281 |
} def
|
|
|
282 |
|
|
|
283 |
/context-get-collapsed-margin { % => Context
|
|
|
284 |
/Margin get 0 get
|
|
|
285 |
} def
|
|
|
286 |
|
|
|
287 |
/context-get-fixed-positioned { % => Context
|
|
|
288 |
/FixedPositioned get
|
|
|
289 |
} def
|
|
|
290 |
|
|
|
291 |
/context-get-viewport { % => Context
|
|
|
292 |
/Viewport get 0 get
|
|
|
293 |
} def
|
|
|
294 |
|
|
|
295 |
/context-point-in-floats { % => Y X Context
|
|
|
296 |
/null % => Y X Context /null
|
|
|
297 |
1 index context-floats % => Y X Context /null Floats
|
|
|
298 |
{ % => Y X Context /null Float
|
|
|
299 |
4 index
|
|
|
300 |
4 index
|
|
|
301 |
2 index
|
|
|
302 |
box-generic-contains-point-margin { % => Y X Context /null Float
|
|
|
303 |
exch pop
|
|
|
304 |
exit % => Y X Context Float
|
|
|
305 |
} if
|
|
|
306 |
pop
|
|
|
307 |
} forall % => Y X Context Float
|
|
|
308 |
|
|
|
309 |
exch pop
|
|
|
310 |
exch pop
|
|
|
311 |
exch pop
|
|
|
312 |
} def
|
|
|
313 |
|
|
|
314 |
/context-pop { % => Context
|
|
|
315 |
dup context-pop-collapsed-margin
|
|
|
316 |
dup context-pop-floats
|
|
|
317 |
pop
|
|
|
318 |
} def
|
|
|
319 |
|
|
|
320 |
/context-pop-collapsed-margin { % => Context
|
|
|
321 |
dup /Margin get % => Context CMT
|
|
|
322 |
array-pop-first % => Context CMT'
|
|
|
323 |
/Margin exch put % =>
|
|
|
324 |
} def
|
|
|
325 |
|
|
|
326 |
/context-pop-container-uid { % => Context
|
|
|
327 |
dup /ContainerUID get
|
|
|
328 |
array-pop-first
|
|
|
329 |
/ContainerUID exch put
|
|
|
330 |
} def
|
|
|
331 |
|
|
|
332 |
/context-pop-floats { % => Context
|
|
|
333 |
dup /Floats get
|
|
|
334 |
array-pop-first
|
|
|
335 |
/Floats exch put
|
|
|
336 |
} def
|
|
|
337 |
|
|
|
338 |
/context-pop-viewport { % => Context
|
|
|
339 |
dup /Viewport get
|
|
|
340 |
array-pop-first % => Context Viewports
|
|
|
341 |
/Viewport exch put % =>
|
|
|
342 |
} def
|
|
|
343 |
|
|
|
344 |
/context-push { % => Context
|
|
|
345 |
|
|
|
346 |
dup context-push-floats
|
|
|
347 |
pop
|
|
|
348 |
} def
|
|
|
349 |
|
|
|
350 |
/context-push-collapsed-margin { % => Value Context
|
|
|
351 |
dup /Margin get % => Value Context CMT
|
|
|
352 |
2 index exch % => Value Content Value CMT
|
|
|
353 |
array-append % => Value Context CMT'
|
|
|
354 |
/Margin exch put % => Value
|
|
|
355 |
pop
|
|
|
356 |
} def
|
|
|
357 |
|
|
|
358 |
/context-push-container-uid { % => Uid Context
|
|
|
359 |
dup /ContainerUID get % => Uid Context UIDStack
|
|
|
360 |
2 index exch array-append % => Uid Context UIDStack'
|
|
|
361 |
1 index exch
|
|
|
362 |
/ContainerUID exch put
|
|
|
363 |
pop pop
|
|
|
364 |
} def
|
|
|
365 |
|
|
|
366 |
/context-push-floats { % => Context
|
|
|
367 |
dup /Floats get
|
|
|
368 |
[] exch array-append % => Context Floats'
|
|
|
369 |
/Floats exch % => Context /Floats Floats'
|
|
|
370 |
put % =>
|
|
|
371 |
} def
|
|
|
372 |
|
|
|
373 |
/context-push-viewport { % => Viewport Context
|
|
|
374 |
dup /Viewport get % => Viewport Context Viewports
|
|
|
375 |
2 index exch array-append % => Viewport Context Viewports'
|
|
|
376 |
1 index exch /Viewport exch put % => Viewport Context
|
|
|
377 |
pop pop
|
|
|
378 |
} def
|
|
|
379 |
|
|
|
380 |
% helper utility
|
|
|
381 |
/make-sorted-bottom-y-list { % => Boxes
|
|
|
382 |
{
|
|
|
383 |
get-bottom-margin
|
|
|
384 |
exch array-prepend
|
|
|
385 |
} exch
|
|
|
386 |
[] exch
|
|
|
387 |
reduce % => UnsortedBottomsYs
|
|
|
388 |
|
|
|
389 |
{ gt } % => UnsortedBottomsYs GtFun
|
|
|
390 |
array-sort % => SortedBottomYs
|
|
|
391 |
} def
|
|
|
392 |
|
|
|
393 |
%%%%%%%%%%%%%%%%%%%%%
|
|
|
394 |
|
|
|
395 |
/empty-context {
|
|
|
396 |
<< /Floats [] /CollapsedMarginTop [0] >>
|
|
|
397 |
} def
|
|
|
398 |
|
|
|
399 |
/context-stack [ empty-context ] def
|
|
|
400 |
|
|
|
401 |
/push-context {
|
|
|
402 |
empty-context
|
|
|
403 |
context-stack
|
|
|
404 |
array-append
|
|
|
405 |
|
|
|
406 |
/context-stack exch def
|
|
|
407 |
} def
|
|
|
408 |
|
|
|
409 |
/pop-context {
|
|
|
410 |
context-stack
|
|
|
411 |
array-pop-first
|
|
|
412 |
|
|
|
413 |
/context-stack exch def
|
|
|
414 |
} def
|
|
|
415 |
|
|
|
416 |
/context-current {
|
|
|
417 |
context-stack 0 get
|
|
|
418 |
} def
|
|
|
419 |
|
|
|
420 |
/context-floats-bottom { % => MaxValue
|
|
|
421 |
{ get-bottom-margin min } exch
|
|
|
422 |
context-floats reduce
|
|
|
423 |
} def
|
|
|
424 |
|
|
|
425 |
/context-save-float { % => Float
|
|
|
426 |
context-current
|
|
|
427 |
/Floats get
|
|
|
428 |
|
|
|
429 |
array-append
|
|
|
430 |
|
|
|
431 |
context-current exch
|
|
|
432 |
/Floats exch
|
|
|
433 |
put
|
|
|
434 |
} def
|
|
|
435 |
|
|
|
436 |
% Get the bottom edge coordinate of the bottommost float in
|
|
|
437 |
% current formatting context
|
|
|
438 |
%
|
|
|
439 |
% @return /null in case of no floats exists in current context
|
|
|
440 |
% numeric coordinate value otherwise
|
|
|
441 |
%
|
|
|
442 |
/context-float-bottom { % =>
|
|
|
443 |
context-floats
|
|
|
444 |
dup length 0 gt {
|
|
|
445 |
{ get-bottom-margin min }
|
|
|
446 |
exch
|
|
|
447 |
dup 0 get get-bottom-margin
|
|
|
448 |
exch
|
|
|
449 |
reduce
|
|
|
450 |
} {
|
|
|
451 |
pop /null
|
|
|
452 |
} ifelse
|
|
|
453 |
} def
|
|
|
454 |
|
|
|
455 |
% Get the right edge coordinate of the rightmost float in
|
|
|
456 |
% current formatting context
|
|
|
457 |
%
|
|
|
458 |
% @return null in case of no floats exists in current context
|
|
|
459 |
% numeric coordinate value otherwise
|
|
|
460 |
%
|
|
|
461 |
/context-float-right { % =>
|
|
|
462 |
context-floats
|
|
|
463 |
dup length 0 gt {
|
|
|
464 |
{ get-right-margin min }
|
|
|
465 |
exch
|
|
|
466 |
dup 0 get get-right-margin
|
|
|
467 |
exch
|
|
|
468 |
reduce
|
|
|
469 |
} {
|
|
|
470 |
pop /null
|
|
|
471 |
} ifelse
|
|
|
472 |
} def
|