<commit_before>/*
 * Copyright 1999-2005 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: LineLayoutManager.java,v 1.17 2004/04/02 10:38:29 cbowditch Exp $ */

package org.apache.fop.layoutmgr.inline;

import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.Block;
import org.apache.fop.fo.properties.CommonHyphenation;
import org.apache.fop.hyphenation.Hyphenation;
import org.apache.fop.hyphenation.Hyphenator;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.BreakingAlgorithm;
import org.apache.fop.layoutmgr.ElementListObserver;
import org.apache.fop.layoutmgr.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue;
import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.KnuthPossPosIter;
import org.apache.fop.layoutmgr.KnuthSequence;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.LeafPosition;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.SpaceSpecifier;
import org.apache.fop.area.Area;
import org.apache.fop.area.LineArea;
import org.apache.fop.area.inline.InlineArea;

import java.util.ListIterator;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;

import org.apache.fop.traits.MinOptMax;

/**
 * LayoutManager for lines. It builds one or more lines containing
 * inline areas generated by its sub layout managers.
 * A break is found for each line which may contain one of more
 * breaks from the child layout managers.
 * Once a break is found then it is return for the parent layout
 * manager to handle.
 * When the areas are being added to the page this manager
 * creates a line area to contain the inline areas added by the
 * child layout managers.
 */
public class LineLayoutManager extends InlineStackingLayoutManager 
                               implements BlockLevelLayoutManager {

    private Block fobj; 
    
    private void initialize() {
        bTextAlignment = fobj.getTextAlign();
        bTextAlignmentLast = fobj.getTextAlignLast();
        textIndent = fobj.getTextIndent();
        hyphProps = fobj.getCommonHyphenation();
        
        //
        if (bTextAlignment != EN_JUSTIFY && bTextAlignmentLast == EN_JUSTIFY) {
            effectiveAlignment = 0;
        } else {
            effectiveAlignment = bTextAlignment;
        }
    }

    /**
     * Private class to store information about inline breaks.
     * Each value holds the start and end indexes into a List of
     * inline break positions.
     */
    private static class LineBreakPosition extends LeafPosition {
        // int iPos;
        int iParIndex; // index of the Paragraph this Position refers to
        int availableShrink;
        int availableStretch;
        int difference;
        double dAdjust; // Percentage to adjust (stretch or shrink)
        double ipdAdjust; // Percentage to adjust (stretch or shrink)
        int startIndent;
        int lineHeight;
        int lineWidth;
        int baseline;
        int topShift;
        int bottomShift;

        LineBreakPosition(LayoutManager lm, int index, int iBreakIndex,
                          int shrink, int stretch, int diff,
                          double ipdA, double adjust, int ind,
                          int lh, int lw, int bl, int ts, int bs) {
            super(lm, iBreakIndex);
            availableShrink = shrink;
            availableStretch = stretch;
            difference = diff;
            iParIndex = index;
            ipdAdjust = ipdA;
            dAdjust = adjust;
            startIndent = ind;
            lineHeight = lh;
            lineWidth = lw;
            baseline = bl;
            topShift = ts;
            bottomShift = bs;
        }
        
    }


    /** Break positions returned by inline content. */
    private List vecInlineBreaks = new java.util.ArrayList();

    private int bTextAlignment = EN_JUSTIFY;
    private int bTextAlignmentLast;
    private int effectiveAlignment;
    private Length textIndent;
    private int iIndents = 0;
    private CommonHyphenation hyphProps;
    //private LayoutProps layoutProps;

    private int lineHeight;
    private int lead;
    private int follow;
    // offset of the middle baseline with respect to the main baseline
    private int middleShift;

    private List knuthParagraphs = null;
    private int iReturnedLBP = 0;
    private int iStartElement = 0;
    private int iEndElement = 0;

    //     parameters of Knuth's algorithm:
    // penalty value for flagged penalties
    private int flaggedPenalty = 50;

    private LineLayoutPossibilities lineLayouts;
    private List lineLayoutsList;
    private int iLineWidth = 0;

    // this constant is used to create elements when text-align is center:
    // every TextLM descendant of LineLM must use the same value, 
    // otherwise the line breaking algorithm does not find the right
    // break point
    public static final int DEFAULT_SPACE_WIDTH = 3336;


    // this class is used to remember
    // which was the first element in the paragraph
    // returned by each LM
    private class Update {
        private InlineLevelLayoutManager inlineLM;
        private int iFirstIndex;

        public Update(InlineLevelLayoutManager lm, int index) {
            inlineLM = lm;
            iFirstIndex = index;
        }
    }

    // this class represents a paragraph
    private class Paragraph extends KnuthSequence {
        // space at the end of the last line (in millipoints)
        private MinOptMax lineFiller;
        private int textAlignment;
        private int textAlignmentLast;
        private int textIndent;
        private int lineWidth;
        // the LM which created the paragraph
        private LineLayoutManager layoutManager;

        public Paragraph(LineLayoutManager llm, int alignment, int alignmentLast,
                         int indent) {
            super(true);
            layoutManager = llm;
            textAlignment = alignment;
            textAlignmentLast = alignmentLast;
            textIndent = indent;
        }

        public void startParagraph(int lw) {
            lineWidth = lw;
            startSequence();
        }

        public void startSequence() {
            // set the minimum amount of empty space at the end of the
            // last line
            if (bTextAlignment == EN_CENTER) {
                lineFiller = new MinOptMax(0); 
            } else {
                lineFiller = new MinOptMax(0, (int)(lineWidth / 12), lineWidth); 
            }

            // add auxiliary elements at the beginning of the paragraph
            if (bTextAlignment == EN_CENTER && bTextAlignmentLast != EN_JUSTIFY) {
                this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0,
                                       null, false));
                ignoreAtStart ++;
            }

            // add the element representing text indentation
            // at the beginning of the first paragraph
            if (knuthParagraphs.size() == 0
                        && fobj.getTextIndent().getValue() != 0) {
                this.add(new KnuthInlineBox(fobj.getTextIndent().getValue(), 0, 0, 0,
                                      null, false));
                ignoreAtStart ++;
            }
        }

        public void endParagraph() {
            KnuthSequence finishedPar = this.endSequence();
            if (finishedPar != null) {
                knuthParagraphs.add(finishedPar);
            }
        }

        public KnuthSequence endSequence() {
            // remove glue and penalty item at the end of the paragraph
            while (this.size() > ignoreAtStart
                   && !((KnuthElement)this.get(this.size() - 1)).isBox()) {
                this.remove(this.size() - 1);
            }
            if (this.size() > ignoreAtStart) {
                if (bTextAlignment == EN_CENTER
                    && bTextAlignmentLast != EN_JUSTIFY) {
                    this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0,
                                           null, false));
                    this.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
                                              false, null, false));
                    ignoreAtEnd = 2;
                } else if (bTextAlignmentLast != EN_JUSTIFY) {
                    // add the elements representing the space
                    // at the end of the last line
                    // and the forced break
                    this.add(new KnuthPenalty(0, KnuthElement.INFINITE, 
                                              false, null, false));
                    this.add(new KnuthGlue(lineFiller.opt, 
                            lineFiller.max - lineFiller.opt, 
                            lineFiller.opt - lineFiller.min, null, false));
                    this.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
                                              false, null, false));
                    ignoreAtEnd = 3;
                } else {
                    // add only the element representing the forced break
                    this.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
                                              false, null, false));
                    ignoreAtEnd = 1;
                }
                return this;
            } else {
                this.clear();
                return null;
            }
        }

        private void addALetterSpace() {
            KnuthBox prevBox = (KnuthBox) removeLast();
            LinkedList oldList = new LinkedList();
            // if there are two consecutive KnuthBoxes the
            // first one does not represent a whole word,
            // so it must be given one more letter space
            if (!prevBox.isAuxiliary()) {
                // if letter spacing is constant,
                // only prevBox needs to be replaced;
                oldList.add(prevBox);
            } else {
                // prevBox is the last element
                // in the sub-sequence
                //   <box> <aux penalty> <aux glue> <aux box>
                // the letter space is added to <aux glue>,
                // while the other elements are not changed
                oldList.add(prevBox);
                oldList.addFirst((KnuthGlue) removeLast());
                oldList.addFirst((KnuthPenalty) removeLast());<commit_msg>Fix for bug 35940 Some more checks in order to remove all the elements representing trailing spaces at the end of a paragraph<commit_after>/*
 * Copyright 1999-2005 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: LineLayoutManager.java,v 1.17 2004/04/02 10:38:29 cbowditch Exp $ */

package org.apache.fop.layoutmgr.inline;

import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.Block;
import org.apache.fop.fo.properties.CommonHyphenation;
import org.apache.fop.hyphenation.Hyphenation;
import org.apache.fop.hyphenation.Hyphenator;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.BreakingAlgorithm;
import org.apache.fop.layoutmgr.ElementListObserver;
import org.apache.fop.layoutmgr.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue;
import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.KnuthPossPosIter;
import org.apache.fop.layoutmgr.KnuthSequence;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.LeafPosition;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.SpaceSpecifier;
import org.apache.fop.area.Area;
import org.apache.fop.area.LineArea;
import org.apache.fop.area.inline.InlineArea;

import java.util.ListIterator;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;

import org.apache.fop.traits.MinOptMax;

/**
 * LayoutManager for lines. It builds one or more lines containing
 * inline areas generated by its sub layout managers.
 * A break is found for each line which may contain one of more
 * breaks from the child layout managers.
 * Once a break is found then it is return for the parent layout
 * manager to handle.
 * When the areas are being added to the page this manager
 * creates a line area to contain the inline areas added by the
 * child layout managers.
 */
public class LineLayoutManager extends InlineStackingLayoutManager 
                               implements BlockLevelLayoutManager {

    private Block fobj; 
    
    private void initialize() {
        bTextAlignment = fobj.getTextAlign();
        bTextAlignmentLast = fobj.getTextAlignLast();
        textIndent = fobj.getTextIndent();
        hyphProps = fobj.getCommonHyphenation();
        
        //
        if (bTextAlignment != EN_JUSTIFY && bTextAlignmentLast == EN_JUSTIFY) {
            effectiveAlignment = 0;
        } else {
            effectiveAlignment = bTextAlignment;
        }
    }

    /**
     * Private class to store information about inline breaks.
     * Each value holds the start and end indexes into a List of
     * inline break positions.
     */
    private static class LineBreakPosition extends LeafPosition {
        // int iPos;
        int iParIndex; // index of the Paragraph this Position refers to
        int availableShrink;
        int availableStretch;
        int difference;
        double dAdjust; // Percentage to adjust (stretch or shrink)
        double ipdAdjust; // Percentage to adjust (stretch or shrink)
        int startIndent;
        int lineHeight;
        int lineWidth;
        int baseline;
        int topShift;
        int bottomShift;

        LineBreakPosition(LayoutManager lm, int index, int iBreakIndex,
                          int shrink, int stretch, int diff,
                          double ipdA, double adjust, int ind,
                          int lh, int lw, int bl, int ts, int bs) {
            super(lm, iBreakIndex);
            availableShrink = shrink;
            availableStretch = stretch;
            difference = diff;
            iParIndex = index;
            ipdAdjust = ipdA;
            dAdjust = adjust;
            startIndent = ind;
            lineHeight = lh;
            lineWidth = lw;
            baseline = bl;
            topShift = ts;
            bottomShift = bs;
        }
        
    }


    /** Break positions returned by inline content. */
    private List vecInlineBreaks = new java.util.ArrayList();

    private int bTextAlignment = EN_JUSTIFY;
    private int bTextAlignmentLast;
    private int effectiveAlignment;
    private Length textIndent;
    private int iIndents = 0;
    private CommonHyphenation hyphProps;
    //private LayoutProps layoutProps;

    private int lineHeight;
    private int lead;
    private int follow;
    // offset of the middle baseline with respect to the main baseline
    private int middleShift;

    private List knuthParagraphs = null;
    private int iReturnedLBP = 0;
    private int iStartElement = 0;
    private int iEndElement = 0;

    //     parameters of Knuth's algorithm:
    // penalty value for flagged penalties
    private int flaggedPenalty = 50;

    private LineLayoutPossibilities lineLayouts;
    private List lineLayoutsList;
    private int iLineWidth = 0;

    // this constant is used to create elements when text-align is center:
    // every TextLM descendant of LineLM must use the same value, 
    // otherwise the line breaking algorithm does not find the right
    // break point
    public static final int DEFAULT_SPACE_WIDTH = 3336;


    // this class is used to remember
    // which was the first element in the paragraph
    // returned by each LM
    private class Update {
        private InlineLevelLayoutManager inlineLM;
        private int iFirstIndex;

        public Update(InlineLevelLayoutManager lm, int index) {
            inlineLM = lm;
            iFirstIndex = index;
        }
    }

    // this class represents a paragraph
    private class Paragraph extends KnuthSequence {
        // space at the end of the last line (in millipoints)
        private MinOptMax lineFiller;
        private int textAlignment;
        private int textAlignmentLast;
        private int textIndent;
        private int lineWidth;
        // the LM which created the paragraph
        private LineLayoutManager layoutManager;

        public Paragraph(LineLayoutManager llm, int alignment, int alignmentLast,
                         int indent) {
            super(true);
            layoutManager = llm;
            textAlignment = alignment;
            textAlignmentLast = alignmentLast;
            textIndent = indent;
        }

        public void startParagraph(int lw) {
            lineWidth = lw;
            startSequence();
        }

        public void startSequence() {
            // set the minimum amount of empty space at the end of the
            // last line
            if (bTextAlignment == EN_CENTER) {
                lineFiller = new MinOptMax(0); 
            } else {
                lineFiller = new MinOptMax(0, (int)(lineWidth / 12), lineWidth); 
            }

            // add auxiliary elements at the beginning of the paragraph
            if (bTextAlignment == EN_CENTER && bTextAlignmentLast != EN_JUSTIFY) {
                this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0,
                                       null, false));
                ignoreAtStart ++;
            }

            // add the element representing text indentation
            // at the beginning of the first paragraph
            if (knuthParagraphs.size() == 0
                        && fobj.getTextIndent().getValue() != 0) {
                this.add(new KnuthInlineBox(fobj.getTextIndent().getValue(), 0, 0, 0,
                                      null, false));
                ignoreAtStart ++;
            }
        }

        public void endParagraph() {
            KnuthSequence finishedPar = this.endSequence();
            if (finishedPar != null) {
                knuthParagraphs.add(finishedPar);
            }
        }

        public KnuthSequence endSequence() {
            // remove elements representig spaces at the end of the paragraph
            removeElementsForTrailingSpaces();
            if (this.size() > ignoreAtStart) {
                if (bTextAlignment == EN_CENTER
                    && bTextAlignmentLast != EN_JUSTIFY) {
                    this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0,
                                           null, false));
                    this.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
                                              false, null, false));
                    ignoreAtEnd = 2;
                } else if (bTextAlignmentLast != EN_JUSTIFY) {
                    // add the elements representing the space
                    // at the end of the last line
                    // and the forced break
                    this.add(new KnuthPenalty(0, KnuthElement.INFINITE, 
                                              false, null, false));
                    this.add(new KnuthGlue(lineFiller.opt, 
                            lineFiller.max - lineFiller.opt, 
                            lineFiller.opt - lineFiller.min, null, false));
                    this.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
                                              false, null, false));
                    ignoreAtEnd = 3;
                } else {
                    // add only the element representing the forced break
                    this.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
                                              false, null, false));
                    ignoreAtEnd = 1;
                }
                return this;
            } else {
                this.clear();
                return null;
            }
        }

        /**
         * remove elements representing spaces at the end of the paragraph;
         * the text could have one or more trailing spaces, each of them
         * being either a normal space or a non-breaking space;
         * according to the alignment, the sub-sequence of elements
         * representing each space has a different "pattern"
         */
        private void removeElementsForTrailingSpaces() {
            KnuthElement removedElement;
            while (this.size() > ignoreAtStart
                   && ((KnuthElement) this.get(this.size() - 1)).isGlue()) {
                if (textAlignment == EN_CENTER) {
                    // centered text: the pattern is
                    //     <glue> <penaly> <glue> <box> <penaly> <glue>
                    removedElement = (KnuthGlue) this.remove(this.size() - 1);
                    removedElement = (KnuthPenalty) this.remove(this.size() - 1);
                    removedElement = (KnuthBox) this.remove(this.size() - 1);
                    removedElement = (KnuthGlue) this.remove(this.size() - 1);
                    removedElement = (KnuthPenalty) this.remove(this.size() - 1);
                    removedElement = (KnuthGlue) this.remove(this.size() - 1);
                } else if (textAlignment == EN_START || textAlignment == EN_END) {
                    // left- or right-aligned text: the pattern is
                    //     <glue> <penalty> <glue>
                    removedElement = (KnuthGlue) this.remove(this.size() - 1);
                    removedElement = (KnuthPenalty) this.remove(this.size() - 1);
                    removedElement = (KnuthGlue) this.remove(this.size() - 1);
                } else {
                    // justified text: the pattern is
                    //     <glue>
                    removedElement = (KnuthGlue) this.remove(this.size() - 1);
                }
                // if the space was a non-breaking one, there is also a penalty
                if (this.size() > ignoreAtStart
                    && ((KnuthElement) this.get(this.size() - 1)).isPenalty()) {
                    removedElement = (KnuthPenalty) this.remove(this.size() - 1);
                }
            }
        }

        private void addALetterSpace() {
            KnuthBox prevBox = (KnuthBox) removeLast();
            LinkedList oldList = new LinkedList();
            // if there are two consecutive KnuthBoxes the
            // first one does not represent a whole word,
            // so it must be given one more letter space
            if (!prevBox.isAuxiliary()) {
                // if letter spacing is constant,
                // only prevBox needs to be replaced;
                oldList.add(prevBox);
            } else {
                // prevBox is the last element
                // in the sub-sequence
                //   <box> <aux penalty> <aux glue> <aux box>
                // the letter space is added to <aux glue>,
                // while the other elements are not changed
                oldList.add(prevBox);
                oldList.addFirst((KnuthGlue) removeLast());
                oldList.addFirst((KnuthPenalty) removeLast());
{'fraction_non_alphanumeric': 0.07745308636971589, 'fraction_numerical': 0.0059173995865926315, 'mean_word_length': 1.8436095424685952, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 26, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5526678', 'n_tokens_mistral': 6600, 'n_tokens_neox': 6233, 'n_words': 2006}