xmlgraphics-fop-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "J.Pietschmann" <j3322...@yahoo.de>
Subject How layout works
Date Thu, 24 Apr 2003 21:31:48 GMT
Hi all,
it might be interesting to write up again how the layout core works
in the old and in the new code.

In the old code, most of the layout functionality is concentrated
in the layout() methods of the FOs. Also most of the necessary state
is concentrated as fields in the FOs. The most notable exception to
these rules is LineArea.addText() and related functionality, obviously
because there is no FO corresponding to a line. Another expception
is table layout, mainly because of row and column spanning cells.
There are also a few relevant code parts sprinkled unnecessarily
and unintuitively elsewhere, for example some important break-before
logic is attached to the property, and there are some static (!)
methods important for footnotes are attached to an area class.

The layout can be roughly described by this pseudo code:
   setup an initial state for the FO's layout process
   create an area for the FO, if applicable and necessary
   if there are children
     foreach child
       layout child
       if keep/other conditions violated
         rollback layout
       else if line|column|page is full
         create a new area for the FO
     end foreach
   finalize area and add to area tree
The layout rollback is the greatest problem, you need
- reset the FO's state to a snapshop
- reset global state: Ids, out-of-line areas (fortunately,
   no floats yet), markers.
Neither is cleanly implemented in the old code which is a recurrent
source of famous and infamous bugs, but this could be cured.
The next problem is that a page is fed to the renderer, which makes
handling conditions influencing more than one page impossible.
Granted, every example I saw which *required* a look-ahead of more
than one page for correct layout was artificially constructed, but
this does not mean they wont ever occur in the wild.

In the new code the layout is done by layout managers. Basically
every FO has a layout manager, additionally there are managers
for lines, columns and pages.
Instead of creating and filling areas, the new code is organized
around computing breaks. A layout manager has three important
methods
  1. initialize layout manager state (void)
  2. get next break possibility (param: layout context)
       foreach child layout manager
         loop
           get next break possiblity from child layout manager
           if this break possibility makes a valid break
             return it
          end loop
       end foreach
  3. get areas (param: next break possiblity) for FO creating areas
       create area
       for break possiblity
             from last saved break possiblity
             to next break possiblity
          get areas from break possibility {actually from some
            child layout managers}
           add areas to area
      end for
      return area
For FOs which don't create normal areas, method 3 returns the areas
in the loop directly.
You'll probably see the problems:
- control flow oszillates between lots of objects
- the layout state is distributed over lots of objects: the layout manager
   and its numerous super classes, the break possiblities, the position
   objects encapsulated by break possibility objects, various iterators
   and to some extend the layout context passed around
Also, the iterator classes for retrieving layout managers and break
possiblities don't operate on explicit or even tangible collections, which
makes my brain hurt (but I've seen worse examples of this syndrome,
iterators seems to be attractive). Note that while there are lists of break
possiblities, the BreakPossPosIterator iterates over a tree of break
possiblities.
In general, I like the idea of creating break possiblities first and see
whether they create break possiblities for the parent, because this makes
backtracking easier: instead of unrolling ready-to-render layout just
restart at a previous break possibility with a new layout context. An
interesting side effect is that for certain renderers the area tree
doesn't have to be constructed explicitely, you can try to render the
areas right after they are constructed, provided the break possibility
provides enough information (and there is no forward page number
reference).

My approach would be
1. get rid of all the iterators and move the functionality to the
    layout managers because layout managers currently store many
    of the same info anyway.
2. get rid of position objects and fold their data into break possiblities
3. make a proper hierarchy of break possibility objects
4. move stacking info to the layout context and make proper snapshots.
5. eventually get rid of the layout managers which correspond 1-to-1
    to FOs and move the functionality back to the FOs.
This is however not a small task, and I'm reluctant to start partly because
inquiries to Keiron and Karen for rationales of the current design didn't
result in anything, not even a statement like "It looked good"
Also IDs, markers and out-of-line areas will need some more attention,
the mapping from IDs to pages/areas for example should be stored in either
athe next break possiblity or a layout context snapshot.

Comments?

J.Pietschmann


---------------------------------------------------------------------
To unsubscribe, e-mail: fop-dev-unsubscribe@xml.apache.org
For additional commands, email: fop-dev-help@xml.apache.org


Mime
View raw message