Esempio n. 1
0
bool
ParagraphLayout::_AppendGlyphInfos(const TextSpan& span)
{
	int charCount = span.CountChars();
	if (charCount == 0)
		return true;

	const BString& text = span.Text();
	const BFont& font = span.Style().Font();

	// Allocate arrays
	float* escapementArray = new (std::nothrow) float[charCount];
	if (escapementArray == NULL)
		return false;
	ArrayDeleter<float> escapementDeleter(escapementArray);

	// Fetch glyph spacing information
	font.GetEscapements(text, charCount, escapementArray);

	// Append to glyph buffer and convert escapement scale
	float size = font.Size();
	const char* c = text.String();
	for (int i = 0; i < charCount; i++) {
		if (!_AppendGlyphInfo(UTF8ToCharCode(&c), escapementArray[i] * size,
				span.Style())) {
			return false;
		}
	}

	return true;
}
Esempio n. 2
0
bool
Paragraph::Append(const TextSpan& span)
{
	// Try to merge with last span if the TextStyles are equal
	if (fTextSpans.CountItems() > 0) {
		const TextSpan& lastSpan = fTextSpans.LastItem();
		if (lastSpan.Style() == span.Style()) {
			BString text(lastSpan.Text());
			text.Append(span.Text());
			fTextSpans.Remove();
			return fTextSpans.Add(TextSpan(text, span.Style()));
		}
	}
	return fTextSpans.Add(span);
}
Esempio n. 3
0
void
ParagraphLayout::_DrawSpan(BView* view, BPoint offset,
	const TextSpan& span, int32 textOffset) const
{
	const BString& text = span.Text();
	if (text.Length() == 0)
		return;

	const GlyphInfo& glyph = fGlyphInfos.ItemAtFast(textOffset);
	const LineInfo& line = fLineInfos.ItemAtFast(glyph.lineIndex);

	offset.x += glyph.x;
	offset.y += line.y + line.maxAscent;

	const CharacterStyle& style = span.Style();

	view->SetFont(&style.Font());
	view->SetHighColor(style.ForegroundColor());

	// TODO: Implement other style properties

	escapement_delta delta;
	delta.nonspace = line.extraGlyphSpacing;
	delta.space = line.extraWhiteSpacing;

	// TODO: Fix in app_server: First glyph should not be shifted by delta.
	if (text[0] == ' ')
		offset.x -= delta.space;
	else
		offset.x -= delta.nonspace;

	view->DrawString(span.Text(), offset, &delta);
}
Esempio n. 4
0
bool
Paragraph::Prepend(const TextSpan& span)
{
	_InvalidateCachedLength();

	// Try to merge with first span if the TextStyles are equal
	if (fTextSpans.CountItems() > 0) {
		const TextSpan& firstSpan = fTextSpans.ItemAtFast(0);
		if (firstSpan.Style() == span.Style()) {
			BString text(span.Text());
			text.Append(firstSpan.Text());
			return fTextSpans.Replace(0, TextSpan(text, span.Style()));
		}
	}
	return fTextSpans.Add(span, 0);
}
Esempio n. 5
0
bool
Paragraph::Insert(int32 offset, const TextSpan& newSpan)
{
	_InvalidateCachedLength();

	int32 index = 0;
	while (index < fTextSpans.CountItems()) {
		const TextSpan& span = fTextSpans.ItemAtFast(index);
		if (offset - span.CountChars() < 0)
			break;
		offset -= span.CountChars();
		index++;
	}

	if (fTextSpans.CountItems() == index)
		return Append(newSpan);

	// Try to merge with span at index if the TextStyles are equal
	TextSpan span = fTextSpans.ItemAtFast(index);
	if (span.Style() == newSpan.Style()) {
		span.Insert(offset, newSpan.Text());
		return fTextSpans.Replace(index, span);
	}

	if (offset == 0) {
		if (index > 0) {
			// Try to merge with TextSpan before if offset == 0 && index > 0
			TextSpan span = fTextSpans.ItemAtFast(index - 1);
			if (span.Style() == newSpan.Style()) {
				span.Insert(span.CountChars(), newSpan.Text());
				return fTextSpans.Replace(index - 1, span);
			}
		}
		// Just insert the new span before the one at index
		return fTextSpans.Add(newSpan, index);
	}

	// Split the span,
	TextSpan spanBefore = span.SubSpan(0, offset);
	TextSpan spanAfter = span.SubSpan(offset, span.CountChars() - offset);

	return fTextSpans.Replace(index, spanBefore)
		&& fTextSpans.Add(newSpan, index + 1)
		&& fTextSpans.Add(spanAfter, index + 2);
}
Esempio n. 6
0
void
ParagraphLayout::_DrawSpan(BView* view, const TextSpan& span,
	int32 textOffset) const
{
	const GlyphInfo& glyph = fGlyphInfos.ItemAtFast(textOffset);
	const LineInfo& line = fLineInfos.ItemAtFast(glyph.lineIndex);
	
	float x = glyph.x;
	float y = line.y + line.maxAscent;

	const CharacterStyle& style = span.Style();

	view->SetFont(&style.Font());
	view->SetHighColor(style.ForegroundColor());

	// TODO: Implement other style properties
	// TODO: Implement correct glyph spacing

	view->DrawString(span.Text(), BPoint(x, y));
}
Esempio n. 7
0
bool
Paragraph::Remove(int32 offset, int32 length)
{
	if (length == 0)
		return true;

	_InvalidateCachedLength();

	int32 index = 0;
	while (index < fTextSpans.CountItems()) {
		const TextSpan& span = fTextSpans.ItemAtFast(index);
		if (offset - span.CountChars() < 0)
			break;
		offset -= span.CountChars();
		index++;
	}

	if (index >= fTextSpans.CountItems())
		return false;

	TextSpan span(fTextSpans.ItemAtFast(index));
	int32 removeLength = std::min(span.CountChars() - offset, length);
	span.Remove(offset, removeLength);
	length -= removeLength;
	index += 1;

	// Remove more spans if necessary
	while (length > 0 && index < fTextSpans.CountItems()) {
		int32 spanLength = fTextSpans.ItemAtFast(index).CountChars();
		if (spanLength <= length) {
			fTextSpans.Remove(index);
			length -= spanLength;
		} else {
			// Reached last span
			removeLength = std::min(length, spanLength);
			TextSpan lastSpan = fTextSpans.ItemAtFast(index).SubSpan(
				removeLength, spanLength - removeLength);
			// Try to merge with first span, otherwise replace span at index
			if (lastSpan.Style() == span.Style()) {
				span.Insert(span.CountChars(), lastSpan.Text());
				fTextSpans.Remove(index);
			} else {
				fTextSpans.Replace(index, lastSpan);
			}

			break;
		}
	}

	// See if anything from the TextSpan at offset remained, keep it as empty
	// span if it is the last remaining span.
	index--;
	if (span.CountChars() > 0 || fTextSpans.CountItems() == 1) {
		fTextSpans.Replace(index, span);
	} else {
		fTextSpans.Remove(index);
		index--;
	}

	// See if spans can be merged after one has been removed.
	if (index >= 0 && index + 1 < fTextSpans.CountItems()) {
		const TextSpan& span1 = fTextSpans.ItemAtFast(index);
		const TextSpan& span2 = fTextSpans.ItemAtFast(index + 1);
		if (span1.Style() == span2.Style()) {
			span = span1;
			span.Append(span2.Text());
			fTextSpans.Replace(index, span);
			fTextSpans.Remove(index + 1);
		}
	}

	return true;
}