/* BreakFormula.java
* =========================================================================
* This file is part of the JLaTeXMath Library - http://forge.scilab.org/jlatexmath
*
* Copyright (C) 2011 DENIZET Calixte
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* A copy of the GNU General Public License can be found in the file
* LICENSE.txt provided with the source distribution of this program (see
* the META-INF directory in the source jar). This license can also be
* found on the GNU website at http://www.gnu.org/licenses/gpl.html.
*
* If you did not receive a copy of the GNU General Public License along
* with this program, contact the lead developer, or write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Linking this library statically or dynamically with other modules
* is making a combined work based on this library. Thus, the terms
* and conditions of the GNU General Public License cover the whole
* combination.
*
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce
* an executable, regardless of the license terms of these independent
* modules, and to copy and distribute the resulting executable under terms
* of your choice, provided that you also meet, for each linked independent
* module, the terms and conditions of the license of that module.
* An independent module is a module which is not derived from or based
* on this library. If you modify this library, you may extend this exception
* to your version of the library, but you are not obliged to do so.
* If you do not wish to do so, delete this exception statement from your
* version.
*
*/
package com.himamis.retex.renderer.share;
import java.util.List;
import java.util.Stack;
public final class BreakFormula {
public static Box split(Box box, double width, double interline) {
if (box instanceof HorizontalBox) {
return split((HorizontalBox) box, width, interline);
} else if (box instanceof VerticalBox) {
return split((VerticalBox) box, width, interline);
} else {
return box;
}
}
public static Box split(HorizontalBox hbox0, double width,
double interline) {
VerticalBox vbox = new VerticalBox();
HorizontalBox first;
HorizontalBox second = null;
Stack<Position> positions = new Stack<Position>();
HorizontalBox hbox = hbox0;
while (hbox.width > width && (canBreak(positions, hbox, width)) != hbox.width) {
Position pos = positions.pop();
HorizontalBox[] hboxes = pos.hbox.split(pos.index - 1);
first = hboxes[0];
second = hboxes[1];
while (!positions.isEmpty()) {
pos = positions.pop();
hboxes = pos.hbox.splitRemove(pos.index);
hboxes[0].add(first);
hboxes[1].add(0, second);
first = hboxes[0];
second = hboxes[1];
}
vbox.add(first, interline);
hbox = second;
}
if (second != null) {
vbox.add(second, interline);
return vbox;
}
return hbox;
}
private static Box split(VerticalBox vbox, double width, double interline) {
VerticalBox newBox = new VerticalBox();
for (Box box : vbox.children) {
newBox.add(split(box, width, interline));
}
return newBox;
}
private static double canBreak(Stack<Position> stack, HorizontalBox hbox, double width) {
List<Box> children = hbox.children;
double[] cumWidth = new double[children.size() + 1];
cumWidth[0] = 0;
for (int i = 0; i < children.size(); i++) {
Box box = children.get(i);
cumWidth[i + 1] = cumWidth[i] + box.width;
if (cumWidth[i + 1] > width) {
int pos = getBreakPosition(hbox, i);
if (box instanceof HorizontalBox) {
Stack<Position> newStack = new Stack<Position>();
double w = canBreak(newStack, (HorizontalBox) box, width - cumWidth[i]);
if (w != box.width && (cumWidth[i] + w <= width || pos == -1)) {
stack.push(new Position(i - 1, hbox));
stack.addAll(newStack);
return cumWidth[i] + w;
}
}
if (pos != -1) {
stack.push(new Position(pos, hbox));
return cumWidth[pos];
}
}
}
return hbox.width;
}
private static int getBreakPosition(HorizontalBox hb, int i) {
if (hb.breakPositions == null) {
return -1;
}
if (hb.breakPositions.size() == 1 && hb.breakPositions.get(0) <= i) {
return hb.breakPositions.get(0);
}
int pos = 0;
for (; pos < hb.breakPositions.size(); pos++) {
if (hb.breakPositions.get(pos) > i) {
if (pos == 0) {
return -1;
}
return hb.breakPositions.get(pos - 1);
}
}
return hb.breakPositions.get(pos - 1);
}
private static class Position {
int index;
HorizontalBox hbox;
Position(int index, HorizontalBox hbox) {
this.index = index;
this.hbox = hbox;
}
}
}