final int width = booklet.width;
final int height = booklet.height;
// App Settings
final AlbiteFont fontPlain = booklet.fontPlain;
final AlbiteFont fontItalic = booklet.fontItalic;
final int spaceWidth = fontPlain.charWidth(' ');
//#debug
AlbiteMIDlet.LOGGER.log("Spacewidth: " + spaceWidth);
int dashWidth = 0;
final int fontHeight = booklet.fontHeight;
final int fontHeightX2 = 2 * fontHeight;
final int fontIndent = booklet.fontIndent;
//#if !(TinyMode || TinyModeExport || LightMode || LightModeExport)
final ZLTextTeXHyphenator hyphenator = booklet.hyphenator;
//#endif
// Chapter settings
final String chapterPath = booklet.getChapter().getPath();
final char[] buffer = booklet.getTextBuffer();
final int bufferSize;
final Archive bookFile = booklet.bookArchive;
final Vector images = ip.images;
byte style;
boolean center;
byte color;
AlbiteFont font;
HyphenatedTextRegion lastHyphenatedWord;
boolean startsNewParagraph;
TextParser parser = ip.parser;
int wordPixelWidth; //word width in pixels
Vector wordsOnThisLine = new Vector(20); //RegionTexts
boolean firstWord;
int posX = 0;
int posY = 0;
Vector regionsTemp;
if (images.isEmpty()) {
//text mode
regionsTemp = new Vector(300);
parser.position = end = start = ip.position;
parser.length = ip.length;
bufferSize = buffer.length;
style = ip.style;
center = ip.center;
lastHyphenatedWord = ip.lastHyphenatedWord;
startsNewParagraph = ip.startsNewParagraph;
} else {
//image mode
ImageRegion ri = (ImageRegion) images.firstElement();
images.removeElementAt(0);
imageRegion = ri;
regionsTemp = new Vector(40);
posY = 0;
bufferSize = ri.altTextBufferPosition + ri.altTextBufferLength;
parser.position = end = start = ri.altTextBufferPosition;
parser.length = 0;
style = ITALIC;
center = true;
lastHyphenatedWord = null;
startsNewParagraph = true;
}
/*
* Setup font & color, based on style value from previous page.
*/
font = chooseFont(fontPlain, fontItalic, style);
color = chooseTextColor(style);
boolean lastLine = false;
boolean firstLine = true;
boolean lineBreak = false;
page:
while (true) {
/*
* There is no more space for new lines,
* so the page is done.
*/
if (posY >= height - fontHeight) {
break;
}
/*
* Check if it is the last line of the page
*/
if (posY >= height - (fontHeightX2)) {
lastLine = true;
}
/*
* NB: posX & posY are in pixels, pos is in chars.
*/
posX = 0;
firstWord = true;
/*
* Clear the cache that will hold all the elements on the line
*/
wordsOnThisLine.removeAllElements();
/*
* Indent the line, if it starts a new paragraph.
*/
if (startsNewParagraph) {
posX = fontIndent;
}
line:
while (true) {
/*
* Parse on
*/
if (!parser.parseNext(buffer, bufferSize)) {
//#ifdef DEBUG_PARSER
//# AlbiteMIDlet.LOGGER.log("parser done");
//#endif
/* No more chars to read */
if (imageRegion == null) {
ip.bufferRead = true;
}
lineBreak = true;
if (wordsOnThisLine.size() > 0) {
positionWordsOnLine(
wordsOnThisLine, regionsTemp, width,
posY, spaceWidth, fontIndent, lineBreak,
startsNewParagraph, center);
}
break page;
}
//#ifdef DEBUG_PARSER
//# AlbiteMIDlet.LOGGER.log(
//# "parser: _"
//# + new String(
//# buffer, parser.position, parser.length)
//# + "_, "
//# + parser.position + " / "
//# + parser.length
//# + " state: " + parser.state + "\n");
//#endif
/*
* Logic for possible parsing states.
*/
final int state = parser.state;
switch (state) {
case TextParser.STATE_PASS:
continue line;
case TextParser.STATE_NEW_SOFT_LINE:
if (posX == 0) {
/*
* Only if it's on the next line
*/
startsNewParagraph = true;
}
if (!(posX > (startsNewParagraph ? fontIndent : 0))) {
continue line;
}
case TextParser.STATE_NEW_LINE: //linebreak
if (!firstLine || (posX >
(startsNewParagraph ? fontIndent : 0)
)) {
lineBreak = true;
break line;
} else {
/* don't start a page with blank lines */
continue line;
}
case TextParser.STATE_STYLING:
/* enable styling */
if (parser.enableBold) {
style |= BOLD;
}
if (parser.enableItalic) {
style |= ITALIC;
}
if (parser.enableHeading) {
style |= HEADING;
}
if (parser.enableCenterAlign) {
center = true;
}
if (parser.disableCenterAlign) {
center = false;
}
/* disable styling */
if (parser.disableBold) {
style &= ~BOLD;
}
if (parser.disableItalic) {
style &= ~ITALIC;
}
if (parser.disableHeading) {
style &= ~HEADING;
}
/* setup font & color */
font = chooseFont(fontPlain,
fontItalic, style);
color = chooseTextColor(style);
continue line;
case TextParser.STATE_IMAGE:
if (booklet.renderImages) {
ImageRegion ri = new ImageRegion(
(bookFile == null
? null
: bookFile.getEntry(
RandomReadingFile
.relativeToAbsoluteURL(
chapterPath +
new String(buffer,
parser.imageURLPosition,
parser.imageURLLength))
)),
parser.imageTextPosition,
parser.imageTextLength);
images.addElement(ri);
}
continue line;
case TextParser.STATE_RULER:
regionsTemp.addElement(
new RulerRegion(
(short) 0,
(short) posY,
(short) width,
(short) font.getLineHeight(),
parser.position,
ColorScheme.COLOR_TEXT));
break line;
default:
/*
* There is nothing to do. It must be
* STATE_NORMAL
*/
}
if (parser.length == 0) {
continue line;
}
wordPixelWidth = font.charsWidth(buffer,
parser.position, parser.length);
if (!firstWord) {
/*
* If it is not the first word, it will need the
* space(s) before it
*/
posX += font.charWidth(' ');
}
/*
* word FITS on the line without need to split it
*/
if (wordPixelWidth + posX <= width) {
/*
* if a hyphenated word chain was being build,
* this is the <i>last</i> chunk of it
*/
if (lastHyphenatedWord != null) {
if (parser.length > 0) {
HyphenatedTextRegion rt =
new HyphenatedTextRegion(
(short) 0, (short) 0,
(short) wordPixelWidth,
(short) fontHeight,
lastHyphenatedWord,
parser.position,
parser.length);
lastHyphenatedWord = null;
wordsOnThisLine.addElement(rt);
}
} else {
/*
* Just add a whole word to the line
*/
if (parser.length > 0) {
wordsOnThisLine.addElement(
new TextRegion((short) 0, (short) 0,
(short) wordPixelWidth,
(short) fontHeight, parser.position,
parser.length, style, color));
}
}
posX += wordPixelWidth;
firstWord = false;
} else {
/*
* try to hyphenate word
*/
dashWidth = font.charWidth('-');
//#if !(TinyMode || TinyModeExport || LightMode || LightModeExport)
if (hyphenator != null) {
ZLTextHyphenationInfo info = hyphenator.getInfo(
buffer, parser.position, parser.length);
/*
* try to hyphenate word, so that the largest
* possible chunk is on this line
*/
/*
* wordInfo.length - 2: starts from one before
* the last
*/
for (int i = parser.length - 2; i > 0; i--) {
if (info.isHyphenationPossible(i)) {
wordPixelWidth = font.charsWidth(buffer,
parser.position, i) + dashWidth;
/*
* This part of the word fits on the line
*/
if (wordPixelWidth < width - posX) {
/*
* If the word chunk already ends with a
* dash, include it.
*/
if (buffer[parser.position + i]
== '-') {
i++;
}
if (i > 0) {
HyphenatedTextRegion rt;
if (lastHyphenatedWord != null){
rt = new
HyphenatedTextRegion(
(short) 0, (short) 0,
(short) wordPixelWidth,
(short) fontHeight,
lastHyphenatedWord,
parser.position,
i);
} else {
rt = new
HyphenatedTextRegion(
(short) 0, (short) 0,
(short) wordPixelWidth,
(short) fontHeight,
parser.position,
parser.length,
style,
color,
parser.position,
i);
}
wordsOnThisLine.addElement(rt);
lastHyphenatedWord = rt;
}
parser.position += i;
parser.length = 0;
posX += wordPixelWidth;
firstWord = false;
/* the word was hyphented */
break line;
}
}
}
}
//#endif
/*
* The word could not be hyphenated. Could it fit
* into a single line at all?
*/
if (font.charsWidth(buffer, parser.position,
parser.length) > width) {
/* This word neither hyphenates, nor does it
* fit at all on a single line, so one should
* force hyphanation on it!
*/
for (int i = parser.length - 2; i > 0; i--) {
wordPixelWidth = font.charsWidth(buffer,
parser.position, i) + dashWidth;
if (wordPixelWidth < width - posX) {
/*
* If the word chunk already ends with a