package de.uniulm.mathematik.typo.items; import java.util.*; public class TriangleLineBreaker extends BasicLineBreaker { public static class Constructor implements LineBreakerFactory.Constructor { public LineBreaker create() { return new TriangleLineBreaker(); } } // class Constructor private class Word { public HorizontalSequence word; public Item bp; public boolean last; public Word(HorizontalSequence hseq, Item item) { word = hseq; bp = item; last = false; } public Width getWidth() { Width sum = new Width(word.getWidth()); sum.add(bp); if (last) { Item hyphen = bp.getHyphen(); if (hyphen != null) { sum.add(hyphen); } } return sum; } } private void addLine(LinkedList lines, LinkedList line, int twidth, int parwidth) { HorizontalSequence t = new SimpleHorizontalSequence(); for (Word w: line) { t.add(w.word); t.add(w.bp); if (w.last) { Item hyphen = w.bp.getHyphen(); if (hyphen != null) { t.add(hyphen); } } } HorizontalFitter.fit(t, twidth); HorizontalSequence s = new SimpleHorizontalSequence(); Item glue1 = new Glue(0, Item.INFINITY, 0); s.add(glue1); s.add(t); Item glue2 = new Glue(0, Item.INFINITY, 0); s.add(glue2); if (wrapper != null) { s = wrapper.wrap(s); } HorizontalFitter.fit(s, parwidth); Item hbox = new HorizontalBox(s); if (hboxwrapper != null) { hbox = hboxwrapper.wrap(hbox); } lines.addFirst(hbox); } public Item breakParagraph(HorizontalSequence hseq, int parwidth, int baselineskip) { // compute individual line widths of the triangle LinkedList widths; widths = new LinkedList(); int lwidth = parwidth; while (lwidth >= 3 * baselineskip) { lwidth -= 2 * baselineskip; widths.addFirst(new Integer(lwidth)); } // reverse the list of words LinkedList words; words = new LinkedList(); for (HorizontalSequence word: hseq.getWords()) { words.addFirst(word); } // generate lines LinkedList lines; lines = new LinkedList(); LinkedList line; line = null; Width linewidth = null; // current line boolean first = true; while (words.size() > 0 && widths.size() > 0) { HorizontalSequence word = words.pop(); Item nextbp; if (first) { // do not use the infinitely stretchable bp // which has been delivered by the sequencer nextbp = new Penalty(-Item.INFINITY, false); first = false; } else { nextbp = word.getFollowingBreakpoint(); } Word w = new Word(word, nextbp); if (line == null) { line = new LinkedList(); line.addFirst(w); w.last = true; linewidth = w.getWidth(); } else { int intendedWidth; if (widths.size() == 0) { intendedWidth = parwidth; } else { intendedWidth = widths.peek().intValue(); } Width sum = new Width(linewidth); sum.add(w.getWidth()); if (sum.getWidth() - sum.getShrinkability() <= intendedWidth) { line.addFirst(w); linewidth = sum; } else { if (lines == null) { lines = new LinkedList(); } if (widths.size() > 0) { widths.pop(); } addLine(lines, line, intendedWidth, parwidth); line.clear(); line.addFirst(w); w.last = true; linewidth = w.getWidth(); } } } // create upper box Item upperbox = null; if (words.size() > 0 || line.size() > 0) { HorizontalSequence block = new SimpleHorizontalSequence(); Item lastbp = null; if (line != null) { while (words.size() > 0) { HorizontalSequence ws = words.pollLast(); if (lastbp != null) { block.add(lastbp); } block.add(ws); lastbp = ws.getFollowingBreakpoint(); } for (Word w: line) { if (lastbp != null) { block.add(lastbp); } block.add(w.word); lastbp = w.bp; } } if (lastbp != null && lastbp.getHyphen() != null) { block.add(lastbp.getHyphen()); } block.add(new Penalty(-Item.INFINITY, false)); LineBreaker lb = new TotalFitLineBreaker(); upperbox = lb.breakParagraph(block, parwidth, baselineskip); } // create lower virtual box VerticalBox lowerbox = new VerticalBox(baselineskip); for (Item l: lines) { lowerbox.add(l); } if (upperbox == null) { return lowerbox; } else { VerticalStack vbox = new VerticalStack(); vbox.add(upperbox); vbox.add(lowerbox); return vbox; } } } // class TriangleLineBreaker