Spaces:
Sleeping
Sleeping
| % Definition of float context "class" | |
| /context-add-absolute-positioned { % => Box Context | |
| dup /AbsolutePositioned get % => Box Context AB | |
| 2 index exch | |
| array-prepend % => Box Context AB' | |
| /AbsolutePositioned exch put % => Box | |
| pop | |
| } def | |
| /context-add-fixed-positioned { % => Box Context | |
| dup /FixedPositioned get % => Box Context AB | |
| 2 index exch | |
| array-prepend % => Box Context AB' | |
| /FixedPositioned exch put % => Box | |
| pop | |
| } def | |
| /context-add-float { % => Float Context | |
| dup /Floats get % => Float Context Floats | |
| dup 0 get % => Float Context Floats Floats[0] | |
| 3 index exch array-prepend % => Float Context Floats Floats[0]' | |
| 0 exch put % => Float Context | |
| pop pop | |
| } def | |
| /context-container-uid { % => Context | |
| /ContainerUID get 0 get | |
| } def | |
| /context-create { % => | |
| << | |
| /ContainerUID [1] | |
| /AbsolutePositioned [] | |
| /FixedPositioned [] | |
| /Floats [[]] | |
| /Margin [0 0] | |
| /Viewport [] | |
| >> | |
| } def | |
| % Find the minimal X at the given Y coordinate suitable for float placement | |
| % | |
| /context-float-left-x { % => Y X Context | |
| 3 copy dup | |
| context-floats % => Y X Context Y X Context Floats | |
| context-float-left-x-rec % => Y X Context X | |
| % Clear the stack | |
| exch pop | |
| exch pop | |
| exch pop | |
| } def | |
| /context-float-left-x-rec { % => Y X Context Floats | |
| dup length 0 gt { | |
| dup 0 get % => Y X Context Floats Float | |
| dup /float get-css-value | |
| /left eq { | |
| % Check if this float contains given Y-coordinate | |
| % | |
| % Note that top margin coordinate is inclusive but | |
| % bottom margin coordinate is exclusive! The cause is following: | |
| % - if we have several floats in one line, their top margin edge Y coordinates will be equal, | |
| % so we must use agreater or equal sign to avod placing all floats at one X coordinate | |
| % - on the other side, if we place one float under the other, the top margin Y coordinate | |
| % of bottom float will be equal to bottom margin Y coordinate of the top float and | |
| % we should NOT offset tho bottom float in this case | |
| dup get-top-margin % => Y X Context Floats Float FTM | |
| rounding-epsilon add | |
| 5 index % => Y X Context Floats Float FTM Y | |
| ge % => Y X Context Floats Float FTM>=Y | |
| 1 index get-bottom-margin % => Y X Context Floats Float FTM>=Y FBM | |
| 6 index % => Y X Context Floats Float FTM>=Y FBM Y | |
| lt % => Y X Context Floats Float FTM>=Y FBM<Y | |
| and { % => Y X Context Floats Float | |
| dup get-right-margin % => Y X Context Floats Float FRM | |
| 4 index max % => Y X Context Floats Float X'=MAX(FRM,X) | |
| exch pop % => Y X Context Floats X' | |
| 4 3 roll pop % => Y Context Floats X' | |
| 3 1 roll % => Y X' Context Floats | |
| array-pop-first | |
| context-float-left-x-rec % => X | |
| } { | |
| pop | |
| array-pop-first | |
| context-float-left-x-rec | |
| } ifelse | |
| } { | |
| pop | |
| array-pop-first | |
| context-float-left-x-rec | |
| } ifelse | |
| } { | |
| % no more floats | |
| pop pop exch pop | |
| } ifelse | |
| } def % => X | |
| % Calculates position of left floating box (taking into account the possibility | |
| % of "wrapping" float to next line in case we have not enough space at current level (Y coordinate) | |
| % | |
| % @param parent reference to a parent box | |
| % @param width width of float being placed. Full width! so, extra horizontal space (padding, margins and borders) is added here too | |
| % @param $y Starting Y-coordinate | |
| % @return X X coordinate of float upper-left corner | |
| % @return Y Y coordinate of float upper-left corner | |
| % | |
| /context-float-left-xy { % => Parent Width Y Context | |
| % Prepare information about the float bottom corrdinates | |
| dup context-floats % => Parent Width Y Context Floats | |
| make-sorted-bottom-y-list % => Parent Width Y Context FloatBottoms | |
| context-float-left-xy-rec % => Y X | |
| } def % => Y X | |
| /context-float-left-xy-rec { % => Parent Width Y Context FloatBottoms | |
| 4 index get-left | |
| 3 index % => Parent Width Y Context FloatBottoms X Y | |
| exch % => Parent Width Y Context FloatBottoms Y X | |
| 3 index | |
| context-float-left-x % => Parent Width Y Context FloatBottoms X | |
| % Check if current float will fit into the parent box | |
| dup 5 index add % => Parent Width Y Context FloatBottoms X FloatRight | |
| 6 index get-right | |
| rounding-epsilon add | |
| le { % => Parent Width Y Context FloatBottoms X | |
| % will fit | |
| exch pop % => Parent Width Y Context X | |
| exch pop % => Parent Width Y X | |
| 4 2 roll % => Y X Parent Width | |
| pop pop exch % => X Y | |
| } { | |
| pop % => Parent Width Y Context FloatBottoms | |
| % Check if all floats have been already cleared | |
| dup length 0 eq { | |
| % All floats are cleared; fall back to the leftmost X coordinate | |
| pop pop exch pop % => Parent Y | |
| exch % => Y Parent | |
| get-left exch % => X Y | |
| } { | |
| % No, float does not fit at current level, let's try to 'clear' some previous floats | |
| dup 0 get % => Parent Width Y Context FloatBottoms Bottom0 | |
| 3 index min % => Parent Width Y Context FloatBottoms Y' | |
| 4 3 roll pop % => Parent Width Context FloatBottoms Y' | |
| 3 1 roll | |
| array-pop-first % => Parent Width Y' Context FloatBottoms' | |
| context-float-left-xy-rec % => X Y | |
| } ifelse | |
| } ifelse | |
| } def % => X Y | |
| % Find the minimal X at the given Y coordinate suitable for float placement | |
| % | |
| /context-float-right-x { % => Y X Context | |
| 3 copy dup | |
| context-floats % => Y X Context Y X Context Floats | |
| context-float-right-x-rec % => Y X Context X | |
| % Clear the stack | |
| exch pop | |
| exch pop | |
| exch pop | |
| } def | |
| /context-float-right-x-rec { % => Y X Context Floats | |
| dup length 0 gt { | |
| dup 0 get % => Y X Context Floats Float | |
| dup /float get-css-value | |
| /right eq { | |
| % Check if this float contains given Y-coordinate | |
| % | |
| % Note that top margin coordinate is inclusive but | |
| % bottom margin coordinate is exclusive! The cause is following: | |
| % - if we have several floats in one line, their top margin edge Y coordinates will be equal, | |
| % so we must use agreater or equal sign to avod placing all floats at one X coordinate | |
| % - on the other side, if we place one float under the other, the top margin Y coordinate | |
| % of bottom float will be equal to bottom margin Y coordinate of the top float and | |
| % we should NOT offset tho bottom float in this case | |
| dup get-top-margin % => Y X Context Floats Float FTM | |
| rounding-epsilon add | |
| 5 index % => Y X Context Floats Float FTM Y | |
| ge % => Y X Context Floats Float FTM>=Y | |
| 1 index get-bottom-margin % => Y X Context Floats Float FTM>=Y FBM | |
| 6 index % => Y X Context Floats Float FTM>=Y FBM Y | |
| lt % => Y X Context Floats Float FTM>=Y FBM<Y | |
| and { % => Y X Context Floats Float | |
| dup get-left-margin % => Y X Context Floats Float FRM | |
| 4 index min % => Y X Context Floats Float X'=MAX(FRM,X) | |
| exch pop % => Y X Context Floats X' | |
| 4 3 roll pop % => Y Context Floats X' | |
| 3 1 roll % => Y X' Context Floats | |
| array-pop-first | |
| context-float-right-x-rec % => X | |
| } { % => Y X Context Floats Float | |
| pop % => Y X Context Floats | |
| array-pop-first | |
| context-float-right-x-rec % => X | |
| } ifelse | |
| } { | |
| pop | |
| array-pop-first | |
| context-float-right-x-rec | |
| } ifelse | |
| } { | |
| % no more floats | |
| pop pop exch pop | |
| } ifelse | |
| } def % => X | |
| % Calculates position of left floating box (taking into account the possibility | |
| % of "wrapping" float to next line in case we have not enough space at current level (Y coordinate) | |
| % | |
| % @param parent reference to a parent box | |
| % @param width width of float being placed. Full width! so, extra horizontal space (padding, margins and borders) is added here too | |
| % @param $y Starting Y-coordinate | |
| % @return X X coordinate of float upper-left corner | |
| % @return Y Y coordinate of float upper-left corner | |
| % | |
| /context-float-right-xy { % => Parent Width Y Context | |
| % Prepare information about the float bottom corrdinates | |
| dup context-floats % => Parent Width Y Context Floats | |
| make-sorted-bottom-y-list % => Parent Width Y Context FloatBottoms | |
| context-float-right-xy-rec % => X Y | |
| } def % => X Y | |
| /context-float-right-xy-rec { % => Parent Width Y Context FloatBottoms | |
| 4 index get-right | |
| 3 index % => Parent Width Y Context FloatBottoms X Y | |
| exch | |
| 3 index | |
| context-float-right-x % => Parent Width Y Context FloatBottoms X | |
| % Check if current float will fit into the parent box | |
| dup % => Parent Width Y Context FloatBottoms X X | |
| 6 index get-right | |
| rounding-epsilon add % => Parent Width Y Context FloatBottoms X X FRight | |
| le { % => Parent Width Y Context FloatBottoms X | |
| % will fit | |
| exch pop exch pop % => Parent Width Y X | |
| 4 2 roll % => Y X Parent Width | |
| pop pop exch % => X Y | |
| } { | |
| pop % => Parent Width Y Context FloatBottoms | |
| % Check if all floats have been already cleared | |
| dup length 0 eq { | |
| % All floats are cleared; fall back to the leftmost X coordinate | |
| pop pop exch pop % => Parent Y | |
| exch % => Y Parent | |
| get-left exch % => X Y | |
| } { | |
| % No, float does not fit at current level, let's try to 'clear' some previous floats | |
| dup 0 get % => Parent Width Y Context FloatBottoms Bottom0 | |
| 3 index min % => Parent Width Y Context FloatBottoms Y' | |
| 4 3 roll pop % => Parent Width Context FloatBottoms Y' | |
| 3 1 roll | |
| array-pop-first % => Parent Width Y' Context FloatBottoms' | |
| context-float-left-xy-rec % => X Y | |
| } ifelse | |
| } ifelse | |
| } def % => X Y | |
| /context-floats { % => Context | |
| /Floats get 0 get | |
| } def | |
| /context-get-absolute-positioned { % => Context | |
| /AbsolutePositioned get | |
| } def | |
| /context-get-collapsed-margin { % => Context | |
| /Margin get 0 get | |
| } def | |
| /context-get-fixed-positioned { % => Context | |
| /FixedPositioned get | |
| } def | |
| /context-get-viewport { % => Context | |
| /Viewport get 0 get | |
| } def | |
| /context-point-in-floats { % => Y X Context | |
| /null % => Y X Context /null | |
| 1 index context-floats % => Y X Context /null Floats | |
| { % => Y X Context /null Float | |
| 4 index | |
| 4 index | |
| 2 index | |
| box-generic-contains-point-margin { % => Y X Context /null Float | |
| exch pop | |
| exit % => Y X Context Float | |
| } if | |
| pop | |
| } forall % => Y X Context Float | |
| exch pop | |
| exch pop | |
| exch pop | |
| } def | |
| /context-pop { % => Context | |
| dup context-pop-collapsed-margin | |
| dup context-pop-floats | |
| pop | |
| } def | |
| /context-pop-collapsed-margin { % => Context | |
| dup /Margin get % => Context CMT | |
| array-pop-first % => Context CMT' | |
| /Margin exch put % => | |
| } def | |
| /context-pop-container-uid { % => Context | |
| dup /ContainerUID get | |
| array-pop-first | |
| /ContainerUID exch put | |
| } def | |
| /context-pop-floats { % => Context | |
| dup /Floats get | |
| array-pop-first | |
| /Floats exch put | |
| } def | |
| /context-pop-viewport { % => Context | |
| dup /Viewport get | |
| array-pop-first % => Context Viewports | |
| /Viewport exch put % => | |
| } def | |
| /context-push { % => Context | |
| 0 1 index context-push-collapsed-margin | |
| dup context-push-floats | |
| pop | |
| } def | |
| /context-push-collapsed-margin { % => Value Context | |
| dup /Margin get % => Value Context CMT | |
| 2 index exch % => Value Content Value CMT | |
| array-append % => Value Context CMT' | |
| /Margin exch put % => Value | |
| pop | |
| } def | |
| /context-push-container-uid { % => Uid Context | |
| dup /ContainerUID get % => Uid Context UIDStack | |
| 2 index exch array-append % => Uid Context UIDStack' | |
| 1 index exch | |
| /ContainerUID exch put | |
| pop pop | |
| } def | |
| /context-push-floats { % => Context | |
| dup /Floats get | |
| [] exch array-append % => Context Floats' | |
| /Floats exch % => Context /Floats Floats' | |
| put % => | |
| } def | |
| /context-push-viewport { % => Viewport Context | |
| dup /Viewport get % => Viewport Context Viewports | |
| 2 index exch array-append % => Viewport Context Viewports' | |
| 1 index exch /Viewport exch put % => Viewport Context | |
| pop pop | |
| } def | |
| % helper utility | |
| /make-sorted-bottom-y-list { % => Boxes | |
| { | |
| get-bottom-margin | |
| exch array-prepend | |
| } exch | |
| [] exch | |
| reduce % => UnsortedBottomsYs | |
| { gt } % => UnsortedBottomsYs GtFun | |
| array-sort % => SortedBottomYs | |
| } def | |
| %%%%%%%%%%%%%%%%%%%%% | |
| /empty-context { | |
| << /Floats [] /CollapsedMarginTop [0] >> | |
| } def | |
| /context-stack [ empty-context ] def | |
| /push-context { | |
| empty-context | |
| context-stack | |
| array-append | |
| /context-stack exch def | |
| } def | |
| /pop-context { | |
| context-stack | |
| array-pop-first | |
| /context-stack exch def | |
| } def | |
| /context-current { | |
| context-stack 0 get | |
| } def | |
| /context-floats-bottom { % => MaxValue | |
| { get-bottom-margin min } exch | |
| context-floats reduce | |
| } def | |
| /context-save-float { % => Float | |
| context-current | |
| /Floats get | |
| array-append | |
| context-current exch | |
| /Floats exch | |
| put | |
| } def | |
| % Get the bottom edge coordinate of the bottommost float in | |
| % current formatting context | |
| % | |
| % @return /null in case of no floats exists in current context | |
| % numeric coordinate value otherwise | |
| % | |
| /context-float-bottom { % => | |
| context-floats | |
| dup length 0 gt { | |
| { get-bottom-margin min } | |
| exch | |
| dup 0 get get-bottom-margin | |
| exch | |
| reduce | |
| } { | |
| pop /null | |
| } ifelse | |
| } def | |
| % Get the right edge coordinate of the rightmost float in | |
| % current formatting context | |
| % | |
| % @return null in case of no floats exists in current context | |
| % numeric coordinate value otherwise | |
| % | |
| /context-float-right { % => | |
| context-floats | |
| dup length 0 gt { | |
| { get-right-margin min } | |
| exch | |
| dup 0 get get-right-margin | |
| exch | |
| reduce | |
| } { | |
| pop /null | |
| } ifelse | |
| } def |