% \iffalse %% %% (C) Copyright 1999-2000 Frank Mittelbach, David Carlisle, Chris Rowley %% All rights reserved. %% %% Not for general distribution. In its present form it is not allowed %% to put this package onto CD or an archive without consulting the %% the authors. %% % \fi % % \begin{macrocode} \def\@tempa#1: #2.dtx,v #3 #4 #5 #6 #7${ \ProvidesPackage{#2}[#4 #3 #5 #6]} \@tempa$Id: xo-place.dtx,v 1.37 2000/08/11 07:14:28 latex3 Exp $ % \end{macrocode} % % % % Ignore white space in this package. % \begin{macrocode} \IgnoreWhiteSpace % \end{macrocode} % % % % \subsection{Selecting the next area to try} % % % \begin{macro}{\std@try@this@area} % The |\std@try@this@area| command is called when we have % selected a float from the |\@activelist| and want to place it % in one of the open areas to see if it fits there. If we succeed % in finding a potential candidate place we will exit using % |\contruct@trial| which will run a trial cutting the galley to % see if each column gets the right kind of text and contains the % right kind of callouts. % The areas are tried in a defined order. % % If we don't find any open areas we return putting the current % float onto the |\area@ddd| and then calling |\@trynextfloat|. % % If we find an open area but for some reason the float is not % allowed to go there we close that area for floats of this type % and recurse (i.e. try to use the next open area for this type). % % The reasons for failure to place the float into the first open % area are numerous. First there are restrictions on the number of % floats on a page (if we reach this all areas get closed) there % there are similar restrictions for each individual float area. % % If those tests are passed we trial typeset the float with its % caption (or rather typeset and attach its caption) to determine % the size needed by the float. That will give us a dimension to % test against restrictions for the amount of space floats are % allowed to occupy etc. % % \begin{macrocode} \def\std@try@this@area{ %<*trace> \@tracepush{std@try@this@area} % % \end{macrocode} % If all areas for the float type are closed we have to defer this float. % \begin{macrocode} \ifx\this@open@areas\@empty %<*trace> \tr@ce{defer:~no~open~area~ available} % \do@next\defer@and@try@next@float \else % \end{macrocode} % Otherwise the next area to try is the first of |\this@open@areas|: % \begin{macrocode} \setup@this@area{\expandafter\@carcube\this@open@areas\@nil} %<*trace> \tr@ce{area~trial:~ \this@area} % %<*progress> \progress{~ area~trial:~ \this@area} % % \end{macrocode} % Next test needs cleanup once the span has a decent data % structure.\footnote{FIX!!} % \begin{macrocode} \ifnum \this@area@span@number = \if!\this@span@number! 1\else % big hack \this@span@number \fi \relax %<*trace> \tr@ce{span~ count~ okay:~ \this@area \space =~ \if!\this@span@number! 1\else % big hack \this@span@number \fi} % % \end{macrocode} % % \begin{macrocode} \ifnum \pagesetup@max@float@num > \page@float@count % \end{macrocode} % % \begin{macrocode} \ifnum\csname pagesetup@\this@area @float@num\endcsname = \csname \this@area @float@count \endcsname % % \end{macrocode} % Current area doesn't accept any more floats, so try next one (if any) % \begin{macrocode} %<*trace> \tr@ce{close~area:~\this@area\space float~num~reached ~ (\csname pagesetup@\this@area @float@num\endcsname)} % %<*progress> \progress@failed{\this@area\space float~num~reached ~ (\csname pagesetup@\this@area @float@num\endcsname)} % \do@next\try@next@area % \end{macrocode} % % \begin{macrocode} \else \xin@\this@area \this@page@closed \ifin@ %<*trace> \tr@ce{area~ closed~ for~ all~ types;~ member~ of~ (\this@page@closed)} % %<*progress> \progress@failed{area~ closed~ for~ all~ types} % \do@next\try@next@area \else %<*trace> \tr@ce{area~ not~ closed~ for~ all~ types:~ not~ member~ of~ (\this@page@closed)} % \xin@\this@area \this@closed@areas \ifin@ %<*trace> \tr@ce{area~ closed~ for~ class~ \this@class;~ member~ of~ (\this@closed@areas)} % %<*progress> \progress@failed {area~ closed~ for~ class~ \this@class} % \do@next\try@next@area \else %<*trace> \tr@ce{area~ open~ for~ class~ \this@class;~ not~ member~ of~ (\this@closed@areas)} % \xin@\this@area\this@fps \ifin@ % \append@caption@to@float \construct@and@test@col@hts \if@test \do@next\try@next@area \else \do@next\pretests@success@action \fi \else %<*trace> \tr@ce{close~area:~\this@area\space float~not~allowed~ by~ user~ control~ (\this@fps)} % %<*progress> \progress@failed{\this@area\space float~not~allowed~ by~ user~ control~ (\this@fps)} % \do@next\try@next@area \fi \fi \fi \fi \else % defer \global\let\this@open@areas\@empty %<*trace> \tr@ce{defer:~max~float~num~reached ~(\pagesetup@max@float@num)} % %<*progress> \progress@failed{max~float~num~reached ~(\pagesetup@max@float@num)} % \do@next\defer@and@try@next@float \fi \else %<*trace> \tr@ce{span~ count~ unsuitable:~ \this@area \space /=~ \if!\this@span@number! 1\else % big hack \this@span@number \fi} % %<*progress> \progress@failed{span~ count~ \this@area \space /=~ \if!\this@span@number! 1\else % big hack \this@span@number \fi} % \do@next\try@next@area \fi \fi %<*trace> \@tracepop{std@try@this@area} % \do@continue } % \end{macrocode} % \end{macro} % % % % % \begin{macro}{\do@next} % Emergency macro to reduce the number of input levels (as the code % got past the internal default of 300). This is because we have a % lot of recursion going on without being tail % recursion. Essentially this means some of the code needs slightly % different implementation.\footnote{fix} % \begin{macrocode} \def\do@next{\let\do@continue} % \end{macrocode} % \end{macro} % % \begin{macro}{\relaxed@try@this@area} % \begin{macrocode} \def\relaxed@try@this@area{ %<*trace> \@tracepush{relaxed@try@this@area} % % \end{macrocode} % If all areas for the float type are closed we have to defer this float. % \begin{macrocode} \ifx\this@open@areas\@empty %<*trace> \tr@ce{defer:~no~open~area~ available} % \do@next\defer@and@try@next@float \else % \end{macrocode} % Otherwise the next area to try is the first of |\this@open@areas|: % \begin{macrocode} \setup@this@area{\expandafter\@carcube\this@open@areas\@nil} %<*trace> \tr@ce{area~trial:~ \this@area} % %<*progress> \progress{~ area~trial:~ \this@area} % % \end{macrocode} % Next test needs cleanup once the span has a decent data % structure.\footnote{FIX!!} % \begin{macrocode} \ifnum \this@area@span@number = \if!\this@span@number! 1\else % big hack \this@span@number \fi \relax %<*trace> \tr@ce{span~ count~ okay:~ \this@area \space =~ \if!\this@span@number! 1\else % big hack \this@span@number \fi} % % \end{macrocode} % % \begin{macrocode} \xin@\this@area\this@page@closed \ifin@ %<*trace> \tr@ce{area~ closed~ for~ all~ types;~ member~ of~ (\this@page@closed)} % %<*progress> \progress@failed{area~ closed~ for~ all~ types} % \do@next\try@next@area \else %<*trace> \tr@ce{area~ not~ closed~ for~ all~ types:~ not~ member~ of~ (\this@page@closed)} % \xin@\this@area \this@closed@areas \ifin@ %<*trace> \tr@ce{area~ closed~ for~ class~ \this@class;~ member~ of~ (\this@closed@areas)} % %<*progress> \progress@failed {area~ closed~ for~ class~ \this@class} % \do@next\try@next@area \else %<*trace> \tr@ce{area~ open~ for~ class~ \this@class;~ not~ member~ of~ (\this@closed@areas)} % \append@caption@to@float \construct@and@test@col@hts \if@test \do@next\try@next@area \else \do@next\pretests@success@action \fi \fi \fi \else %<*trace> \tr@ce{span~ count~ unsuitable:~ \this@area \space /=~ \if!\this@span@number! 1\else % big hack \this@span@number \fi} % %<*progress> \progress@failed{span~ count~ \this@area \space /=~ \if!\this@span@number! 1\else % big hack \this@span@number \fi} % \do@next\try@next@area \fi \fi %<*trace> \@tracepop{relaxed@try@this@area} % \do@continue } % \end{macrocode} % \end{macro} % % % % % \begin{macro}{\construct@and@test@col@hts} % The |\construct@and@test@col@hts| loops over all columns % affected by the float area we want to place our float into % and reduces the column size as % needed. It sets the switch |@test| to true in case the float % doesn't fit into area for some reason. It is up to the calling % macro to take proper action in this case (including resetting % column heights to their former values). % \begin{macrocode} \def\construct@and@test@col@hts { % \end{macrocode} % We use the information from the area not from the float (which % allows us to put small floats into larger areas. % \begin{macrocode} \update@this@area@columns { \expandafter \construct@and@test@col@ht \csname col@ht@ \the\count@ \endcsname {\the\count@} % \end{macrocode} % We need to break out of the updating loop if we found a column that % doesn't work, a) to save time and b) since the % |\construct@and@test@col@ht| resets the switch again to false % (in the current implementation). % \begin{macrocode} \if@test \count@\z@ % break out of loop \fi } } % \end{macrocode} % \end{macro} % % % % \begin{macro}{\construct@and@test@col@ht} % The |\construct@and@test@col@ht| reduces the height of one column % by the size of the current float (plus some suitable extra space) % and tests if this reduction is possible/allowed. It sets the % switch |@test| to true if it encounters a problem. % \begin{macrocode} \def\construct@and@test@col@ht#1#2{ %<*trace> \tr@ce{col height~before:~ \the#1 (\string#1)} % % \end{macrocode} % In |\@tempdima| we calculate the amount of space we need if we % place the float. This is the size of the float, i.e., its height % and depth, plus either |\pagesetup@float@text@sep| if this is the % very first float in this column (on top or on bottom), or % |\pagesetup@float@area@sep| if it is the first float in the % current area, or |\pagesetup@float@float@sep| if we already have % floats in this area. % \begin{macrocode} \@tempdima \ht\this@captioned@float \advance \@tempdima \dp\this@captioned@float \ifnum \csname col@ \this@area@type @floats@#2@number\endcsname = \z@ %<*trace> \tr@ce{first~ float~ in~ any~ \this@area@type\space in~ column~ #2:~ adding~ \string\pagesetup@float@text@sep =\the\pagesetup@float@text@sep} % \advance \@tempdima \pagesetup@float@text@sep \else \advance \@tempdima \expandafter \ifx \csname area@\this@area\endcsname\@empty \pagesetup@float@area@sep %<*trace> \tr@ce{first~ float~ in~ \this@area :~ adding~ \string\pagesetup@float@area@sep =\the\pagesetup@float@area@sep} % \else \pagesetup@float@float@sep %<*trace> \tr@ce{additional~ float~ in~ \this@area :~ adding~ \string\pagesetup@float@float@sep = \the\pagesetup@float@float@sep} % \fi \fi % \end{macrocode} % Now we make the area size fully fall into the page grid (if there % is one). To do this we first substract any delta that has been % accumulated for the column (to get back to the real size) and % then run |\snap@to@grid| to get the next grid point. % \begin{macrocode} \advance \@tempdima -\csname col@ \this@area@type @delta@ #2 \endcsname \relax % \end{macrocode} % The |\col@|\meta{area-type}|@delta@|\meta{col} are macros but % fortunately low-level \TeX{} supports register assignments of the % form |--3pt| so the above will work even if the macro contains a % negative value. % \begin{macrocode} \snap@to@grid \@tempdima \pagesetup@grid@point@sep % \end{macrocode} % % If the distance to the next grid point is larger than the % distance to the previous one, and if the space between floats and % text is allowed to shrink by the needed amount we will use the % previous grid point. % \begin{macrocode} \ifdim \returned@lower@delta@size < \returned@delta@size \relax \ifdim \returned@lower@delta@size < \pagesetup@float@text@shrink %<*trace> \tr@ce{GRID:~ column~#2:~ choosing~ lower~ grid~ point} % % \end{macrocode} % We do this by copying the |\returned@lower@...| to the macros % used below. Note that for the delta size we have to use the % negation since we want to backup by this amount and delta sizes % are always given in absolute values. % \begin{macrocode} \global\let \returned@size \returned@lower@size \xdef \returned@delta@size {-\returned@lower@delta@size } \fi \fi %<*trace> \tr@ce{GRID:~ column~#2:~ \the\@tempdima\space ->~ \returned@size} % \@tempdima \returned@size % \end{macrocode} % % After updating |\@tempdima| in this way we now have to check if % the space remaining for the text column is large enough. % \begin{macrocode} \@tempdimb#1 \advance \@tempdimb -\@tempdima \@testfalse \ifdim \textminlines\baselineskip > \@tempdimb % \end{macrocode} % If not we bail out % \begin{macrocode} \@testtrue %<*trace> \tr@ce{close~area:~\this@area\space not~ enough~ text~ lines~ left~ (\textminlines x\the\baselineskip> \the\@tempdimb)} % %<*progress> \progress@failed{not~ enough~ text~ space~ (\textminlines x\the\baselineskip\space >~ \the\@tempdimb)} % \else % \end{macrocode} % Otherwise we have to update the column heights (and their saved % version in case we back out later) as well as storing the new % delta (which is still in |\returned@delta@size|). % \begin{macrocode} %<*trace> \tr@ce{saved@col@ht@ #2~ <-~\the#1} % \expandafter\xdef \csname saved@col@ht@ #2\endcsname{\the#1} \global#1\@tempdimb \global\expandafter\let \csname saved@col@ \this@area@type @delta@ #2 \expandafter \endcsname \csname col@ \this@area@type @delta@ #2 \endcsname \global\expandafter\let \csname col@ \this@area@type @delta@ #2 \endcsname \returned@delta@size %<*trace> \tr@ce{GRID (delta):~ column~#2\this@area@type:~ \csname saved@col@ \this@area@type @delta@ #2 \endcsname\space ->~ \returned@delta@size} % \fi %<*trace> \tr@ce{col height~after:~ \the#1} % } % \end{macrocode} % \end{macro} % % % \begin{macro}{\textminlines} % Tmp definition; should be interfaced to pagesetup. % \begin{macrocode} \def\textminlines{4} % \end{macrocode} % \end{macro} % % % % \subsection{Supporting grid based designs} % % % % \begin{macro}{\pagesetup@grid@point@sep} % |\pagesetup@grid@point@sep| is the distance between grid points % for page design or 0pt if we are not doing grid design. % \begin{macrocode} \let\pagesetup@grid@point@sep\ERROR % \end{macrocode} % \end{macro} % % % \begin{macro}{\snap@to@grid} % |\snap@to@grid| takes a dimension as first argument and a % ``grid-size'' as second argument and from those two values % calculates a new dimension which is a multiple of the grid-size % and equal or larger than the first argument. % % It returns this calculated value globally in |\returned@size|. In % addition it will return in |\returned@delta@size| the delta % between the original and the new dimension. % % It also returns a lower or equal grid point in % |\returned@lower@size| and the delta to it (absolute value) in % |\returned@lower@delta@size|. % % Thus the first argument lies on a grid point if and only if % |\returned@size| equals |\returned@lower@size|. % % If we are not doing grid typesetting then |\snap@to@grid| is % actually a dummy which will return always the first argument in % |\returned@size| and |\returned@lower@size|, and |0pt| in the % deltas. % % The actual definition is assigned within the page setup. % \begin{macrocode} \let\snap@to@grid\ERROR % \end{macrocode} % \end{macro} % % % \begin{macro}{\dummy@snap@to@grid} % In case we don't do grids we simply pretend that all sizes lie on % grid points. % \begin{macrocode} \def \dummy@snap@to@grid #1#2{ \begingroup % \end{macrocode} % Definitions below can be optimised for speed but the ones used % give better tracing. % \begin{macrocode} \@tempdima #1 \relax \xdef \returned@size { \the\@tempdima } \global\let \returned@lower@size \returned@size \gdef \returned@delta@size {0pt} \global\let \returned@lower@delta@size \returned@delta@size \endgroup } % \end{macrocode} % \end{macro} % % % \begin{macro}{\std@snap@to@grid} % But if we do grid typesetting we have to do a bit more work % here. % \begin{macrocode} \def \std@snap@to@grid #1#2{ % \end{macrocode} % Everything is done in a group so that the register change do not % affect other parts of the code. % \begin{macrocode} \begingroup % \end{macrocode} % First we calculate in |\@tempdimc| the nearest grid point which % is smaller or equal to the given size in |#1| by using scaled % point arithmetic. % \begin{macrocode} \@tempdima #1\relax \@tempdimb #2\relax \@tempcnta \@tempdima % orig size in sp \@tempcntb \@tempdimb % grid size in sp \divide \@tempcnta \@tempcntb \@tempdimc \@tempcnta\@tempdimb % \end{macrocode} % If the calculated grid point is smaller than the original % dimension use the next larger one. But record the other in % |\returned@lower@size|. % \begin{macrocode} \ifdim \@tempdimc < \@tempdima \xdef \returned@lower@size { \the\@tempdimc } \advance\@tempdimc \@tempdimb \fi % \end{macrocode} % The |\returned@size| will be whatever the result of the above is % and |\returned@delta@size| the difference to the given value in % |#1|. Note that |\returned@size| will always be larger or equal % to this value so the difference computed below will also be % non-negative! % \begin{macrocode} \xdef \returned@size { \the\@tempdimc } \advance \@tempdimc -\@tempdima \xdef \returned@delta@size { \the\@tempdimc } % \end{macrocode} % Now if this difference turns out to be zero then we actually % started with a dimension exactly on a grid point. In this case we % better define both |\returned@lower@size| and % |\returned@lower@delta@size| to equal their counterparts. % \begin{macrocode} \ifdim \@tempdimc = \z@ \global \let \returned@lower@size \returned@size \global \let \returned@lower@delta@size \returned@delta@size % \end{macrocode} % Otherwise we only have to compute |\returned@lower@delta@size| % since in that case we already recorded |\returned@lower@size| % above (and we better had since by now we lost this information as % we reused |\@tempdimc|). Now the value for this macro should be % the difference between |\returned@delta@size| and our grid size % both of which are already stored in some temp registers, % thus\ldots % \begin{macrocode} \else \advance\@tempdimb-\@tempdimc \xdef \returned@lower@delta@size { \the\@tempdimb } \fi \endgroup %<*trace> \tr@ce{GRID:~ \string\returned@lower@size=\returned@lower@size} \tr@ce{GRID:~ \string\returned@lower@delta@size=\returned@lower@delta@size} \tr@ce{GRID:~ \string\returned@size=\returned@size} \tr@ce{GRID:~ \string\returned@delta@size=\returned@delta@size} % } % \end{macrocode} % \end{macro} % % % % % % \subsection{Deferring a float} % % % % \begin{macro}{\really@defer@and@try@next@float} % \begin{macrocode} \def\really@defer@and@try@next@float{ %<*progress> \progress@failed{-->~ defer} \progress@nl{} % \@cons\area@ddd\this@float@box %<*trace> \tr@ce{this@page@closed~ <-~ "\this@page@closed"~ +~ "\pagesetup@ddd@all@close"} % \xdef\this@page@closed{\this@page@closed, \pagesetup@ddd@all@close} \ifx\pagesetup@ddd@class@close\pagesetup@area@list %<*trace> \tr@ce{this@closed@areas~ <-~ "\pagesetup@ddd@class@close"~ (all~ closed)} % \global\let\this@closed@areas\pagesetup@ddd@class@close \else %<*trace> \tr@ce{this@closed@areas~ <-~ "\this@closed@areas"~ +~ "\pagesetup@ddd@class@close"} % \xdef\this@closed@areas{\this@closed@areas, \pagesetup@ddd@class@close} \fi \global\expandafter\let\csname closed@\this@class @areas\endcsname % FMi tmp \this@closed@areas \try@next@float } % \end{macrocode} % \end{macro} % % % % \begin{macro}{\defer@and@try@next@float} % % This code either defers the current float and restarts by calling % |\try@next@float| or recurses after relaxing the placement % conditions (in case the current float should be flushed). % % If the placement conditions are already relaxed we move the first % flush point that affects the current float one column forward and % then retry. This might result in succeding to place the float, if % not it will ultiamtely result in the flush point being moved from % the page at which point the float can be deferred. % % \begin{macrocode} \def\defer@and@try@next@float{ %<*trace> \@tracepush{defer@and@try@next@float} % % \end{macrocode} % If there have been no flush points or if the flush points seen do % not affect the current float we can immediately defer it. % \begin{macrocode} \if@flushseen \xin@\this@class\flush@classes@list@max \ifin@ %<*trace> \tr@ce{flush:~ class~ \this@class\space in~ \flush@classes@list@max} % % \end{macrocode} % First test is just there to avoid doing any of the loops % (might not be worth having) % \begin{macrocode} \ifnum \csname flush@min@col@1\endcsname > \curr@col@count %<*trace> \tr@ce{flush:~ no~ flush~ points~ on~ page;~ defer} % \do@next\really@defer@and@try@next@float \else % \end{macrocode} % % The code is often invoked before there is an attempt to split the % galley; this means we don't know which flush point affects the % current float and thus have to manually get at it. % % So we loop through the |\flush@last@float@|\meta{num} values to % find the first one that a) affects the current float type and b) % holds a sequence number that is higher or equal to the sequence % number of the current float. % \begin{macrocode} \count@ \@ne \loop % \end{macrocode} % If |\count@| is greater than |\flush@seq@num| we have exhausted % all possible flush points without finding a candidate. % \begin{macrocode} \ifnum \flush@seq@num < \count@ \in@false \else % \end{macrocode} % Otherwise, if |\this@sequence@number| is greater than % |\flush@last@float@|\meta{num} the current flush point is before % the call-out to the current float. % \begin{macrocode} %<*trace> \tr@ce{flush:~ \this@sequence@number \space ???~ \csname flush@last@float@ \the\count@ \endcsname} % \ifnum \this@sequence@number > \csname flush@last@float@ \the\count@ \endcsname \relax % \end{macrocode} % We set |\in@true| to get a repeat below with a new value of % |\count@|. % \begin{macrocode} \in@true \else % \end{macrocode} % Otherwise we have a flush point that is later in the galley in % comparison to the call-out of the current float thus potentially % affects it. Therefore we now have to check if the sequence class % of the current float is affected by the flush point found: % \begin{macrocode} \expandafter\xin@\expandafter\this@class \csname flush@classes@list@ \the\count@ \endcsname % \end{macrocode} % Now we could make good use of the |\unless| primitive of % e\TeX. But since we want to run with standard \TeX{} and don't % have |\xnotin@| available we invert the result. % \begin{macrocode} \ifin@ \in@false \else \in@true %<*trace> \tr@ce{flush:~ class~ \this@class\space not~ in~ \csname flush@classes@list@ \the\count@ \endcsname \space (ignored) } % \fi \fi \fi \ifin@ \advance\count@\@ne \repeat %<*trace> \tr@ce{flush:~ first~ float~ point~ after~ float~ =~ \the\count@} % \ifnum \flush@seq@num < \count@ %<*trace> \tr@ce{flush:~ this~ float~ past~all~flush~ points;~ defer} % \do@next\really@defer@and@try@next@float \else % \end{macrocode} % Once a |flush@min@col| is larger than |\curr@col@count| it has % moved to the next page. In particular this is true for the % artificial value |\maxdimen| to which it is sometimes set to % denote this fact. If so we can defer our float. % \begin{macrocode} \ifnum \csname flush@min@col@\the\count@\endcsname > \curr@col@count %<*trace> \tr@ce{flush:~ float~ past~ all~ flush~ points~ on~ current~ page;~ defer} % \do@next\really@defer@and@try@next@float \else % \end{macrocode} % If we have already relaxed the conditions and we are still in % conflict with a flush point on the current page we nearly ran out % of options. In this case we are forced to move the flush point, % but rather than moving it to the next page and defering the float % we can move it one column further (which might make it fall off % the page though) and then retry to place the float since we have % now more space available. % \begin{macrocode} \ifx\try@this@area\relaxed@try@this@area %<*trace> \tr@ce{flush:~ defer~ forced;~ move~ flush~ point~ columns} % %<*progress> \progress@nl{} \progress@nl{Flushing~ impossible~ -->~ breaking~ before~ flush~ point~ and~ retry} % % \end{macrocode} % We should only increment the |flush@min@col@| value of the first % flush point that affects our float (this will automatically move % later flush points if necessary). Incrementing the later ones is % incorrect as they might not need moving! % \begin{macrocode} \expandafter \gincrement@num \csname flush@min@col@ \the\count@ \endcsname %<*trace> \tr@ce{flush@min@col@\the\count@ \space <-~ \csname flush@min@col@ \the\count@ \endcsname } % %<*progress> \progress@nl{} \progress@nl{Defer~ impossible~ -->~ moving~ flush~ point~ to~ column~ \csname flush@min@col@ \the\count@\endcsname \space and~ retry} % % \end{macrocode} % Not clear that it is really necessary to check all areas again, % but it is late (after midnight) and it is definitely not % wrong.\footnote{Check!} % \begin{macrocode} \relax@float@placement@conditions % needed to reset open areas \do@next\try@this@area \else % \end{macrocode} % % \begin{macrocode} \relax@float@placement@conditions \do@next\try@this@area \fi \fi \fi \fi \else %<*trace> \tr@ce{flush:~ class~ \this@class\space not~ in~ \flush@classes@list@max;~ defer} % \do@next\really@defer@and@try@next@float \fi \else %<*trace> \tr@ce{flush:~ no~ flush~ point~ seen; defer} % \do@next\really@defer@and@try@next@float \fi %<*trace> \@tracepop{defer@and@try@next@float} % \do@continue } % \end{macrocode} % \end{macro} % % % \begin{macro}{\relax@float@placement@conditions} % \begin{macrocode} \def \relax@float@placement@conditions { %<*progress> \progress@failed{-->~ retry~ with~ relaxed~ conditions} \progress@nl{} % %<*trace> \tr@ce{flush:~relax~placement~conditions} % \global\let\try@this@area\relaxed@try@this@area % next line perhaps external? \global\let\this@open@areas\saved@this@open@areas \global\let\check@some@constraints\relaxed@check@some@constraints \global\let\check@callout@constraints\relaxed@check@callout@constraints \global\let\calculate@target@fl@column\relaxed@calculate@target@fl@column } % \end{macrocode} % \end{macro} % % \begin{macro}{\tighten@float@placement@conditions} % \begin{macrocode} \def\tighten@float@placement@conditions { %<*trace> \tr@ce{flush:~tighten~placement~conditions} % \global\let\try@this@area\std@try@this@area \global\let\check@some@constraints\std@check@some@constraints \global\let\check@callout@constraints\std@check@callout@constraints \global\let\calculate@target@fl@column\std@calculate@target@fl@column } % \end{macrocode} % \end{macro} % % % % \begin{macro}{\partly@tighten@float@placement@conditions} % This is used when we have placed the last float that is affected % by a certain flush point. We don't want to tighten up completely % since this would essentially mean that we can't place any further % floats since callout relationships etc might be violated for % them. Good question is whether or not the last restriction should % be used again since this too might prevent any further placements. % \begin{macrocode} \def\partly@tighten@float@placement@conditions { %<*trace> \tr@ce{flush:~partly~tighten~placement~conditions} % \global\let\try@this@area\std@try@this@area % \global\let\check@some@constraints\std@check@some@constraints % \global\let\check@callout@constraints\std@check@callout@constraints \global\let\calculate@target@fl@column\std@calculate@target@fl@column } % \end{macrocode} % \end{macro} % % % % \subsection{Checking float placement during trial} % % The interface to checking float placement in relation to its callout % is the following piece of code in |\grab@column@or|: %\begin{verbatim} % \let\@elt\check@callout@constraints % \float@classes@list %\end{verbatim} % This loops through all float types and executes % |\check@callout@constraints| with the float type as an argument. The output % routine |\grab@column@or| itself is called for each column of a trial % configuration, thus the above loop is called for each column % individually (|\curr@col@count| can be used to determine the current % column number). % % By giving |\check@callout@constraints| an appropriate definition a % pagesetup template can implement different relationships between % callout and float. % % Possible tests (getting stronger): % \begin{itemize} % % \item % Don't check, i.e., add the float when you find it and it fits % according to other criteria (like number of floats in the area, % etc.). This is implemented in |\check@callout@none|. % % % \item % Check if callouts for all floats on the page (not column) are % either on the same page or on an earlier page; i.e., callout can be % late as long as the float is visible from the callout. % % Fail if for last column and all float types: % last callout number for float type is smaller than maximum last float % of type put into any column.\footnote{This description is % probably wrong} % % This is implemented in |\check@callout@page|. % % \item % Check if callouts for all floats in the column are either on the % same column or on an earlier column. % % Fail if for any column and any float type: % last callout number for float type is smaller last float sequence % number for type recorded for this column. % % This case consists in fact of two subcases depending on how we % interpret to which column a spanning float belongs. If we claim % that a spanning float is placed into its starting column, then we % fail if its call-out is in a later column even though this column % might still be spanned by the float area. % % This is implemented in |\check@callout@column|. % % \item % Check if callouts for all floats in the column are on an earlier % column or if on the same column the float was added to the bottom % (or marginal) area; i.e. strict float/callout order % % Fail if for each type and for any column: % `top' callout number less than `top' float number % (at top of text column) %\begin{verbatim} % [Corectness proof: % TRUE => first callout's float comes before bottom % and so comes too early % => FAIL % FALSE => first callout's float comes in bottom and all other % callouts come later and so are in bottom or beyond % => OK % ] %\end{verbatim} % The proof above is in fact only valid if you look at the whole % document and not only at a single page since a float in the bottom % area of the last column with its callout on the next page will % only be detected when testing the next page. Therefore one needs % an additional check of type |\check@callout@column|. % % This is implemented in |\check@callout@after|. % % % \end{itemize} % % % \begin{macro}{\check@callout@none} % This test is an easy one: just do nothing, i.e., gobble the argument. % \begin{macrocode} \let\check@callout@none\@gobble % \end{macrocode} % \end{macro} % % \begin{macro}{\check@callout@page} % We are are only interested in the callout/float relation per page % we only have to do a check when producing the last column, i.e., % when |\curr@col@count| is |\col@count|. % \begin{macrocode} \def\check@callout@page#1{ %<*trace> \@tracepush{check@callout@page} % \ifnum\curr@col@count=\col@count % \end{macrocode} % We store in |\fl@max| the highest sequence number for floats of % the current type up to the end of the page. For this we have to % find the maximum of |\fl@0@|\meta{type} (highest float number on % previous pages) and those for the columns, e.g., % |\fl@|\meta{colnum}|@|\meta{type}; this is done by the following % code: % \begin{macrocode} \global\expandafter\let\expandafter\fl@max \csname fl@0@#1\endcsname \forall@columns { \ifnum\csname fl@\the\curr@col@count @#1\endcsname>\fl@max\relax \xdef\fl@max{\csname fl@\the\curr@col@count @#1\endcsname} \fi } % \end{macrocode} % We then store the number of the last callout in |\count@|; the % |0| will take care of the potential problem that there was never any % callout so far. And we better have a |\relax| afterwards since % otherwise we will expand the |\ifnum| before we have finished % assigning the |\count@|. % \begin{macrocode} \count@0\LastMark{#1}\relax %<*trace> \tr@ce{Last~callout~ (#1)~ =~ \the\count@} % % \end{macrocode} % Now we have to compare those two numbers to find out if that % trial has failed: % \begin{macrocode} \ifnum\count@<\fl@max\relax \@failtrue %<*progress> \progress@failed{last~callout~ \the\count@\space~<~\fl@max \space last~float~put~on~page~or~ earlier} % %<*trace> \tr@ce{Failed:~(#1)~ last~callout~ \the\count@\space~<~\fl@max \space last~float~put~on~page~or~ earlier} \else \tr@ce{OK:~(#1)~ last~callout~ \the\count@\space~>=~\fl@max \space last~float~put~on~page~or~ earlier} % \fi \fi %<*trace> \@tracepop{check@callout@page} % } % \end{macrocode} % \end{macro} % % % % \begin{macro}{\fl@max} % The macro |\fl@max| is used within |\check@callout@page| to hold % the highest sequence number of any allocated float on the current % page for the type under testing. It will be recalculated on % each pass.\footnote{One could generate this value while running through % the trials --- this would perhaps be a bit more time efficient.} % \begin{macrocode} \let\fl@max\ERROR % \end{macrocode} % \end{macro} % % % \begin{macro}{\check@callout@column} % Checking each column separately means we have to compare for each % type the last callout on this or previous columns (i.e., as % returned by |\LastMark|) with the highest sequence number for % floats of this type in the current column (as stored in % |fl@|\meta{col}|@|\meta{type}). So we first store the callout % info in |\count@|. % \begin{macrocode} \def\check@callout@column#1{ %<*trace> \@tracepush{check@callout@column} % \count@0\LastMark{#1}\relax % \end{macrocode} % Then we do the test. If there are no floats of the current type % in the current column |\fl@|\meta{col}|@|\meta{type} will be zero % and thus the following test will come out true. This is the % correct behaviour as any callouts that might be present will be % correctly evaluated in tests on neighboring columns with floats. % \begin{macrocode} \ifnum\count@<\csname fl@\the\curr@col@count @#1\endcsname\relax %<*progress> \progress@failed{last~ callout~ \the\count@\space <~ \csname fl@\the\curr@col@count @#1\endcsname \space last~ float~ placed~ in~ column~ \the\curr@col@count} % %<*trace> \tr@ce{Failed:~(#1)~ last~ callout~ \the\count@\space <~ \csname fl@\the\curr@col@count @#1\endcsname \space last~float~placed} % % \end{macrocode} % If the test fails we abort this trial by setting the switch % |@fail| to true. We also set % |\curr@col@count| to |\col@count| which will save us any further % iteration (in case this wasn't the last column). Finally we % locally set |\@elt| to |\@gobble| which will essentially about % the current loop through the |\float@classes@list|. % \begin{macrocode} \@failtrue \global\curr@col@count\col@count \let\@elt\@gobble % \end{macrocode} % Otherwise the constraints for callout of current float type are % met so we report this fact if we do tracing. % \begin{macrocode} %<*trace> \else \tr@ce{OK:~(#1)~ last~ callout~ \the\count@\space >=~ \csname fl@\the\curr@col@count @#1\endcsname \space last~float~placed} % \fi %<*trace> \@tracepop{check@callout@column} % } % \end{macrocode} % \end{macro} % % % \begin{macro}{\check@callout@after} % % \begin{macrocode} \def\check@callout@after#1{ %<*trace> \@tracepush{check@callout@after} % % \end{macrocode} % % We first check if all floats are either on the same column than % their callout or on an later column by calling % |\check@callout@column|. If this returns |@fail| we immediately % abort any further processing. % \begin{macrocode} \check@callout@column{#1} \if@fail\else % \end{macrocode} % % If the above check found no violation we have to check for top % area floats that might preceed their callouts. % % For this we look at the value of the % |\tfl@|\meta{col}|@|\meta{float-type} macro which holds the % highest float sequence number for floats of this type allocated % in that column. % \begin{macrocode} \global\expandafter\let\expandafter \returned@sequence@number \csname tfl@\the\curr@col@count @#1\endcsname % \end{macrocode} % % If there was no float in the top area we get |0| back and in % that case we are done since all our constraints are met. % \begin{macrocode} \ifnum \returned@sequence@number = \z@ %<*trace> \tr@ce{OK:~(#1)~ top~ areas~ have~ no~ floats} % \else % \end{macrocode} % % Otherwise we have to look at the top callout number and compare % it to the last float number of the top area. % \begin{macrocode} \count@ 0\PreviousMark{#1}\relax % \end{macrocode} % If that callout number is less than the last float number we % failed since this means that there is a float in the top area % which callout has not yet been seem. So we abort the % trial. Otherwise our constraints are met. % \begin{macrocode} \ifnum \count@ < \returned@sequence@number \relax % \end{macrocode} % But before aborting we give some information on why we % failed. This has to come first since we change |\curr@col@count| % below. % \begin{macrocode} %<*progress> \progress@failed{top~ callout~ \the\count@\space <~ \returned@sequence@number \space last~ float~ put~ in~ top~ of~ column~ \the\curr@col@count} % \@failtrue \global\curr@col@count\col@count \let\@elt\@gobble %<*trace> \tr@ce{Failed:~(#1)~ top~ callout~ \the\count@\space <~ \returned@sequence@number \space last~float~put~in~top} \else \tr@ce{OK:~(#1)~ top~ callout~ \the\count@\space >=~ \returned@sequence@number \space last~float~put~in~top} % \fi \fi \fi %<*trace> \@tracepop{check@callout@after} % } % \end{macrocode} % \end{macro} % % % % % \subsection{Checking bottom float footnote constraints} % % In |\grab@column@or|, the output routine that grabs a single column % during a trial, we have the command |\check@some@constraints| which % allows to check some constraints and if they aren't met is supposed % to set the switch |@fail|. % % This can, for example be used to implement a constraint that bottom % floats are only allowed if there are no footnotes in the current % column.\footnote{At the moment this is restricted to single column % floats. Spanning floats are always allowed.} % % \begin{macro}{\check@float@footnote@forbidden} % The command |\check@float@footnote@forbidden| is the % implementation for |\check@some@constraints| that prevents bottom % floats if the current column contains footnotes. % \begin{macrocode} \def\check@float@footnote@forbidden{ %<*trace> \@tracepush{check@float@footnote@forbidden} % \ifvoid\footins \else % \end{macrocode} % If the current column contains footnotes and we have bottom % floats we fail. First we check if there is a bottom area for this % column defined if not we pretend there is an empty one. % \begin{macrocode} \expandafter \ifx \csname area@b\the\curr@col@count1\endcsname \relax \global\expandafter\let \csname area@b\the\curr@col@count1\endcsname \@empty \fi % \end{macrocode} % Then we check if the bottom area is empty and fail otherwise % \begin{macrocode} \expandafter \ifx \csname area@b\the\curr@col@count1\endcsname \@empty %<*trace> \tr@ce{OK:~ no~ old~ bottom~ floats} % \else %<*progress> \progress@failed{old~bottom~floats:~ \expandafter\meaning \csname area@b\the\curr@col@count1\endcsname} % %<*trace> \tr@ce{Failed:~ old~bottom~floats:~ \expandafter\meaning \csname area@b1\the\curr@col@count\endcsname} % \@failtrue \fi % \end{macrocode} % Finally we test if the float we are try to place is going onto a % bottom area. % % However we only do this if the float doesn't span.\footnote{Extend?} % \begin{macrocode} \ifnum \this@area@span@number = \@ne %<*trace> \tr@ce{this@area,column:~ \this@area,~\the\curr@col@count} % \if b \this@area@type \ifnum \this@area@col@number = \curr@col@count \@failtrue \fi \fi \fi \if@fail %<*progress> \progress@failed{column~ \the\curr@col@count\space contains~ footnotes~ and~ bottom~ floats} % %<*trace> \tr@ce{Failed:~ column~ \the\curr@col@count\space contains~ footnotes~ and~ bottom~ floats} % \global\curr@col@count\col@count \fi \fi %<*trace> \@tracepop{check@float@footnote@forbidden} % } % \end{macrocode} % \end{macro} % % % \begin{macro}{\check@float@footnote@none} % % This is the implementation for |\check@some@constraints| if we % don't care about mixing footnotes and bottom floats. The reason % |\@empty| rather than |\relax| is used is that otherwise the % |\ifx| test in the template would fail. % \begin{macrocode} \let\check@float@footnote@none\@empty % \end{macrocode} % \end{macro} % % % % % % % \endinput \endinput % % $Log: xo-place.dtx,v $ % Revision 1.37 2000/08/11 07:14:28 latex3 % added header % % Revision 1.36 2000/08/11 06:49:47 latex3 % untabify % % Revision 1.35 2000/08/11 06:45:03 latex3 % only partially tighten float constraints after passing a flush point % % Revision 1.34 2000/07/23 21:03:19 latex3 % removed obsolete commentary % % Revision 1.33 2000/07/21 13:53:17 latex3 % more renaming for float sequence class concept % % Revision 1.32 2000/07/18 21:06:36 latex3 % introduced float sequence classes % % Revision 1.31 2000/07/12 17:24:53 latex3 % more support for grids % % Revision 1.30 2000/07/10 21:00:57 latex3 % support for grid typesetting % % Revision 1.29 2000/07/04 19:42:05 latex3 % fix tracing for GRID stuff % % Revision 1.28 2000/07/01 15:57:25 latex3 % use \update@this@area@columns % integrate code to support grid design (first draft) % % Revision 1.27 2000/06/29 17:18:14 latex3 % introduced \setup@this@area % % Revision 1.26 2000/06/26 15:03:40 latex3 % making prototype for \pagesetup@float@area@sep % % Revision 1.25 2000/06/22 20:08:09 latex3 % renamed some macros to get them more uniform % % Revision 1.24 2000/06/22 11:01:24 latex3 % When substracting heights from columns do this for the columns spanned % by the area. Don't use the span number from the float (in the future % this might be smaller than the span number of the area) % % Revision 1.23 2000/06/19 21:38:04 latex3 % fixed flush point handling when deferring % % Revision 1.22 2000/06/18 19:03:53 latex3 % added "Checking bottom float footnote constraints" from xo-page % % Revision 1.21 2000/06/16 11:20:15 latex3 % rename \construct@and@test@col@height to \construct@and@test@col@ht % rename \construct@and@test@col@heights to \construct@and@test@col@hts % rename \cl@height1 to \@col@ht@1 (etc) % % Revision 1.20 2000/06/16 11:06:37 latex3 % support float-callout-span-constraint % % Revision 1.19 2000/06/16 07:49:49 latex3 % improve progress info % % Revision 1.18 2000/06/15 17:49:02 latex3 % moved macros from xo-page into here since they deal with placement % % Revision 1.17 2000/06/15 15:23:32 latex3 % implemented new semantics for area names % % Revision 1.16 2000/06/13 20:48:18 latex3 % docu update % % Revision 1.15 2000/06/06 12:50:40 latex3 % before attempting fuzzy flushpoints % % Revision 1.14 2000/05/03 18:57:56 latex3 % provide \construct@and@test@col@heights subroutine % % fix problem that deferred floats would not stop other floats going % into earlier areas % % Revision 1.13 2000/03/31 17:08:50 latex3 % avoid using up too much input stack by using tail recursion in % strategic places (tmp fix) % % Revision 1.12 2000/03/26 21:04:03 latex3 % some renaming of macros % % Revision 1.11 2000/03/24 15:34:27 latex3 % version that starts supporting spans (still a hack yet) % % Revision 1.10 2000/03/22 15:52:37 latex3 % some normalisations of names % first go at spans (tmp version) % % Revision 1.9 2000/03/17 20:23:11 latex3 % more fixes to flushing (looks good now) % % Revision 1.8 2000/03/16 10:28:29 latex3 % partial and full flush working for the first time % % Revision 1.7 2000/03/05 19:31:56 latex3 % some renaming % extend to multiple columns (6 max right now) % fix defer logic: when flushseen don't defer immediately % % Revision 1.6 2000/02/27 15:12:45 david % *** empty log message *** % % Revision 1.5 2000/02/27 11:27:45 david % first attempt at flush floats % % Revision 1.4 2000/02/26 18:24:21 david % renaming, and using \initialise@areas % % Revision 1.3 2000/02/16 13:40:09 latex3 % added 3col support % % Revision 1.2 2000/02/16 10:10:43 latex3 % added documentation % added test for float area size after adding float % % Revision 1.1 2000/02/13 22:27:39 latex3 % Initial revision %