blob: 54ca3e54fe20ed5b2cbf77c67726de126ea96b37 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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$ */
package org.apache.fop.layoutmgr.inline;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Line layout possibilities.
*/
public class LineLayoutPossibilities {
/** logger instance */
private static final Log LOG = LogFactory.getLog(LineLayoutPossibilities.class);
private final class Possibility {
private int lineCount;
private double demerits;
private List<LineLayoutManager.LineBreakPosition> breakPositions;
private Possibility(int lc, double dem) {
lineCount = lc;
demerits = dem;
breakPositions = new java.util.ArrayList<LineLayoutManager.LineBreakPosition>(lc);
}
private int getLineCount() {
return lineCount;
}
private double getDemerits() {
return demerits;
}
private void addBreakPosition(LineLayoutManager.LineBreakPosition pos) {
// Positions are always added with index 0 because
// they are created backward, from the last one to
// the first one
breakPositions.add(0, pos);
}
private LineLayoutManager.LineBreakPosition getBreakPosition(int i) {
return breakPositions.get(i);
}
}
private List possibilitiesList;
private List savedPossibilities;
private int minimumIndex;
private int optimumIndex;
private int maximumIndex;
private int chosenIndex;
private int savedOptLineCount;
/** default constructor */
public LineLayoutPossibilities() {
possibilitiesList = new java.util.ArrayList();
savedPossibilities = new java.util.ArrayList();
optimumIndex = -1;
}
/**
* Add possibility.
* @param ln line number
* @param dem demerits
*/
public void addPossibility(int ln, double dem) {
possibilitiesList.add(new Possibility(ln, dem));
if (possibilitiesList.size() == 1) {
// first Possibility added
minimumIndex = 0;
optimumIndex = 0;
maximumIndex = 0;
chosenIndex = 0;
} else {
if (dem < ((Possibility)possibilitiesList.get(optimumIndex)).getDemerits()) {
optimumIndex = possibilitiesList.size() - 1;
chosenIndex = optimumIndex;
}
if (ln < ((Possibility)possibilitiesList.get(minimumIndex)).getLineCount()) {
minimumIndex = possibilitiesList.size() - 1;
}
if (ln > ((Possibility)possibilitiesList.get(maximumIndex)).getLineCount()) {
maximumIndex = possibilitiesList.size() - 1;
}
}
}
/**
* Save in a different array the computed Possibilities,
* so possibilitiesList is ready to store different Possibilities.
* @param bSaveOptLineCount true if should save optimum line count
*/
public void savePossibilities(boolean bSaveOptLineCount) {
if (bSaveOptLineCount) {
savedOptLineCount = getOptLineCount();
} else {
savedOptLineCount = 0;
}
savedPossibilities = possibilitiesList;
possibilitiesList = new java.util.ArrayList();
}
/**
* Replace the Possibilities stored in possibilitiesList with
* the ones stored in savedPossibilities and having the same line number.
*/
public void restorePossibilities() {
int index = 0;
while (savedPossibilities.size() > 0) {
Possibility restoredPossibility = (Possibility) savedPossibilities.remove(0);
if (restoredPossibility.getLineCount() < getMinLineCount()) {
// if the line number of restoredPossibility is less than the minimum one,
// add restoredPossibility at the beginning of the list
possibilitiesList.add(0, restoredPossibility);
// update minimumIndex
minimumIndex = 0;
// shift the other indexes;
optimumIndex++;
maximumIndex++;
chosenIndex++;
} else if (restoredPossibility.getLineCount() > getMaxLineCount()) {
// if the line number of restoredPossibility is greater than the maximum one,
// add restoredPossibility at the end of the list
possibilitiesList.add(possibilitiesList.size(), restoredPossibility);
// update maximumIndex
maximumIndex = possibilitiesList.size() - 1;
index = maximumIndex;
} else {
// find the index of the Possibility that will be replaced
while (index < maximumIndex
&& getLineCount(index) < restoredPossibility.getLineCount()) {
index++;
}
if (getLineCount(index) == restoredPossibility.getLineCount()) {
possibilitiesList.set(index, restoredPossibility);
} else {
// this should not happen
LOG.error("LineLayoutPossibilities restorePossibilities(),"
+ " min= " + getMinLineCount()
+ " max= " + getMaxLineCount()
+ " restored= " + restoredPossibility.getLineCount());
return;
}
}
// update optimumIndex and chosenIndex
if (savedOptLineCount == 0
&& getDemerits(optimumIndex) > restoredPossibility.getDemerits()
|| savedOptLineCount != 0
&& restoredPossibility.getLineCount() == savedOptLineCount) {
optimumIndex = index;
chosenIndex = optimumIndex;
}
}
//log.debug(">> minLineCount = " + getMinLineCount()
// + " optLineCount = " + getOptLineCount() + " maxLineCount() = " + getMaxLineCount());
}
/**
* @param pos a position
* @param i an index into posibilities list
*/
public void addBreakPosition(LineLayoutManager.LineBreakPosition pos, int i) {
((Possibility)possibilitiesList.get(i)).addBreakPosition(pos);
}
/** @return true if can use more lines */
public boolean canUseMoreLines() {
return (getOptLineCount() < getMaxLineCount());
}
/** @return true if can use fewer lines */
public boolean canUseLessLines() {
return (getMinLineCount() < getOptLineCount());
}
/** @return the line count of the minimum index */
public int getMinLineCount() {
return getLineCount(minimumIndex);
}
/** @return the line count of the optimum index */
public int getOptLineCount() {
return getLineCount(optimumIndex);
}
/** @return the line count of the maximum index */
public int getMaxLineCount() {
return getLineCount(maximumIndex);
}
/** @return the line count of the chosen index */
public int getChosenLineCount() {
return getLineCount(chosenIndex);
}
/**
* @param i the posibilities list index
* @return the line count
*/
public int getLineCount(int i) {
return ((Possibility)possibilitiesList.get(i)).getLineCount();
}
/** @return the demerits of the chosen index */
public double getChosenDemerits() {
return getDemerits(chosenIndex);
}
/**
* @param i the posibilities list index
* @return the demerits
*/
public double getDemerits(int i) {
return ((Possibility)possibilitiesList.get(i)).getDemerits();
}
/** @return the possibilities count */
public int getPossibilitiesNumber() {
return possibilitiesList.size();
}
/**
* @param i the break position index
* @return the chosen position
*/
public LineLayoutManager.LineBreakPosition getChosenPosition(int i) {
return ((Possibility)possibilitiesList.get(chosenIndex)).getBreakPosition(i);
}
/**
* @param adj the adjustment
* @return the adjustment or zero
*/
public int applyLineCountAdjustment(int adj) {
if (adj >= (getMinLineCount() - getChosenLineCount())
&& adj <= (getMaxLineCount() - getChosenLineCount())
&& getLineCount(chosenIndex + adj) == getChosenLineCount() + adj) {
chosenIndex += adj;
LOG.debug("chosenLineCount= " + (getChosenLineCount() - adj) + " adjustment= " + adj
+ " => chosenLineCount= " + getLineCount(chosenIndex));
return adj;
} else {
// this should not happen!
LOG.warn("Cannot apply the desired line count adjustment.");
return 0;
}
}
/** print all */
public void printAll() {
System.out.println("++++++++++");
System.out.println(" " + possibilitiesList.size() + " possibility':");
for (int i = 0; i < possibilitiesList.size(); i++) {
System.out.println(" " + ((Possibility)possibilitiesList.get(i)).getLineCount()
+ (i == optimumIndex ? " *" : "")
+ (i == minimumIndex ? " -" : "")
+ (i == maximumIndex ? " +" : ""));
}
System.out.println("++++++++++");
}
}