diff options
Diffstat (limited to 'src/documentation/content/xdocs/DnI/getnextbreakposs.xml')
-rw-r--r-- | src/documentation/content/xdocs/DnI/getnextbreakposs.xml | 1227 |
1 files changed, 1227 insertions, 0 deletions
diff --git a/src/documentation/content/xdocs/DnI/getnextbreakposs.xml b/src/documentation/content/xdocs/DnI/getnextbreakposs.xml new file mode 100644 index 000000000..96bd64390 --- /dev/null +++ b/src/documentation/content/xdocs/DnI/getnextbreakposs.xml @@ -0,0 +1,1227 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + * Copyright 2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + --> + +<!-- $Id$ --> + +<!-- +<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" + "docbookx.dtd"> + --> + + <chapter> + <title>Phase 2a: The <literal>getNextBreakPoss</literal> call +tree</title> + + <section> + <title>Overview</title> + + <para> <itemizedlist spacing="compact"> + <listitem> + <para>Create a new layout context for the children.</para> + </listitem> + <listitem> + <para>Then process the flow: loop until the flow is exhausted +(isFinished()): <itemizedlist spacing="compact"> + <listitem> + <para>Get the next possible breakpoint (getNextBreakPoss). +<itemizedlist spacing="compact"> + <listitem> + <para>Loop until the list of child layout +managers is exhausted: <itemizedlist spacing="compact"> + <listitem> + <para> Get a child layout manager +(AbstractLayoutManager.getChildLM). The current child layout manager +is returned until it is finished. Then the layout manager for the next +child is returned.</para> + </listitem> + <listitem> + <para> Create a new layout context for +the children.</para> + </listitem> + <listitem> + <para> If the child layout manager is +not finished, get the next possible breakpoint +(getNextBreakPoss).</para> + </listitem> + <listitem> + <para> If a breakpoint is returned, +break the loop and return the breakpoint.</para> + </listitem> + </itemizedlist></para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>This finishes a page.</para> + </listitem> + <listitem> + <para>Get the next possible breakpoint +(getNextBreakPoss) (<emphasis>continued</emphasis>) <itemizedlist spacing="compact"> + <listitem> + <para>Loop until the list of child layout +managers is exhausted: (<emphasis>continued</emphasis>) <itemizedlist spacing="compact"> + <listitem> + <para>Else if no breakpoint is returned, +do the next cycle with the next child layout manager.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Mark the layout manager as finished (the +list of child layout managers is exhausted).</para> + </listitem> + </itemizedlist></para> + </listitem> + </itemizedlist></para> + </listitem> + </itemizedlist></para> + + <para>At this point a complete (pseudo)tree of possible break +points for a page has been collected.</para> + + </section> + + <section> + <title>How do layout managers get layout managers for the child +FO nodes?</title> + +<para>Child layout managers are created and retrieved in the method +<literal>AbstractLayoutManager.getChildLM</literal>.</para> + +<para>The layout manager has a layout strategy, which has an +<literal>AddLMVisitor</literal> object, which is responsible for +creating layout managers for the FO nodes.</para> + +<para>The layout manager gets the layout manager for its next child from its +<literal>LMIter</literal> object <literal>childLMIter</literal>. This +<literal>LMIter</literal> 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 +<literal>preLoadNext</literal> method. It does so by calling the +layout strategy's <literal>AddLMVisitor</literal> object's +<literal>addLayoutManager</literal> method. The +<literal>LMIter</literal> object gets the layout strategy via the +current layout manager, which it knows.</para> + +<para><literal>AddLMVisitor</literal>'s <literal>addLayoutManager</literal> +method first registers the LM list in its second argument, i.e. the +<literal>LMIter</literal> object's LM list, as its own member +<literal>currentLMlist</literal>. Then it asks the FO node to accept +it as the <literal>FOTreeVisitor</literal> +(<literal>acceptVisitor</literal>). The FO node then calls the +appropriate method of this FO tree visitor, in this case +(<literal>fo:flow</literal>) the method <literal>serveFlow</literal> +(<literal>AddLMVisitor.serveFlow</literal>). This method creates a +<literal>FlowLayoutManager</literal> object and adds it to the +<literal>currentLMList</literal>. Thus <literal>LMIter</literal> has a +layout manager for its next child. It returns this layout manager in +the call to its <literal>next()</literal> method, when the current +layout manager invokes its <literal>getChildLM</literal> method.</para> + +<para>Note that layout manager types may have their own subclass of +<literal>LMIter</literal>, +e.g. <literal>BlockLayoutManager$BlockLMiter</literal> and +<literal>AbstractList$ListItr</literal>, which may implement a +different method of creating child layout managers.</para> + +<para>The method <literal>acceptVisitor</literal> of the FO node calls the +appropriate method of its visitor. This procedure effectively +implements an indirect mapping from FO node type to layout +manager. The indirection allows the <literal>AddLMVisitor</literal> +object to return its own layout manager for each FO node type. Because +the <literal>AddLMVisitor</literal> object is part of the layout +strategy, this indirection allows the layout strategy to provide its +own layout managers for the layout process. In this manner, a +different layout strategy can be coupled to the other parts of the +program.</para> + +<para>Note that <literal>AbstractLayoutManager.getChildLM</literal> 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 +<literal>getChildLM</literal>. 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 +<literal>LMiter.preLoadNext</literal> +<literal>baseIter.hasNext()</literal> returns false. The latter case +is used in <literal>BlockLayoutManager.getNextBreakPoss</literal>.</para> + +<para>Stack trace: Creating a new layout manager for a child, in +<literal>LMiter.preLoadNext</literal>, in +<literal>AbstractLayoutManager.getChildLM</literal>:</para> + +<screen> + [1] org.apache.fop.layoutmgr.AbstractLayoutManager.<init> (AbstractLayoutManager.java:71) + [2] org.apache.fop.layoutmgr.BlockStackingLayoutManager.<init> (BlockStackingLayoutManager.java:70) + [3] org.apache.fop.layoutmgr.FlowLayoutManager.<init> (FlowLayoutManager.java:81) + [4] org.apache.fop.layoutmgr.AddLMVisitor.serveFlow (AddLMVisitor.java:894) + [5] org.apache.fop.fo.pagination.Flow.acceptVisitor (Flow.java:187) + [6] org.apache.fop.layoutmgr.AddLMVisitor.addLayoutManager (AddLMVisitor.java:198) + [7] org.apache.fop.layoutmgr.LMiter.preLoadNext (LMiter.java:88) + [8] org.apache.fop.layoutmgr.LMiter.hasNext (LMiter.java:77) + [9] org.apache.fop.layoutmgr.AbstractLayoutManager.getChildLM (AbstractLayoutManager.java:186) + [10] org.apache.fop.layoutmgr.PageLayoutManager.getNextBreakPoss (PageLayoutManager.java:253) + [11] org.apache.fop.layoutmgr.PageLayoutManager.doLayout (PageLayoutManager.java:228) +</screen> + + </section> + + <section> + <title>Block layout managers and their child layout managers</title> + +<para>Block LMs are different in their treatment of their child LMs. For +this purpose <literal>BlockLayoutManager</literal> defines a nested class <literal>BlockLMiter</literal>, +which is a subclass of <literal>LMiter</literal>.</para> + +<para>A <literal>BlockLMiter</literal> object has a member called proxy, +which is the basic <literal>LMiter</literal> over the children of the +block. If the proxy produces a child LM that does not generate inline +areas, the child LM is added to the list of child LMs as normal. But +if the childLM generates an inline area, a new +<literal>LineLayoutManager</literal> object is created +(<literal>BlockLayoutManager.BlockLMiter.createLineManager</literal>). This +LM asks the proxy to produce more child LMs. As long as these child +LMs generate inline areas, they are collected by the +<literal>LineLayoutManager</literal> object. Finally, the +<literal>LineLayoutManager</literal> object creates its +<literal>LMiter</literal> object as the +<literal>ListIterator</literal> over the list of collected child LMs.</para> + + </section> + + <section> + <title>About <literal>getNextBreakPoss</literal> and the list of +child layout managers</title> + +<para>Note that the breakpoint may come from a deeply nested child. Each +layout manager keeps a reference to its current child layout +manager. The whole list is descended again +(<literal>getChildLM</literal>) at the next call to +<literal>getNextBreakPoss</literal>.<warning> + <simpara>TO BE IMPROVED</simpara> + </warning> +</para> + +<para>Stack of layout managers: + <variablelist> + <varlistentry> + <term><literal>PageSequence</literal></term> + <listitem> + <simpara><literal>PageLayoutManager</literal></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><literal>Flow</literal></term> + <listitem> + <simpara><literal>FlowLayoutManager</literal></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><literal>Block</literal></term> + <listitem> + <simpara><literal>BlockLayoutManager</literal></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><literal>Block</literal></term> + <listitem> + <simpara><literal>LineLayoutManager</literal></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><literal>FOText</literal></term> + <listitem> + <simpara><literal>TextLayoutManager</literal></simpara> + </listitem> + </varlistentry> + </variablelist> +For <literal>BlockLayoutManager</literal> and +<literal>LineLayoutManager</literal> <literal>Block</literal> is the +same, but their <literal>childLMIter</literal> are different: +<literal>BlockLayoutManager$BlockLMiter</literal> vs +<literal>AbstractList$ListItr</literal></para> + +<screen> + [1] org.apache.fop.layoutmgr.TextLayoutManager.getNextBreakPoss (TextLayoutManager.java:270) + [2] org.apache.fop.layoutmgr.LineLayoutManager.getNextBreakPoss (LineLayoutManager.java:212) + [3] org.apache.fop.layoutmgr.BlockLayoutManager.getNextBreakPoss (BlockLayoutManager.java:229) + [4] org.apache.fop.layoutmgr.FlowLayoutManager.getNextBreakPoss (FlowLayoutManager.java:111) + [5] org.apache.fop.layoutmgr.PageLayoutManager.getNextBreakPoss (PageLayoutManager.java:261) + [6] org.apache.fop.layoutmgr.PageLayoutManager.doLayout (PageLayoutManager.java:228) +</screen> + +<para>A <literal>TextLayoutManager</literal>: +<screen> + this = { + vecAreaInfo: instance of java.util.ArrayList(id=1062) + chars: instance of char[13] (id=1064) + textInfo: instance of org.apache.fop.fo.TextInfo(id=1065) + iAreaStart: 0 + iNextStart: 0 + ipdTotal: null + spaceCharIPD: 4448 + hyphIPD: 5328 + halfWS: instance of org.apache.fop.traits.SpaceVal(id=1066) + iNbSpacesPending: 0 + org.apache.fop.layoutmgr.AbstractLayoutManager.userAgent: instance of org.apache.fop.apps.FOUserAgent(id=1067) + org.apache.fop.layoutmgr.AbstractLayoutManager.parentLM: instance of org.apache.fop.layoutmgr.LineLayoutManager(id=1068) + org.apache.fop.layoutmgr.AbstractLayoutManager.fobj: instance of org.apache.fop.fo.FOText(id=1069) + org.apache.fop.layoutmgr.AbstractLayoutManager.foID: null + org.apache.fop.layoutmgr.AbstractLayoutManager.markers: null + org.apache.fop.layoutmgr.AbstractLayoutManager.bFinished: false + org.apache.fop.layoutmgr.AbstractLayoutManager.curChildLM: null + org.apache.fop.layoutmgr.AbstractLayoutManager.childLMiter: instance of org.apache.fop.layoutmgr.LMiter(id=1070) + org.apache.fop.layoutmgr.AbstractLayoutManager.bInited: true +} +</screen> +</para> + +<para>Text in <literal>fo:text</literal> is handled by a +<literal>TextLayoutManager</literal>. Two routines add the text and +calculate the next possible break.</para> + + </section> + + <section> + <title><literal>LineLayoutManager.getNextBreakPoss</literal></title> + + <section> + <title>Prepare for the main loop</title> + + <itemizedlist spacing="compact"> + <listitem> + <simpara>Create a new empty list of possible line endings, +<literal>vecPossEnd</literal>.</simpara> + </listitem> + <listitem> + <simpara>Retrieve the <literal>ipd</literal> +<literal>availIPD</literal> from the layout context.</simpara> + </listitem> + <listitem> + <simpara>Create a new layout context (inline layout +context) for the child layout managers, based on the layout context +for this layout manager.</simpara> + </listitem> + <listitem> + <simpara>Clear the map of previous + <literal>ipd</literal>s.</simpara> + </listitem> + <listitem> + <simpara>Record the length of +<literal>vecInlineBreaks</literal>, which we can use to find the last +breakposs of the previous line.</simpara> + </listitem> + <listitem> + <simpara>Set <literal>prevBP</literal> to +<literal>null</literal>; <literal>prevBP</literal> contains the last +confirmed breakposs of this line.</simpara> + </listitem> + </itemizedlist> + </section> + + <section> + <title>The main loop over the list of child layout managers</title> + + <para>Loop until the list of child layout managers is +exhausted: <itemizedlist spacing="compact"> + <listitem> + <para>Get a child layout manager +(<literal>AbstractLayoutManager.getChildLM</literal>). The current +child layout manager is returned until it is finished. Then the layout +manager for the next child is returned.</para> + </listitem> + <listitem> + <para>Record the last breakposs.</para> + </listitem> + <listitem> + <para>Record whether the breakposs we are going to +find is the first breakposs of this line.</para> + </listitem> + <listitem> + <para>Record whether it is the first breakposs of +this child layout manager.</para> + </listitem> + <listitem> + <para>Initialize the inline layout context (note that +it is not a new layout context, the same inline layout context is used +by all child layout managers) (method +<literal>InlineStackingLayout.initChildLC</literal>): <itemizedlist spacing="compact"> + <listitem> + <para>Record whether this is a new area; it is a +new area if this is the start of a new line or of a new child +LM.</para> + </listitem> + <listitem> + <para>If this is the start of a new +line <itemizedlist spacing="compact"> + <listitem> + <para>record whether this is the first area +of this child LM,</para> + </listitem> + <listitem> + <para>set the leading space as passed by +argument.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Else if this starts a new child +LM <itemizedlist spacing="compact"> + <listitem> + <para>record that this is the first area,</para> + </listitem> + <listitem> + <para>set the leading space from the previous +BP.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Else set the leading space to + <literal>null</literal>.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Record on the inline layout context whether +leading space is supppressed; it is suppressed if this is the start of +a new line, but not the start of this child LM, and the previous line +was not ended by a forced break.</para> + </listitem> + <listitem> + <para>Retrieve the next breakposs from the current child +LM (<literal>getNextBreakPoss</literal> method of child LM). If it is +not <literal>null</literal>: +<itemizedlist spacing="compact"> + <listitem> + <para>Calculate the <literal>ipd</literal> up to +the previous BP (method +<literal>InlineStackingLayout.updatePrevIPD</literal>): <itemizedlist spacing="compact"> + <listitem> + <para>Take an empty <literal>ipd</literal> + size.</para> + </listitem> + <listitem> + <para>If this starts a new line: <itemizedlist spacing="compact"> + <listitem> + <para>if it has a leading fence, add +leading space (?),</para> + </listitem> + <listitem> + <para>list the <literal>ipd</literal> +for the LM of this BP in the map of previous +<literal>ipd</literal>s.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Else <itemizedlist spacing="compact"> + <listitem> + <para>retrieve the +<literal>ipd</literal> for the LM of this BP in the map of previous +<literal>ipd</literal>s,</para> + </listitem> + <listitem> + <para>if that is +<literal>null</literal> (first BP of this child LM) <itemizedlist spacing="compact"> + <listitem> + <para>retrieve the +<literal>ipd</literal> for the LM of the previous BP in the map of +previous <literal>ipd</literal>s,</para> + </listitem> + <listitem> + <para>add the leading space +of this BP,</para> + </listitem> + <listitem> + <para>add the pending space-end +(stacking size) of the previous BP,</para> + </listitem> + <listitem> + <para>list the +<literal>ipd</literal> for the LM of this BP in the map of previous +<literal>ipd</literal>s.</para> + </listitem> + </itemizedlist></para> + </listitem> + </itemizedlist></para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Add to the <literal>ipd</literal> the +pending space-end (stacking size) of this BP.</para> + </listitem> + <listitem> + <para>Record whether this BP could end the +line: <itemizedlist spacing="compact"> + <listitem> + <para>if a break may occur after this BP, +record true;</para> + </listitem> + <listitem> + <para>else if this BP is suppressible at a +line break, return false;</para> + </listitem> + <listitem> + <para>else, return whether this is the last +child LM and it is finished, or the next area could start a new +line.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>If this BP could end the line, add trailing +space.</para> + </listitem> + <listitem> + <para>If this BP exceeds the line length +(<literal>bpDim.min > availIPD.max</literal>), <itemizedlist spacing="compact"> + <listitem> + <para>if the text should be justified or if +this is the first BP of this line, <itemizedlist spacing="compact"> + <listitem> + <para>if we are in a hyphenation try, +break the loop; we have exhausted our options and one of the previous +BPs should end the line (<literal>_exit of loop_</literal>);</para> + </listitem> + <listitem> + <para>if this BP could not end the +line, add it to the list of inline breaks, and continue with the next +iteration;</para> + </listitem> + <listitem> + <para>prepare to hyphenate: get the +hyphenation context for the text between the last and this BP (method +<literal>getHyphenContext</literal>): <itemizedlist spacing="compact"> + <listitem> + <para>add this BP to the list of +inline breaks; even though this is not a good BP, we add it to the +list, so that we can retrieve the text between the last and this +BP;</para> + </listitem> + <listitem> + <para>iterate back to the +previous BP in this list;</para> + </listitem> + <listitem> + <para>loop over the following +BPs in this list: <itemizedlist spacing="compact"> + <listitem> + <para>retrieve the text +between the preceding and this BP.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>remove this BP again from +the list of inline breaks.</para> + </listitem> + <listitem> + <para>create a hyphenation +object for the retrieved text, taking the language, country and other +hyphenation properties into account.</para> + </listitem> + <listitem> + <para>create a hyphenation +context object from it, and return that.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>store the hyphenation context +with the inline layout context.</para> + </listitem> + <listitem> + <para>Record on the inline layout +context that we are in a hyphenation try.</para> + </listitem> + <listitem> + <para>reset the child LMs to the +previous BP or to the start of the line.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Else (if text should not be justified +and if this is not the first BP of this line) break the loop; one of +the previous BPs should end the line (<literal>_exit of +loop_</literal>);</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Else (if this BP does not exceed the line +length): <itemizedlist spacing="compact"> + <listitem> + <para>add this BP to the list of inline +breaks,</para> + </listitem> + <listitem> + <para>if this BP could end the line, +<itemizedlist spacing="compact"> + <listitem> + <para>record it as the last confirmed +BP: set prevBP to this BP.</para> + </listitem> + <listitem> + <para>if this BP is a forced line +break, break the loop; this BP (or one of the previous BPs?) should +end the line (<literal>_exit of loop_</literal>).</para> + </listitem> + <listitem> + <para>if this BP may fill the line +length (<literal>bpDim.max >= availIPD.min</literal>), add it to the +list of possible line endings, <literal>vecPossEnd</literal>, with a +cost which is equal to the difference of the optimal values of the +content length and the line length (<literal>Math.abs(availIPD.opt - +bpDim.opt)</literal>).</para> + </listitem> + </itemizedlist></para> + </listitem> + </itemizedlist></para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>If we are in a hypenation try, and the hyphenation +context has no more hyphenation points, break the loop; this or one of +the previous BPs should end the line (<literal>_exit of +loop_</literal>).</para> + </listitem> + </itemizedlist></para> + </section> + + <section> + <title>After the main loop</title> + + <para>There are five exit points of the main loop: <orderedlist> + <listitem> + <simpara>The last BP in the hyphenation try has exceeded +the line length.</simpara> + </listitem> + <listitem> + <simpara>The last BP has exceeded the line length, and +we cannot get a hyphenation context.</simpara> + </listitem> + <listitem> + <simpara>The last BP has exceeded the line length, and +we do not hyphenate.</simpara> + </listitem> + <listitem> + <simpara>The last BP has not exceeded the line length +but forces a line break.</simpara> + </listitem> + <listitem> + <simpara>We have run out of hyphenation points (and the +last BP has not exceeded the line length).</simpara> + </listitem> + <listitem> + <simpara>Natural end of the while loop: we are through +the list of child layout managers.</simpara> + </listitem> + </orderedlist></para> + +<para>If the last BP has exceeded the line length, it is not in the +list of inline breaks, and prevBP points to the last good break; +otherwise it is in the list of inline breaks, and prevBP points to +it.</para> + + <itemizedlist spacing="compact"> + <listitem> + <para>If we are through the list of child LMs, mark this + LM as finished.</para> + </listitem> + <listitem> + <para>If no BP was produced, return +<literal>null</literal>. (This should concur with being +finished?)</para> + </listitem> + <listitem> + <para>If prevBP is <literal>null</literal>, there is not +last good break; set it to this BP, even though it fails some +criteria: <itemizedlist spacing="compact"> + <listitem> + <para>it has exceeded the line length in the +hyphenation try or we cannot get a hyphenation context,</para> + </listitem> + <listitem> + <para>or it cannot end the line but it is the last +BP of the last child layout manager.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>If this BP is not a forced break, and there are +several possible line breaks, select the best one; make +<literal>prevBP</literal> point to it. (Could this produce the wrong +result if the BP has exceeded the line length and at the same time is +a forced line break? Should <literal>prevBP</literal> be tested for +being a forced break instead?)</para> + </listitem> + <listitem> + <para>If the last BP is not the actual breakpoint +<literal>prevBP</literal> (<literal>bp != prevBP</literal>) and the +material after <literal>prevBP</literal> is not suppressible at the +end of a line, back up to <literal>prevBP</literal> for a proper start +of the next line.</para> + </listitem> + <listitem> + <para>If the text should be justified and the breakpoint +is a forced line break (here <literal>prevBP</literal> is tested) or +this is the last line of the layout manager, set text alignment to +left-aligned.</para> + </listitem> + <listitem> + <para>Make a line break and return the associated + breakposs.</para> + </listitem> + </itemizedlist> + </section> + </section> + + <section> + <title><literal>LineLayoutManager.makeLineBreak</literal></title> + + <para>Arguments are: <itemizedlist spacing="compact"> + <listitem> + <para>index in <literal>vecInlineBreaks</literal> of + line breaking BP of last line,</para> + </listitem> + <listitem> + <para>target line length,</para> + </listitem> + <listitem> + <para>type of text alignment.</para> + </listitem> + </itemizedlist></para> + +<para>Calculate line dimensions. The Line LayoutManager contains the +parameters <literal>lineHeight</literal>, <literal>lead</literal> and +<literal>follow</literal> as members, which it received from its Block +LayoutManager parent at construction. The Blo ckLayoutManager contains +these parameters as members as well, and has received them from a +<literal>TextInfo</literal> object in the method set +<literal>BlockTextInfo</literal>. The <literal>TextInfo</literal> +object has a reference to the <literal>Font</literal> +object. <literal>lead</literal> is the font ascender, +<literal>follow</literal> is the font descender.</para> + +<para>The leading is the difference between +<literal>lineHeight</literal> and font height = ascender + +descender. The leading is split in two halves, one for above, the +other for below the line. The variable <literal>lineLead</literal> is +calculated as the distance from the baseline to the top of the line, +the variable <literal>maxtb</literal> is calculated as the distance +from the baseline to the bottom of the line. The variable +<literal>middlefollow</literal> set equal to <literal>maxtb</literal>. +These parameters correspond to the members <literal>lead</literal>, +<literal>total</literal> and <literal>follow</literal> of the +breakposs. <warning> + <simpara>Find out the exact meaning of these.</simpara> + </warning></para> + + <itemizedlist spacing="compact"> + <listitem> + <para>Loop over the breakposs in + <literal>vecInlineBreaks</literal>: <itemizedlist spacing="compact"> + <listitem> + <para>adjust <literal>lineLead</literal>, +<literal>maxtb</literal> and <literal>middlefollow</literal> if the +corresponding dimension of the BP is larger;</para> + </listitem> + <listitem> + <para>add the <literal>ipd</literal>s; a BP does +not just hold the <literal>ipd</literal> of the area since the +previous BP, but the cumulative <literal>ipd</literal> for all the +areas contributed by its layout manager; therefore care is taken to +add only the <literal>ipd</literal> of the last BP of each LM; more +precisely, the <literal>ipd</literal> of the last BP of the previous +LM is added when the next LM is encountered;</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Add the <literal>ipd</literal> of the last BP.</para> + </listitem> + <listitem> + <para>Resolve the trailing space of the last BP.</para> + </listitem> + <listitem> + <para>Adjust <literal>middlefollow</literal> if it is +smaller than <literal>maxtb - lineHeight</literal>.</para> + </listitem> + <listitem> + <para>Calculate the stretch or shrink factor +<literal>ipdAdjust</literal> for the stretch- and shrinkable elements +in this line: <itemizedlist spacing="compact"> + <listitem> + <para>if content optimum is larger than line + length optimum, <itemizedlist spacing="compact"> + <listitem> + <para>if content minimum is smaller than + line length optimum, <itemizedlist spacing="compact"> + <listitem> + <para>calculate +<literal>ipdAdjust</literal> between 0 and -1, real line length = line +length optimum,</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>else (content minimum is larger than + line length optimum) <itemizedlist spacing="compact"> + <listitem> + <para><literal>ipdAdjust = +-1</literal>, real line length = content minimum,</para> + </listitem> + </itemizedlist></para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>else (content optimum is smaller than line + length optimum), <itemizedlist spacing="compact"> + <listitem> + <para>if content maximum is larger than line + length optimum, <itemizedlist spacing="compact"> + <listitem> + <para>calculate +<literal>ipdAdjust</literal> between 0 and 1, real line length = line +length optimum,</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>else (content maximum is smaller than + line length optimum), <itemizedlist spacing="compact"> + <listitem> + <para><literal>ipdAdjust = +1</literal>, real line length = content maximum.</para> + </listitem> + </itemizedlist></para> + </listitem> + </itemizedlist></para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Calculate the stretch or shrink factor +<literal>dAdjust</literal> for white space and the indent: +<itemizedlist spacing="compact"> + <listitem> + <para>justify: calculate +<literal>dAdjust</literal>,</para> + </listitem> + <listitem> + <para>center or end: calculate the required + indent.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Create a new <literal>LineBreakPosition</literal> +based on this LM, the last BP in <literal>vecInlineBreaks</literal> +and the calculated dimensions; use <literal>lineLead</literal> for the +baseline position and <literal>lineLead + middlefollow</literal> for +the <literal>lineHeight</literal>.</para> + </listitem> + <listitem> + <para>Create a <literal>BreakPoss</literal> from this + <literal>LineBreakPosition</literal> object.</para> + </listitem> + <listitem> + <para>Mark the BP as last if this LM is finished.</para> + </listitem> + <listitem> + <para>Set the stacking size of the BP +(<literal>bpd</literal>) equal to <literal>lineLead + +middlefollow</literal>.</para> + </listitem> + </itemizedlist> + </section> + + <section> + <title>Line LayoutManager, a sequence of breakposs</title> + +<para>The text is: "waterstaatsingenieur ministersportefeuille +aandachtstrekker. Vernederlandste vakliteratuur" etc. It consists of a +few long Dutch words, which can be found in the hyphenation exceptions +in <filename>nl.xml</filename>. The column width is 8cm. This text and +width have been chosen so that they force many hyphenations.</para> + +<para>This text is contained in a single <literal>FOText</literal> +node, and is dealt with by a single Text LayoutManager, which is a +child layout manager for the Line LayoutManager. The Text +LayoutManager maintains a list of area information objects, +<literal>vecAreaInfo</literal>, and the Line LayoutManager maintains a +list of breakposs, <literal>vecInlineBreaks</literal>. Each breakposs +refers to an area, in its <literal>position.iLeafPos</literal> +member.</para> + +<para>During the process of finding suitable line breaks, breakposs +are generated until one is found that exceeds the line length. Then +the Line LayoutManager backs up to the previous BP, either to start a +hyphenation try or to create the line break. When it creates a line +break, the last breakposs, which exceeds the line length, is not added +to the list of inline breaks. When it starts a hyphenation try, the +breakposs is added to that list, and removed again after the text for +hyphenation has been obtained. Each time, the corresponding area info +is left in the list of area information objects. As a consequence the +list <literal>vecAreaInfo</literal> is longer than the list +<literal>vecInlineBreaks</literal>, and some areas have no +corresponding breakposs.</para> + +<screen> +wa-ter-staats-in-ge-nieur mi-nis-ters-por-te-feuil-le aandachtstrekker. +0 2 5 1 1 1 2 2 2 2 3 3 3 4 4 6 + 1 3 5 0 3 6 9 0 3 5 0 2 0 + +text: waterstaatsingenieur wa ter staats in | +AreaInfo: 0: 0-20 (removed) 0: 0-2 1: 2-5 2: 5-11 3: 11-13 | +InlineBreaks: 0 (removed) 0 1 2 3 | + too long, hyphenate, | + back up V + +gen genieur _ministersportefeuille _mi nis | +4: 13-15 5: 13-20 6: 20-42 7: 20-23 8: 23-26 | + 4 5 (removed) 5 6 | +too long, too long, hyphenate | +line break, back up | +back up v + +ters tersportefeuille_ ter s por +9: 26-30 10: 26-42 11: 26-29 12: 29-30 13: 30-33 + 7 (removed) 7 8 9 +too long, too long, hyphenate, hyphenation +line break, back up error +back up + +te feuil | le | _aandachtstrekker. +14: 33-35 15: 35-40 | 16: 40-42 | 17: 42-60 +10 11 | 12 | 13 (removed) + last hyphenpoint, | | too long, + line break v | hyphenation fails, + | line break, + v back up + +aandachtstrekker. | etc. +18: 43-60 | +13 | +too long, | +hyphenation fails, | +first BP, | +line break v +</screen> + +<para>A few remarkable points: <orderedlist> + +<listitem> +<simpara>The first AreaInfo object is removed from the list during backing + up. This is because the previous BP, which is + <literal>null</literal>, does not belong to this child layout + manager, and therefore the whole child LM is reset.</simpara> +</listitem> + +<listitem> +<simpara>The last BP, no. 18, exceeds the line length, but because it is the + first BP of this line, it is accepted for the line break.</simpara> +</listitem> + +<listitem> +<simpara>BP 7 at position 29 falls at a point that is not a good hyphenation + point. This is probably caused by the fact that for this line only + the partial word is subjected to hyphenation. On the previous line + the complete word was subjected to hyphenation, and there was no BP + at position 29.</simpara> +</listitem> + +<listitem> +<simpara>For the word "aandachtstrekker." hyphenation fails + (<literal>hyph == null</literal> is returned). This may be due to + the period not being separated from the word. When the period is + removed, the word is properly broken.</simpara> +</listitem> + </orderedlist></para> + </section> + + <section> + <title><literal>TextLayoutManager.getNextBreakPoss</literal></title> + + <para> <itemizedlist spacing="compact"> + <listitem> + <para>If this is the first call to this Text +LayoutManager, initialize <literal>ipdTotal</literal> and record that +this breakposs is the first in <literal>iFlags</literal>.</para> + </listitem> + <listitem> + <para>If leading spaces must be suppressed, suppress all +leading space characters <literal>U+20</literal>. Return if this +finished the text.</para> + </listitem> + <listitem> + <para>For the remaining leading space characters, +<itemizedlist spacing="compact"> + <listitem> + <para>If this is a space <literal>U+20</literal> + or a non-breaking space <literal>U+A0</literal>, + <itemizedlist spacing="compact"> + <listitem> + <para>count it;</para> + </listitem> + <listitem> + <para>if this is the first character and this + is the first breakposs, <itemizedlist spacing="compact"> + <listitem> + <para>if the context has leading spaces, +add it (or <literal>halfWS</literal>?);</para> + </listitem> + <listitem> + <para>else add it (or +<literal>halfWS</literal>?) to the pending space, and add the pending +space to the <literal>space</literal> ipd.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>add the space width to the word +<literal>ipd</literal>.</para> + </listitem> + <listitem> + <para>set the pending space to + <literal>halfWS</literal>.</para> + </listitem> + <listitem> + <para>if this is a non-breaking space +<literal>U+A0</literal>, register it in +<literal>bSawNonSuppressible</literal>.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Else (other space characters), <itemizedlist spacing="compact"> + <listitem> + <para>register it in + <literal>bSawNonSuppressible</literal>.</para> + </listitem> + <listitem> + <para>add the pending space to the space +<literal>ipd</literal>, and clear the pending space.</para> + </listitem> + <listitem> + <para>add the character width to the word + <literal>ipd</literal>.</para> + </listitem> + </itemizedlist></para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>If this finishes the text, <itemizedlist spacing="compact"> + <listitem> + <para>register whether there were any +nonsuppressible spaces (<literal>bSawNonSuppressible</literal>) in +<literal>iFlags</literal>.</para> + </listitem> + <listitem> + <para>pass all the info to + <literal>makeBreakPoss</literal> and + <literal>_return_</literal> its breakposs.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Else, <itemizedlist spacing="compact"> + <listitem> + <para>add pending space.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>If hypenation is on, get the size of the next + syllable: <itemizedlist spacing="compact"> + <listitem> + <para>get the size of the next syllable, +<itemizedlist spacing="compact"> + <listitem> + <para>if successful, add the flags +<literal>BreakPoss.CAN_BREAK_AFTER</literal> and +<literal>BreakPoss.CAN_BREAK_AFTER</literal> in +<literal>iFlags</literal>,</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>add the syllable length to the word + <literal>ipd</literal>.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Else look for a legal line-break: breakable +white-space and certain characters such as '-' which can serve as word +breaks; don't look for hyphenation points here though, <itemizedlist spacing="compact"> + <listitem> + <para>for all following characters: <itemizedlist spacing="compact"> + <listitem> + <para>If this is a newline character +<literal>U+0A</literal>, or if <literal>textInfo.bWrap</literal> and +this is a breakable space, or if this is one of the linebreak +characters ("-/") and it is the first character or the preceding +character is a letter or a digit, <itemizedlist spacing="compact"> + <listitem> + <para>add the flag +<literal>BreakPoss.CAN_BREAK_AFTER</literal> to +<literal>iFlags</literal>,</para> + </listitem> + <listitem> + <para>if this is not a space + <literal>U+20</literal>, <itemizedlist spacing="compact"> + <listitem> + <para>move the counter to the next + character,</para> + </listitem> + <listitem> + <para>if this is a newline +<literal>U+0A</literal>, add the flag +<literal>BreakPoss.FORCE</literal> to +<literal>iFlags</literal>,</para> + </listitem> + <listitem> + <para>else add the character width +to the word <literal>ipd</literal>.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>if the rest of the text consists +of spaces <literal>U+20</literal>, register that the rest is +suppressible at a line break +(<literal>BreakPoss.REST_ARE_SUPPRESS_AT_LB</literal>) in +<literal>iFlags</literal>,</para> + </listitem> + <listitem> + <para>pass all the info to +<literal>makeBreakPoss</literal> and <literal>_return_</literal> its +breakposs.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Else add the character width to the word + <literal>ipd</literal>,</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>and continue with the cycle for the next + character.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>At the end of the text, pass all the info to +<literal>makeBreakPoss</literal> and <literal>_return_</literal> its +breakposs.</para> + </listitem> + </itemizedlist></para> + </section> + + <section> + <title><literal>TextLayoutManager.makeBreakPoss</literal></title> + + <itemizedlist spacing="compact"> + <listitem> + <para>Make word <literal>ipd</literal> into a + <literal>MinOptMax</literal> object.</para> + </listitem> + <listitem> + <para>Add space <literal>ipd</literal> to it.</para> + </listitem> + <listitem> + <para>Add total <literal>ipd</literal> from previous texts + to it.</para> + </listitem> + <listitem> + <para>Create an <literal>AreaInfo</literal> object for this +text fragment and add it to the vector of <literal>AreaInfo</literal> +objects.</para> + </listitem> + <listitem> + <para>Create a breakposs for this text fragment.</para> + </listitem> + <listitem> + <para>Set the total <literal>ipd</literal> to the current + <literal>ipd</literal>.</para> + </listitem> + <listitem> + <para>If the flags contain +<literal>BreakPoss.HYPHENATED</literal>, set the stacking size to the +<literal>ipd</literal> plus the width of the hyphen character,</para> + </listitem> + <listitem> + <para>Else set the stacking size to the + <literal>ipd</literal>.</para> + </listitem> + <listitem> + <para>Set the non-stacking size to the line height, from the + text info.</para> + </listitem> + <listitem> + <para>Register the descender and ascender with the breakposs +object; this is currently commented out.</para> + </listitem> + <listitem> + <para>If this is the end of the text, <itemizedlist spacing="compact"> + <listitem> + <para>add <literal>BreakPoss.ISLAST</literal> to the + flags,</para> + </listitem> + <listitem> + <para>declare the LM finished.</para> + </listitem> + </itemizedlist></para> + </listitem> + <listitem> + <para>Register the flags with the breakposs object</para> + </listitem> + <listitem> + <para>Register the pending space or the absence thereof with +the breakposs object.</para> + </listitem> + <listitem> + <para>Register the leading space or the absence thereof with +the breakposs object.</para> + </listitem> + <listitem> + <para>Return the breakposs object.</para> + </listitem> + </itemizedlist> + + </section> + + </chapter> + +<!-- Local Variables: --> +<!-- current-language-environment: UTF-8 --> +<!-- coding: utf-8 --> +<!-- default-input-method: TeX --> +<!-- End: --> |