2. How do layout managers get layout managers for the child FO nodes?

Child layout managers are created and retrieved in the method AbstractLayoutManager.getChildLM.

The layout manager gets the layout manager for its next child from its LMIter object childLMIter. This LMIter object contains an iterator over the children of the layout manager's FO node. It behaves itself as an iterator over the list of layout managers for the children. It constructs those layout managers when needed, in its preLoadNext method, which calls the convenience method preLoadList. Using the iterator fobjIter, preLoadList iterates through the children of the current FO-Object and preloads the corresponding LMs (LayoutManagerMaker.makeLayoutManagers()). Thus LMIter has a layout manager for its next child. It returns this layout manager in the call to its next() method, when the current layout manager invokes its getChildLM method.

BlockLayoutManager.ProxyLMiter has its own subclass of LMIter, which implements a different method of creating child layout managers. See the next section.

The method that creates the LMs, LayoutManagerMaker.makeLayoutManagers(), is implemented by FOP's implementation of the LayoutManagerMaker interface, LayoutManagerMapping. A different LM system can be hooked into FOP by inserting a different implementation of the LayoutManagerMaker interface. (See FOUserAgent.setLayoutManagerMakerOverride.)

Also note that AbstractLayoutManager.getChildLM itself does not behave as an iterator. The current child layout manager is returned until it is finished. One can safely make multiple calls to getChildLM. If the current child layout manager is unfinished and does nothing in between the calls, it remains unfinished, and is returned at every call. If the current child layout manager is finished, the next layout manager is loaded, and, because it is unfinished, returned at every call. If this is the last child layout manager and it is finished, then null is returned because in LMiter.preLoadNext baseIter.hasNext() returns false. The latter case is used in BlockLayoutManager.getNextBreakPoss.

Stack trace: Creating a new layout manager for a child, in LMiter.preLoadNext, in AbstractLayoutManager.getChildLM:

  [1] org.apache.fop.layoutmgr.LayoutManagerMapping.makeLayoutManagers(org.apache.fop.fo.FONode, java.util.List) line: 140
  [2] org.apache.fop.layoutmgr.PageSequenceLayoutManager(org.apache.fop.layoutmgr.AbstractLayoutManager).preLoadList(int) line: 399
  [3] org.apache.fop.layoutmgr.PageSequenceLayoutManager(org.apache.fop.layoutmgr.AbstractLayoutManager).preLoadNext(int) line: 409
  [4] org.apache.fop.layoutmgr.LMiter.hasNext() line: 39
  [5] org.apache.fop.layoutmgr.PageSequenceLayoutManager(org.apache.fop.layoutmgr.AbstractLayoutManager).getChildLM() line: 168
  [6] org.apache.fop.layoutmgr.PageSequenceLayoutManager.getNextBreakPoss(org.apache.fop.layoutmgr.LayoutContext) line: 260
  [7] org.apache.fop.layoutmgr.PageSequenceLayoutManager.activateLayout() line: 232