bool ScrollToEndOfTextAction::isEnabled() const {
	if (!isVisible()) {
		return false;
	}
	ZLTextWordCursor cursor = FBReader::Instance().bookTextView().textArea().endCursor();
	return cursor.isNull() || !cursor.isEndOfParagraph() || !cursor.paragraphCursor().isLast();
}
ZLTextWordCursor ZLTextAreaController::findStart(const ZLTextWordCursor &end, SizeUnit unit, int size) {
	ZLTextWordCursor start = end;
	size -= paragraphHeight(start, true, unit);
	bool positionChanged = !start.isStartOfParagraph();
	start.moveToParagraphStart();
	while (size > 0) {
		if (positionChanged && start.paragraphCursor().isEndOfSection()) {
			break;
		}
		if (!start.previousParagraph()) {
			break;
		}
		if (!start.paragraphCursor().isEndOfSection()) {
			positionChanged = true;
		}
		size -= paragraphHeight(start, false, unit);
	}
	skip(start, unit, -size);

	if (unit != LINE_UNIT) {
		bool sameStart = start == end;
		if (!sameStart && start.isEndOfParagraph() && end.isStartOfParagraph()) {
			ZLTextWordCursor startCopy = start;
			startCopy.nextParagraph();
			sameStart = startCopy == end;
		}
		if (sameStart) {
			start = findStart(end, LINE_UNIT, 1);
		}
	}

	return start;
}
ZLTextWordCursor ZLTextAreaController::buildInfos(const ZLTextWordCursor &start) {
	myArea.myLineInfos.clear();

	ZLTextWordCursor cursor = start;
	int textHeight = myArea.height();
	int counter = 0;
	do {
		ZLTextWordCursor paragraphEnd = cursor;
		paragraphEnd.moveToParagraphEnd();
		ZLTextWordCursor paragraphStart = cursor;
		paragraphStart.moveToParagraphStart();

		ZLTextArea::Style style(myArea, myArea.myProperties.baseStyle());
		style.applyControls(paragraphStart, cursor);
		ZLTextLineInfoPtr info = new ZLTextLineInfo(cursor, style.textStyle(), style.bidiLevel());

		while (!info->End.isEndOfParagraph()) {
			info = myArea.processTextLine(style, info->End, paragraphEnd);
			textHeight -= info->Height + info->Descent;
			if ((textHeight < 0) && (counter > 0)) {
				break;
			}
			textHeight -= info->VSpaceAfter;
			cursor = info->End;
			myArea.myLineInfos.push_back(info);
			if (textHeight < 0) {
				break;
			}
			++counter;
		}
	} while (cursor.isEndOfParagraph() && cursor.nextParagraph() && !cursor.paragraphCursor().isEndOfSection() && (textHeight >= 0));

	return cursor;
}
// Added by John to enable caller to get text from current visible page.
void ZLTextSelectionModel::text(std::string & text, int max)
{
    text.clear();
    ZLTextWordCursor start = myView.startCursor();
    ZLTextWordCursor end = myView.endCursor();
    ZLTextWordCursor cursor = start;
    while (cursor < end)
    {
        if (cursor.isEndOfParagraph())
        {
            cursor.nextParagraph();
            continue;
        }
        const ZLTextElement &element = cursor.element();
        switch (element.kind())
        {
        case ZLTextElement::WORD_ELEMENT:
            {
                const ZLTextWord &word = (const ZLTextWord&)element;
                if (cursor.sameElementAs(end))
                {
                    if (start.sameElementAs(end))
                    {
                        int skip = ZLUnicodeUtil::length(word.Data, start.charIndex());
                        int length = ZLUnicodeUtil::length(word.Data, end.charIndex()) - skip;
                        text.append(word.Data + skip, length);
                    }
                    else
                    {
                        text.append(word.Data, ZLUnicodeUtil::length(word.Data, end.charIndex()));
                    }
                }
                else if (cursor.charIndex() == 0)
                {
                    text.append(word.Data, word.Size);
                }
                else /* cursor == start */
                {
                    int skip = ZLUnicodeUtil::length(word.Data, cursor.charIndex());
                    text.append(word.Data + skip, word.Size - skip);
                }
            }
            break;
        case ZLTextElement::HSPACE_ELEMENT:
        case ZLTextElement::NB_HSPACE_ELEMENT:
            {
                text += ' ';
            }
            break;
        }
        cursor.nextWord();
        if (text.size() >= max)
        {
            return;
        }
    }
}
void ZLTextAreaController::skip(ZLTextWordCursor &cursor, SizeUnit unit, int size) {
	ZLTextWordCursor paragraphStart = cursor;
	paragraphStart.moveToParagraphStart();
	ZLTextWordCursor paragraphEnd = cursor;
	paragraphEnd.moveToParagraphEnd();

	ZLTextArea::Style style(myArea, myArea.myProperties.baseStyle());
	style.applyControls(paragraphStart, cursor);

	while (!cursor.isEndOfParagraph() && (size > 0)) {
		const ZLTextLineInfoPtr info = 
			myArea.processTextLine(style, cursor, paragraphEnd);
		cursor = info->End;
		size -= infoHeight(*info, unit);
	}
}
void ZLTextView::PositionIndicator::draw() {
	ZLTextBaseStyle &baseStyle = ZLTextStyleCollection::instance().baseStyle();

	ZLPaintContext &context = this->context();

	ZLTextWordCursor endCursor = myTextView.endCursor();
	bool isEndOfText = false;
	if (endCursor.isEndOfParagraph()) {
		isEndOfText = !endCursor.nextParagraph();
	}

	myExtraWidth = 0;
	if (myInfo.isTimeShown()) {
		drawExtraText(timeString());
	}
	if (myInfo.isBatteryShown()) {
		drawExtraText(batteryString());
	}
	if (myInfo.isTextPositionShown()) {
		drawExtraText(textPositionString());
	}

	const long bottom = this->bottom();
	const long top = this->top();
	const long left = this->left();
	const long right = this->right();

	if (left >= right) {
		return;
	}

	size_t fillWidth = right - left - 1;

	if (!isEndOfText) {
		fillWidth =
			muldiv(fillWidth, sizeOfTextBeforeCursor(myTextView.endCursor()), sizeOfTextBeforeParagraph(endTextIndex()));
	}

	context.setColor(baseStyle.RegularTextColorOption.value());
	context.setFillColor(myInfo.color());
	context.fillRectangle(myTextView.visualX(left + 1), top + 1, myTextView.visualX(left + fillWidth + 1), bottom - 1);
	context.drawLine(myTextView.visualX(left), top, myTextView.visualX(right), top);
	context.drawLine(myTextView.visualX(left), bottom, myTextView.visualX(right), bottom);
	context.drawLine(myTextView.visualX(left), bottom, myTextView.visualX(left), top);
	context.drawLine(myTextView.visualX(right), bottom, myTextView.visualX(right), top);
}
std::string BookTextView::getFirstInternalHyperlinkId(int x0, int y0, int x1, int y1) {

    std::string id;
    std::string type;

    const ZLTextElementArea * area = elementByCoordinates(x0, y0);
    const ZLTextElementArea * stop_area = elementByCoordinates(x1, y1);

    if ( !area || ((area->Kind != ZLTextElement::WORD_ELEMENT) &&
                   (area->Kind != ZLTextElement::IMAGE_ELEMENT))) {
        return id;
    }
    ZLTextWordCursor cursor = startCursor();
    cursor.moveToParagraph(area->ParagraphIndex);
    int paragraphs = area->ParagraphIndex;
    int end_paragraphs = stop_area ? stop_area->ParagraphIndex : 0;

    do
    {
        cursor.moveToParagraphStart();
        ZLTextKind hyperlinkKind = REGULAR;
        for ( ; !cursor.isEndOfParagraph();) {
            const ZLTextElement &element = cursor.element();
            if (element.kind() == ZLTextElement::CONTROL_ELEMENT) {
                const ZLTextControlEntry &control = ((const ZLTextControlElement&)element).entry();
                if (control.isHyperlink()) {
                    hyperlinkKind = control.kind();
                    id = ((const ZLTextHyperlinkControlEntry&)control).label();
                    type = ((const ZLTextHyperlinkControlEntry&)control).hyperlinkType();
                    if (type == "internal")
                    {
                        return id;
                    }
                } else if (!control.isStart() && (control.kind() == hyperlinkKind)) {
                    hyperlinkKind = REGULAR;
                }
            }
            cursor.nextWord();
        }

    } while( ++paragraphs <= end_paragraphs &&  cursor.nextParagraph());

    return std::string();
}
void ZLTextView::PositionIndicator::draw() {
	ZLPaintContext &context = this->context();

	ZLTextWordCursor endCursor = myTextView.textArea().endCursor();
	bool isEndOfText = false;
	if (endCursor.isEndOfParagraph()) {
		isEndOfText = !endCursor.nextParagraph();
	}

	myExtraWidth = 0;
	if (myInfo.isTimeShown()) {
		drawExtraText(timeString());
	}
	if (myInfo.isTextPositionShown()) {
		drawExtraText(textPositionString());
	}

	const long bottom = this->bottom();
	const long top = this->top();
	const long left = this->left();
	const long right = this->right();

	if (left >= right) {
		return;
	}

	size_t fillWidth = right - left - 1;

	if (!isEndOfText) {
		fillWidth =
			muldiv(fillWidth, sizeOfTextBeforeCursor(myTextView.textArea().endCursor()), sizeOfTextBeforeParagraph(endTextIndex()));
	}

	context.setColor(myTextView.color());
	context.setFillColor(myInfo.color());
	context.fillRectangle(left + 1, top + 1, left + fillWidth + 1, bottom - 1);
	context.drawLine(left, top, right, top);
	context.drawLine(left, bottom, right, bottom);
	context.drawLine(left, bottom, left, top);
	context.drawLine(right, bottom, right, top);
}
bool ZLTextAreaController::preparePaintInfo() {
	if ((myPaintState == NOTHING_TO_PAINT) || (myPaintState == READY)) {
		return false;
	}

            myArea.myLineInfoCache.insert(myArea.myLineInfos.begin(), myArea.myLineInfos.end());



	switch (myPaintState) {
		default:
			break;
		case TO_SCROLL_FORWARD:
			if (!myArea.myEndCursor.paragraphCursor().isLast() ||
					!myArea.myEndCursor.isEndOfParagraph()) {
				ZLTextWordCursor startCursor;
				switch (myScrollingMode) {
					case NO_OVERLAPPING:
						break;
					case KEEP_LINES:
						startCursor = findLineFromEnd(myOverlappingValue);
						break;
					case SCROLL_LINES:
						startCursor = findLineFromStart(myOverlappingValue);
						if (startCursor.isEndOfParagraph()) {
							startCursor.nextParagraph();
						}
						break;
					case SCROLL_PERCENTAGE:
						startCursor = findPercentFromStart(myOverlappingValue);
						break;
				}

				if (!startCursor.isNull() && (startCursor == myArea.myStartCursor)) {

					startCursor = findLineFromStart(1);

				}

				if (!startCursor.isNull()) {

					ZLTextWordCursor endCursor = buildInfos(startCursor);


					if (!visiblePageIsEmpty() && ((myScrollingMode != KEEP_LINES) || (endCursor != myArea.myEndCursor))) {

                                                    myArea.myStartCursor = startCursor;
                                                    myArea.myEndCursor = endCursor;

						break;
					}

				}

                                    myArea.myStartCursor = myArea.myEndCursor;
                                    myArea.myEndCursor = buildInfos(myArea.myStartCursor);

			}
			break;
		case TO_SCROLL_BACKWARD:
			if (!myArea.myStartCursor.paragraphCursor().isFirst() || !myArea.myStartCursor.isStartOfParagraph()) {
				switch (myScrollingMode) {
					case NO_OVERLAPPING:
						myArea.myStartCursor = findStart(myArea.myStartCursor, PIXEL_UNIT, myArea.height());
						break;
					case KEEP_LINES:
					{
						ZLTextWordCursor endCursor = findLineFromStart(myOverlappingValue);
						if (!endCursor.isNull() && (endCursor == myArea.myEndCursor)) {
							endCursor = findLineFromEnd(1);
						}
						if (!endCursor.isNull()) {
							ZLTextWordCursor startCursor = findStart(endCursor, PIXEL_UNIT, myArea.height());
							myArea.myStartCursor =
								(startCursor != myArea.myStartCursor) ?
									startCursor : findStart(myArea.myStartCursor, PIXEL_UNIT, myArea.height());
						} else {
							myArea.myStartCursor = findStart(myArea.myStartCursor, PIXEL_UNIT, myArea.height());
						}
						break;
					}
					case SCROLL_LINES:
						myArea.myStartCursor = findStart(myArea.myStartCursor, LINE_UNIT, myOverlappingValue);
						break;
					case SCROLL_PERCENTAGE:
						myArea.myStartCursor =
							findStart(myArea.myStartCursor, PIXEL_UNIT, myArea.height() * myOverlappingValue / 100);
						break;
				}
				myArea.myEndCursor = buildInfos(myArea.myStartCursor);
				if (visiblePageIsEmpty()) {
					myArea.myStartCursor = findStart(myArea.myStartCursor, LINE_UNIT, 1);
					myArea.myEndCursor = buildInfos(myArea.myStartCursor);
				}
			}
			break;
		case START_IS_KNOWN:
			myArea.myEndCursor = buildInfos(myArea.myStartCursor);
			if (visiblePageIsEmpty()) {
				ZLTextWordCursor startCursor = findLineFromStart(1);
				if (!startCursor.isNull()) {
					myArea.myStartCursor = startCursor;
					if (myArea.myStartCursor.isEndOfParagraph()) {
						myArea.myStartCursor.nextParagraph();
					}
					myArea.myEndCursor = buildInfos(myArea.myStartCursor);
				}
			}
			break;
		case END_IS_KNOWN:
			myArea.myStartCursor = findStart(myArea.myEndCursor, PIXEL_UNIT, myArea.height());
			myArea.myEndCursor = buildInfos(myArea.myStartCursor);
			break;
	}

        myPaintState = READY;
        myArea.myLineInfoCache.clear();
	return true;
}
void ZLTextSelectionModel::createData() const {
	if (!myTextIsUpToDate && !isEmpty()) {
		Range r = internalRange();

		ZLTextWordCursor start = myArea.startCursor();
		start.moveToParagraph(r.first.ParagraphIndex);
		start.moveTo(r.first.ElementIndex, r.first.CharIndex);

		ZLTextWordCursor end = myArea.startCursor();
		end.moveToParagraph(r.second.ParagraphIndex);
		end.moveTo(r.second.ElementIndex, r.second.CharIndex);

		std::set<ZLTextParagraphCursorPtr> pcursors;
		pcursors.insert(start.paragraphCursorPtr());

		ZLTextWordCursor cursor = start;
		while (cursor < end) {
			if (cursor.isEndOfParagraph()) {
				cursor.nextParagraph();
				pcursors.insert(cursor.paragraphCursorPtr());
				myText.append(ZLibrary::EndOfLine);
				continue;
			}
			const ZLTextElement &element = cursor.element();
			switch (element.kind()) {
				case ZLTextElement::WORD_ELEMENT:
				{
					const ZLTextWord &word = (const ZLTextWord&)element;
					if (cursor.sameElementAs(end)) {
						if (start.sameElementAs(end)) {
							int skip = ZLUnicodeUtil::length(word.Data, start.charIndex());
							int length = ZLUnicodeUtil::length(word.Data, end.charIndex()) - skip;
							myText.append(word.Data + skip, length);
						} else {
							myText.append(word.Data, ZLUnicodeUtil::length(word.Data, end.charIndex()));
						}
					} else if (cursor.charIndex() == 0) {
						myText.append(word.Data, word.Size);
					} else /* cursor == start */ {
						int skip = ZLUnicodeUtil::length(word.Data, cursor.charIndex());
						myText.append(word.Data + skip, word.Size - skip);
					}
					break;
				}
				case ZLTextElement::IMAGE_ELEMENT:
					if (myImage.isNull()) {
						myImage = ((const ZLTextImageElement&)element).image();
					}
					break;
				case ZLTextElement::HSPACE_ELEMENT:
				case ZLTextElement::NB_HSPACE_ELEMENT:
					myText += ' ';
					break;
				default:
					break;
			}
			cursor.nextWord();
		}
		if ((cursor == end) && !cursor.isEndOfParagraph() && myImage.isNull()) {
			const ZLTextElement &element = cursor.element();
			if (element.kind() == ZLTextElement::IMAGE_ELEMENT) {
				myImage = ((const ZLTextImageElement&)element).image();
			}
		}

		myCursors.swap(pcursors);
		myTextIsUpToDate = true;
	}
}
ZLTextLineInfoPtr ZLTextView::processTextLine(const ZLTextWordCursor &start, const ZLTextWordCursor &end) {
	const bool useHyphenator =
		ZLTextStyleCollection::instance().baseStyle().AutoHyphenationOption.value();

	ZLTextLineInfoPtr infoPtr = new ZLTextLineInfo(start, myStyle.textStyle());

	std::set<ZLTextLineInfoPtr>::const_iterator it = myLineInfoCache.find(infoPtr);
	if (it != myLineInfoCache.end()) {
		const ZLTextLineInfoPtr &storedInfo = *it;
		myStyle.applyControls(storedInfo->Start, storedInfo->End);
		return storedInfo;
	}

	ZLTextLineInfo &info = *infoPtr;
	ZLTextWordCursor current = start;
	const ZLTextParagraphCursor &paragraphCursor = current.paragraphCursor();
	const bool isFirstLine = current.isStartOfParagraph();

	if (paragraphCursor.paragraph().kind() == ZLTextParagraph::TREE_PARAGRAPH) {
		info.NodeInfo = new ZLTextTreeNodeInfo();
		ZLTextTreeNodeInfo &nodeInfo = *info.NodeInfo;
		const ZLTextTreeParagraph &treeParagraph = (const ZLTextTreeParagraph&)paragraphCursor.paragraph();
		nodeInfo.IsLeaf = treeParagraph.children().empty();
		nodeInfo.IsOpen = treeParagraph.isOpen();
		nodeInfo.IsFirstLine = isFirstLine;
		nodeInfo.ParagraphNumber = paragraphCursor.index();

		nodeInfo.VerticalLinesStack.reserve(treeParagraph.depth() - 1);
		if (treeParagraph.depth() > 1) {
			const ZLTextTreeParagraph *ctp = treeParagraph.parent();
			nodeInfo.VerticalLinesStack.push_back(ctp->children().back() != &treeParagraph);
			for (int i = 1; i < treeParagraph.depth() - 1; ++i) {
				const ZLTextTreeParagraph *parent = ctp->parent();
				nodeInfo.VerticalLinesStack.push_back(ctp != parent->children().back());
				ctp = parent;
			}
		}
	}

	if (isFirstLine) {
		ZLTextElement::Kind elementKind = paragraphCursor[current.wordNumber()].kind();
		while ((elementKind == ZLTextElement::CONTROL_ELEMENT) ||
					 (elementKind == ZLTextElement::FORCED_CONTROL_ELEMENT)) {
			const ZLTextElement &element = paragraphCursor[current.wordNumber()];
			switch (elementKind) {
				case ZLTextElement::CONTROL_ELEMENT:
					myStyle.applyControl((const ZLTextControlElement&)element);
					break;
				case ZLTextElement::FORCED_CONTROL_ELEMENT:
					myStyle.applyControl((const ZLTextForcedControlElement&)element);
					break;
				default:
					break;
			}
			current.nextWord();
			if (current.equalWordNumber(end)) {
				break;
			}
			elementKind = paragraphCursor[current.wordNumber()].kind();
		}
		info.StartStyle = myStyle.textStyle();
		info.RealStart = current;
	}

	ZLTextStylePtr storedStyle = myStyle.textStyle();

	info.LeftIndent = myStyle.textStyle()->leftIndent();
	if (isFirstLine) {
		info.LeftIndent += myStyle.textStyle()->firstLineIndentDelta();
	}
	if (!info.NodeInfo.isNull()) {
		info.LeftIndent += (myStyle.context().stringHeight() + 2) / 3 * 4 * (info.NodeInfo->VerticalLinesStack.size() + 1);
	}
	info.Width = info.LeftIndent;

	if (info.RealStart.equalWordNumber(end)) {
	  info.End = info.RealStart;
		return infoPtr;
	}

	ZLTextPartialInfo newInfo(info, current);
	bool allowBreakAtNBSpace = true;
	const int maxWidth = viewWidth() - myStyle.textStyle()->rightIndent();
	bool wordOccured = false;
	int lastSpaceWidth = 0;
	int removeLastSpace = false;

	ZLTextElement::Kind elementKind = paragraphCursor[newInfo.End.wordNumber()].kind();

	bool breakedAtFirstWord = false;
	do {
		const ZLTextElement &element = paragraphCursor[newInfo.End.wordNumber()];
		newInfo.Width += myStyle.elementWidth(element, newInfo.End.charNumber());
		newInfo.Height = std::max(newInfo.Height, myStyle.elementHeight(element));
		newInfo.Descent = std::max(newInfo.Descent, myStyle.elementDescent(element));
		switch (elementKind) {
			case ZLTextElement::CONTROL_ELEMENT:
				myStyle.applyControl((const ZLTextControlElement&)element);
				break;
			case ZLTextElement::FORCED_CONTROL_ELEMENT:
				myStyle.applyControl((const ZLTextForcedControlElement&)element);
				break;
			case ZLTextElement::WORD_ELEMENT:
			case ZLTextElement::IMAGE_ELEMENT:
				wordOccured = true;
				newInfo.IsVisible = true;
				break;
			case ZLTextElement::HSPACE_ELEMENT:
			case ZLTextElement::NB_HSPACE_ELEMENT:
				if (wordOccured) {
					wordOccured = false;
					++newInfo.SpaceCounter;
					lastSpaceWidth = myStyle.context().spaceWidth();
					newInfo.Width += lastSpaceWidth;
				}
				break;
			case ZLTextElement::EMPTY_LINE_ELEMENT:
				newInfo.IsVisible = true;
			default:
				break;
		}

		if (newInfo.Width > maxWidth) {
			if (!info.End.equalWordNumber(start)) {
				break;
			}
			if (useHyphenator && myStyle.textStyle()->allowHyphenations() &&
					(elementKind == ZLTextElement::WORD_ELEMENT)) {
				breakedAtFirstWord = true;
				break;
			}
		}

		ZLTextElement::Kind previousKind = elementKind;
		newInfo.End.nextWord();
		bool allowBreak = newInfo.End.equalWordNumber(end);
		bool nbspaceBreak = false;
		if (!allowBreak) {
			elementKind = paragraphCursor[newInfo.End.wordNumber()].kind();
			if (elementKind == ZLTextElement::NB_HSPACE_ELEMENT) {
				if (allowBreakAtNBSpace) {
					allowBreak = true;
					nbspaceBreak = true;
				}
			} else {
				allowBreak =
					((elementKind != ZLTextElement::WORD_ELEMENT) || (previousKind == ZLTextElement::WORD_ELEMENT)) &&
					(elementKind != ZLTextElement::IMAGE_ELEMENT) &&
					(elementKind != ZLTextElement::CONTROL_ELEMENT);
			}
		}
		if (allowBreak) {
			newInfo.setTo(info);
			allowBreakAtNBSpace = nbspaceBreak;
			storedStyle = myStyle.textStyle();
			removeLastSpace = !wordOccured && (info.SpaceCounter > 0);
		}
	} while (!newInfo.End.equalWordNumber(end));

	if (!newInfo.End.equalWordNumber(end) && useHyphenator &&
		 myStyle.textStyle()->allowHyphenations()) {
		const ZLTextElement &element = paragraphCursor[newInfo.End.wordNumber()];
		if (element.kind() == ZLTextElement::WORD_ELEMENT) {
			const int startCharNumber = newInfo.End.charNumber();
			newInfo.Width -= myStyle.elementWidth(element, startCharNumber);
			const ZLTextWord &word = (ZLTextWord&)element;
			int spaceLeft = maxWidth - newInfo.Width;
			if (breakedAtFirstWord ||
					((word.Length > 3) && (spaceLeft > 2 * myStyle.context().spaceWidth()))) {
				ZLUnicodeUtil::Ucs2String ucs2string;
				ZLUnicodeUtil::utf8ToUcs2(ucs2string, word.Data, word.Size);
				ZLTextHyphenationInfo hyphenationInfo = ZLTextHyphenator::instance().info(word);
				int hyphenationPosition = word.Length - 1;
				int subwordWidth = 0;
				for (; hyphenationPosition > startCharNumber; --hyphenationPosition) {
					if (hyphenationInfo.isHyphenationPossible(hyphenationPosition)) {
						subwordWidth = myStyle.wordWidth(word, startCharNumber, hyphenationPosition - startCharNumber, ucs2string[hyphenationPosition - 1] != '-');
						if (subwordWidth <= spaceLeft) {
							break;
						}
					}
				}
				if ((hyphenationPosition == startCharNumber) &&
						(info.End.wordNumber() <= info.RealStart.wordNumber())) {
					hyphenationPosition = word.Length;
					subwordWidth = myStyle.elementWidth(element, startCharNumber);
				}
				if (hyphenationPosition > startCharNumber) {
					newInfo.Width += subwordWidth;
					newInfo.setTo(info);
					storedStyle = myStyle.textStyle();
					removeLastSpace = false;
					info.End.setCharNumber(hyphenationPosition);
				}
			}
		}
	}

	if (removeLastSpace) {
		info.Width -= lastSpaceWidth;
		--info.SpaceCounter;
	}

	myStyle.setTextStyle(storedStyle);

	if (isFirstLine) {
		info.Height += info.StartStyle->spaceBefore();
	}
	if (info.End.isEndOfParagraph()) {
		info.VSpaceAfter = myStyle.textStyle()->spaceAfter();
	}

	if (!info.End.equalWordNumber(end) || end.isEndOfParagraph()) {
		myLineInfoCache.insert(infoPtr);
	}

	return infoPtr;
}