HaikuDepot: Text stuff: ParagraphLayout compiles and maybe works
This commit is contained in:
@@ -30,6 +30,7 @@ Application HaikuDepot :
|
|||||||
CharacterStyle.cpp
|
CharacterStyle.cpp
|
||||||
CharacterStyleData.cpp
|
CharacterStyleData.cpp
|
||||||
Paragraph.cpp
|
Paragraph.cpp
|
||||||
|
ParagraphLayout.cpp
|
||||||
ParagraphStyle.cpp
|
ParagraphStyle.cpp
|
||||||
ParagraphStyleData.cpp
|
ParagraphStyleData.cpp
|
||||||
TextDocument.cpp
|
TextDocument.cpp
|
||||||
|
|||||||
@@ -19,10 +19,6 @@
|
|||||||
#include <utf8_functions.h>
|
#include <utf8_functions.h>
|
||||||
#include <View.h>
|
#include <View.h>
|
||||||
|
|
||||||
#include "GlyphInfo.h"
|
|
||||||
#include "List.h"
|
|
||||||
#include "TextStyle.h"
|
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CHAR_CLASS_DEFAULT,
|
CHAR_CLASS_DEFAULT,
|
||||||
@@ -98,22 +94,24 @@ get_char_classification(uint32 charCode)
|
|||||||
|
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
can_end_line(const GlyphInfo* buffer, int offset, int count)
|
can_end_line(const GlyphInfoList& glyphInfos, int offset)
|
||||||
{
|
{
|
||||||
|
int count = glyphInfos.CountItems();
|
||||||
|
|
||||||
if (offset == count - 1)
|
if (offset == count - 1)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (offset < 0 || offset > count)
|
if (offset < 0 || offset > count)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint32 charCode = buffer[offset].charCode;
|
uint32 charCode = glyphInfos.ItemAtFast(offset).charCode;
|
||||||
uint32 classification = get_char_classification(charCode);
|
uint32 classification = get_char_classification(charCode);
|
||||||
|
|
||||||
// wrapping is always allowed at end of text and at newlines
|
// wrapping is always allowed at end of text and at newlines
|
||||||
if (classification == CHAR_CLASS_END_OF_TEXT || charCode == '\n')
|
if (classification == CHAR_CLASS_END_OF_TEXT || charCode == '\n')
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
uint32 nextCharCode = buffer[offset + 1].charCode;
|
uint32 nextCharCode = glyphInfos.ItemAtFast(offset + 1).charCode;
|
||||||
uint32 nextClassification = get_char_classification(nextCharCode);
|
uint32 nextClassification = get_char_classification(nextCharCode);
|
||||||
|
|
||||||
// never separate a punctuation char from its preceding word
|
// never separate a punctuation char from its preceding word
|
||||||
@@ -166,15 +164,13 @@ can_end_line(const GlyphInfo* buffer, int offset, int count)
|
|||||||
ParagraphLayout::ParagraphLayout()
|
ParagraphLayout::ParagraphLayout()
|
||||||
:
|
:
|
||||||
fTextSpans(),
|
fTextSpans(),
|
||||||
fWidth(0.0f),
|
fParagraphStyle(),
|
||||||
|
|
||||||
|
fWidth(0.0f),
|
||||||
fLayoutValid(false),
|
fLayoutValid(false),
|
||||||
|
|
||||||
fGlyphInfoBuffer(NULL),
|
fGlyphInfos(),
|
||||||
fGlpyhInfoBufferSize(0),
|
fLineInfos()
|
||||||
fGlyphInfoCount(0),
|
|
||||||
|
|
||||||
fLayoutLines()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,15 +178,13 @@ ParagraphLayout::ParagraphLayout()
|
|||||||
ParagraphLayout::ParagraphLayout(const Paragraph& paragraph)
|
ParagraphLayout::ParagraphLayout(const Paragraph& paragraph)
|
||||||
:
|
:
|
||||||
fTextSpans(paragraph.TextSpans()),
|
fTextSpans(paragraph.TextSpans()),
|
||||||
fWidth(other.fWidth),
|
fParagraphStyle(paragraph.Style()),
|
||||||
|
|
||||||
|
fWidth(0.0f),
|
||||||
fLayoutValid(false),
|
fLayoutValid(false),
|
||||||
|
|
||||||
fGlyphInfoBuffer(NULL),
|
fGlyphInfos(),
|
||||||
fGlpyhInfoBufferSize(0),
|
fLineInfos()
|
||||||
fGlyphInfoCount(0),
|
|
||||||
|
|
||||||
fLayoutLines()
|
|
||||||
{
|
{
|
||||||
_Init();
|
_Init();
|
||||||
}
|
}
|
||||||
@@ -199,15 +193,13 @@ ParagraphLayout::ParagraphLayout(const Paragraph& paragraph)
|
|||||||
ParagraphLayout::ParagraphLayout(const ParagraphLayout& other)
|
ParagraphLayout::ParagraphLayout(const ParagraphLayout& other)
|
||||||
:
|
:
|
||||||
fTextSpans(other.fTextSpans),
|
fTextSpans(other.fTextSpans),
|
||||||
|
fParagraphStyle(other.fParagraphStyle),
|
||||||
|
|
||||||
fWidth(other.fWidth),
|
fWidth(other.fWidth),
|
||||||
|
|
||||||
fLayoutValid(false),
|
fLayoutValid(false),
|
||||||
|
|
||||||
fGlyphInfoBuffer(NULL),
|
fGlyphInfos(),
|
||||||
fGlpyhInfoBufferSize(0),
|
fLineInfos()
|
||||||
fGlyphInfoCount(0),
|
|
||||||
|
|
||||||
fLayoutLines()
|
|
||||||
{
|
{
|
||||||
_Init();
|
_Init();
|
||||||
}
|
}
|
||||||
@@ -215,7 +207,18 @@ ParagraphLayout::ParagraphLayout(const ParagraphLayout& other)
|
|||||||
|
|
||||||
ParagraphLayout::~ParagraphLayout()
|
ParagraphLayout::~ParagraphLayout()
|
||||||
{
|
{
|
||||||
delete[] fGlyphInfoBuffer;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ParagraphLayout::SetParagraph(const Paragraph& paragraph)
|
||||||
|
{
|
||||||
|
fTextSpans = paragraph.TextSpans();
|
||||||
|
fParagraphStyle = paragraph.Style();
|
||||||
|
|
||||||
|
_Init();
|
||||||
|
|
||||||
|
fLayoutValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -236,8 +239,8 @@ ParagraphLayout::Height()
|
|||||||
|
|
||||||
float height = 0.0f;
|
float height = 0.0f;
|
||||||
|
|
||||||
if (fLayoutLines.CountItems() > 0) {
|
if (fLineInfos.CountItems() > 0) {
|
||||||
const LayoutLine& lastLine = fLayoutLines.LastItem();
|
const LineInfo& lastLine = fLineInfos.LastItem();
|
||||||
height = lastLine.y + lastLine.height;
|
height = lastLine.y + lastLine.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,9 +253,9 @@ ParagraphLayout::Draw(BView* view, const BPoint& offset)
|
|||||||
{
|
{
|
||||||
_ValidateLayout();
|
_ValidateLayout();
|
||||||
|
|
||||||
int lineCount = fLayoutLines.CountItems();
|
int lineCount = fLineInfos.CountItems();
|
||||||
for (int i = 0; i < lineCount; i++) {
|
for (int i = 0; i < lineCount; i++) {
|
||||||
const LayoutLine& line = fLayoutLines.ItemAtFast(i);
|
const LineInfo& line = fLineInfos.ItemAtFast(i);
|
||||||
_DrawLine(view, line);
|
_DrawLine(view, line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -272,51 +275,26 @@ ParagraphLayout::_ValidateLayout()
|
|||||||
void
|
void
|
||||||
ParagraphLayout::_Layout()
|
ParagraphLayout::_Layout()
|
||||||
{
|
{
|
||||||
fLayoutLines.Clear();
|
fLineInfos.Clear();
|
||||||
|
|
||||||
// int charCount = fText.CountChars();
|
float x = fParagraphStyle.FirstLineInset();
|
||||||
// if (charCount == 0)
|
float y = 0.0f;
|
||||||
// return;
|
int lineIndex = 0;
|
||||||
//
|
int lineStart = 0;
|
||||||
// // Allocate arrays
|
|
||||||
// float* escapementArray = new (std::nothrow) float[charCount];
|
int glyphCount = fGlyphInfos.CountItems();
|
||||||
// if (escapementArray == NULL)
|
for (int i = 0; i < glyphCount; i++) {
|
||||||
// return;
|
GlyphInfo glyph = fGlyphInfos.ItemAtFast(i);
|
||||||
// ArrayDeleter<float> escapementDeleter(escapementArray);
|
|
||||||
//
|
uint32 charClassification = get_char_classification(glyph.charCode);
|
||||||
// // Fetch glyph spacing information
|
|
||||||
// fDefaultFont.GetEscapements(fText.String(), charCount, escapementArray);
|
float advanceX = glyph.width;
|
||||||
//
|
float advanceY = 0.0f;
|
||||||
// // Convert to glyph buffer
|
|
||||||
// fGlyphInfoCount = charCount;
|
bool nextLine = false;
|
||||||
// fGlyphInfoBuffer = new (std::nothrow) GlyphInfo[fGlyphInfoCount];
|
bool lineBreak = false;
|
||||||
//
|
|
||||||
// // Init glyph buffer and convert escapement scale
|
// if (glyph.charCode == '\t') {
|
||||||
// float size = fDefaultFont.Size();
|
|
||||||
// const char* c = fText.String();
|
|
||||||
// for (int i = 0; i < fGlyphInfoCount; i++) {
|
|
||||||
// fGlyphInfoBuffer[i].charCode = UTF8ToCharCode(&c);
|
|
||||||
// escapementArray[i] *= size;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// float x = fFirstLineInset;
|
|
||||||
// float y = 0.0f;
|
|
||||||
// int lineIndex = 0;
|
|
||||||
// int lineStart = 0;
|
|
||||||
//
|
|
||||||
// for (int i = 0; i < fGlyphInfoCount; i++) {
|
|
||||||
// uint32 charClassification = get_char_classification(
|
|
||||||
// fGlyphInfoBuffer[i].charCode);
|
|
||||||
//
|
|
||||||
// float advanceX = 0.0f;
|
|
||||||
// float advanceY = 0.0f;
|
|
||||||
// _GetGlyphAdvance(i, advanceX, advanceY, escapementArray);
|
|
||||||
//
|
|
||||||
// bool nextLine = false;
|
|
||||||
// bool lineBreak = false;
|
|
||||||
//
|
|
||||||
// if (fGlyphInfoBuffer[i].charCode == '\t') {
|
|
||||||
// // Figure out tab width, it's the width between the last two tab
|
// // Figure out tab width, it's the width between the last two tab
|
||||||
// // stops.
|
// // stops.
|
||||||
// float tabWidth = 0.0f;
|
// float tabWidth = 0.0f;
|
||||||
@@ -342,92 +320,90 @@ ParagraphLayout::_Layout()
|
|||||||
// if (tabOffset - x > 0.0)
|
// if (tabOffset - x > 0.0)
|
||||||
// advanceX = tabOffset - x;
|
// advanceX = tabOffset - x;
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
// fGlyphInfoBuffer[i].advanceX = advanceX;
|
glyph.advanceX = advanceX;
|
||||||
//
|
|
||||||
// if (fGlyphInfoBuffer[i].charCode == '\n') {
|
if (glyph.charCode == '\n') {
|
||||||
// nextLine = true;
|
nextLine = true;
|
||||||
// lineBreak = true;
|
lineBreak = true;
|
||||||
// fGlyphInfoBuffer[i].x = x;
|
glyph.x = x;
|
||||||
// fGlyphInfoBuffer[i].y = y;
|
fGlyphInfos.Replace(i, glyph);
|
||||||
// } else if (fWidth > 0.0f && x + advanceX > fWidth) {
|
} else if (fWidth > 0.0f && x + advanceX > fWidth) {
|
||||||
// if (charClassification == CHAR_CLASS_WHITESPACE) {
|
fGlyphInfos.Replace(i, glyph);
|
||||||
// advanceX = 0.0f;
|
if (charClassification == CHAR_CLASS_WHITESPACE) {
|
||||||
// } else if (i > lineStart) {
|
advanceX = 0.0f;
|
||||||
// nextLine = true;
|
} else if (i > lineStart) {
|
||||||
// // The current glyph extends outside the width, we need to wrap
|
nextLine = true;
|
||||||
// // to the next line. See what previous offset can be the end
|
// The current glyph extends outside the width, we need to wrap
|
||||||
// // of the line.
|
// to the next line. See what previous offset can be the end
|
||||||
// int lineEnd = i - 1;
|
// of the line.
|
||||||
// while (lineEnd > lineStart
|
int lineEnd = i - 1;
|
||||||
// && !can_end_line(fGlyphInfoBuffer, lineEnd,
|
while (lineEnd > lineStart
|
||||||
// fGlyphInfoCount)) {
|
&& !can_end_line(fGlyphInfos, lineEnd)) {
|
||||||
// lineEnd--;
|
lineEnd--;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// if (lineEnd > lineStart) {
|
if (lineEnd > lineStart) {
|
||||||
// // Found a place to perform a line break.
|
// Found a place to perform a line break.
|
||||||
// i = lineEnd + 1;
|
i = lineEnd + 1;
|
||||||
// // Adjust the glyph info to point at the changed buffer
|
|
||||||
// // position
|
// Adjust the glyph info to point at the changed buffer
|
||||||
// _GetGlyphAdvance(i, advanceX, advanceY, escapementArray);
|
// position
|
||||||
// } else {
|
glyph = fGlyphInfos.ItemAtFast(i);
|
||||||
// // Just break where we are.
|
advanceX = glyph.width;
|
||||||
// }
|
} else {
|
||||||
// }
|
// Just break where we are.
|
||||||
// }
|
}
|
||||||
//
|
}
|
||||||
// if (nextLine) {
|
}
|
||||||
// // * Initialize the max ascent/descent of all preceding glyph infos
|
|
||||||
// // on the current/last line
|
if (nextLine) {
|
||||||
// // * Adjust the baseline offset according to the max ascent
|
// * Initialize the max ascent/descent of all preceding glyph infos
|
||||||
// // * Fill in the line index.
|
// on the current/last line
|
||||||
// unsigned lineEnd;
|
// * Adjust the baseline offset according to the max ascent
|
||||||
// if (lineBreak)
|
// * Fill in the line index.
|
||||||
// lineEnd = i;
|
unsigned lineEnd;
|
||||||
// else
|
if (lineBreak)
|
||||||
// lineEnd = i - 1;
|
lineEnd = i;
|
||||||
//
|
else
|
||||||
// float lineHeight = 0.0;
|
lineEnd = i - 1;
|
||||||
// _FinalizeLine(lineStart, lineEnd, lineIndex, y,
|
|
||||||
// lineHeight);
|
float lineHeight = 0.0;
|
||||||
//
|
_FinalizeLine(lineStart, lineEnd, lineIndex, y, lineHeight);
|
||||||
// // Start position of the next line
|
|
||||||
// x = fLineInset;
|
// Start position of the next line
|
||||||
// y += lineHeight + fLineSpacing;
|
x = fParagraphStyle.LineInset();
|
||||||
//
|
y += lineHeight + fParagraphStyle.LineSpacing();
|
||||||
// if (lineBreak)
|
|
||||||
// lineStart = i + 1;
|
if (lineBreak)
|
||||||
// else
|
lineStart = i + 1;
|
||||||
// lineStart = i;
|
else
|
||||||
//
|
lineStart = i;
|
||||||
// lineIndex++;
|
|
||||||
// }
|
lineIndex++;
|
||||||
//
|
}
|
||||||
// if (!lineBreak && i < fGlyphInfoCount) {
|
|
||||||
// fGlyphInfoBuffer[i].x = x;
|
if (!lineBreak && i < glyphCount) {
|
||||||
// fGlyphInfoBuffer[i].y = y;
|
glyph.x = x;
|
||||||
// }
|
fGlyphInfos.Replace(i, glyph);
|
||||||
//
|
}
|
||||||
// x += advanceX;
|
|
||||||
// y += advanceY;
|
x += advanceX;
|
||||||
// }
|
y += advanceY;
|
||||||
//
|
}
|
||||||
// // The last line may not have been appended and initialized yet.
|
|
||||||
// if (lineStart <= fGlyphInfoCount - 1) {
|
// The last line may not have been appended and initialized yet.
|
||||||
// float lineHeight;
|
if (lineStart <= glyphCount - 1) {
|
||||||
// _FinalizeLine(lineStart, fGlyphInfoCount - 1, lineIndex, y, lineHeight);
|
float lineHeight;
|
||||||
// }
|
_FinalizeLine(lineStart, glyphCount - 1, lineIndex, y, lineHeight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ParagraphLayout::_Init()
|
ParagraphLayout::_Init()
|
||||||
{
|
{
|
||||||
delete[] fGlyphInfoBuffer;
|
fGlyphInfos.Clear();
|
||||||
fGlyphInfoBuffer = NULL;
|
|
||||||
fGlpyhInfoBufferSize = 0;
|
|
||||||
fGlyphInfoCount = 0;
|
|
||||||
|
|
||||||
int spanCount = fTextSpans.CountItems();
|
int spanCount = fTextSpans.CountItems();
|
||||||
for (int i = 0; i < spanCount; i++) {
|
for (int i = 0; i < spanCount; i++) {
|
||||||
@@ -449,7 +425,7 @@ ParagraphLayout::_AppendGlyphInfos(const TextSpan& span)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
const BString& text = span.Text();
|
const BString& text = span.Text();
|
||||||
const BFont& font = span.Style().font;
|
const BFont& font = span.Style().Font();
|
||||||
|
|
||||||
// Allocate arrays
|
// Allocate arrays
|
||||||
float* escapementArray = new (std::nothrow) float[charCount];
|
float* escapementArray = new (std::nothrow) float[charCount];
|
||||||
@@ -464,112 +440,68 @@ ParagraphLayout::_AppendGlyphInfos(const TextSpan& span)
|
|||||||
float size = font.Size();
|
float size = font.Size();
|
||||||
const char* c = text.String();
|
const char* c = text.String();
|
||||||
for (int i = 0; i < charCount; i++) {
|
for (int i = 0; i < charCount; i++) {
|
||||||
_AppendGlyphInfo(UTF8ToCharCode(&c), );
|
if (!_AppendGlyphInfo(UTF8ToCharCode(&c), escapementArray[i] * size,
|
||||||
fGlyphInfoBuffer[i].charCode = ;
|
span.Style())) {
|
||||||
escapementArray[i] *= size;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
ParagraphLayout::_AppendGlyphInfo(uint32 charCode, const TextStyleRef& style)
|
|
||||||
{
|
|
||||||
// Enlarge buffer if necessary
|
|
||||||
if (fGlyphInfoCount == fGlyphInfoBufferSize) {
|
|
||||||
int size = fGlyphInfoBufferSize + 64;
|
|
||||||
|
|
||||||
GlyphInfo* buffer = (GlyphInfo*) realloc(fGlyphInfoBuffer,
|
|
||||||
size * sizeof(GlyphInfo));
|
|
||||||
if (buffer == NULL)
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
fGlyphInfoBufferSize = size;
|
|
||||||
fGlyphInfoBuffer = buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store given information
|
|
||||||
fGlyphInfoBuffer[fGlyphInfoCount].charCode = charCode;
|
|
||||||
fGlyphInfoBuffer[fGlyphInfoCount].glyph = glyph;
|
|
||||||
fGlyphInfoBuffer[fGlyphInfoCount].x = 0;
|
|
||||||
fGlyphInfoBuffer[fGlyphInfoCount].y = 0;
|
|
||||||
fGlyphInfoBuffer[fGlyphInfoCount].advanceX = 0;
|
|
||||||
fGlyphInfoBuffer[fGlyphInfoCount].maxAscend = 0;
|
|
||||||
fGlyphInfoBuffer[fGlyphInfoCount].maxDescend = 0;
|
|
||||||
fGlyphInfoBuffer[fGlyphInfoCount].lineIndex = 0;
|
|
||||||
fGlyphInfoBuffer[fGlyphInfoCount].styleRun = styleRun;
|
|
||||||
|
|
||||||
fGlyphInfoCount++;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
bool
|
||||||
ParagraphLayout::_GetGlyphAdvance(int offset, float& advanceX, float& advanceY,
|
ParagraphLayout::_AppendGlyphInfo(uint32 charCode, float width,
|
||||||
float escapementArray[]) const
|
const CharacterStyle& style)
|
||||||
{
|
{
|
||||||
float additionalGlyphSpacing = 0.0f;
|
if (style.Width() >= 0.0f) {
|
||||||
if (fGlyphInfoBuffer[offset].style.Get() != NULL)
|
// Use the metrics provided by the CharacterStyle and override
|
||||||
additionalGlyphSpacing = fGlyphInfoBuffer[offset].style->glyphSpacing;
|
// the font provided metrics passed in "width"
|
||||||
else
|
width = style.Width();
|
||||||
additionalGlyphSpacing = fGlyphSpacing;
|
|
||||||
|
|
||||||
if (fGlyphInfoBuffer[offset].style.Get() != NULL
|
|
||||||
&& fGlyphInfoBuffer[offset].style->width > 0.0f) {
|
|
||||||
// Use the metrics provided by the TextStyle
|
|
||||||
advanceX = fGlyphInfoBuffer[offset].style->width
|
|
||||||
+ additionalGlyphSpacing;
|
|
||||||
} else {
|
|
||||||
advanceX = escapementArray[offset] + additionalGlyphSpacing;
|
|
||||||
advanceY = 0.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
width += style.GlyphSpacing();
|
||||||
|
|
||||||
|
GlyphInfo glyph(charCode, 0.0f, width, width, 0, style);
|
||||||
|
return fGlyphInfos.Add(glyph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ParagraphLayout::_FinalizeLine(int lineStart, int lineEnd, int lineIndex, float y,
|
ParagraphLayout::_FinalizeLine(int lineStart, int lineEnd, int lineIndex,
|
||||||
float& lineHeight)
|
float y, float& lineHeight)
|
||||||
{
|
{
|
||||||
lineHeight = 0.0f;
|
lineHeight = 0.0f;
|
||||||
float maxAscent = 0.0f;
|
float maxAscent = 0.0f;
|
||||||
float maxDescent = 0.0f;
|
float maxDescent = 0.0f;
|
||||||
|
|
||||||
for (int i = lineStart; i <= lineEnd; i++) {
|
for (int i = lineStart; i <= lineEnd; i++) {
|
||||||
if (fGlyphInfoBuffer[i].style.Get() != NULL) {
|
GlyphInfo glyph = fGlyphInfos.ItemAtFast(i);
|
||||||
if (fGlyphInfoBuffer[i].style->font.Size() > lineHeight)
|
glyph.lineIndex = lineIndex;
|
||||||
lineHeight = fGlyphInfoBuffer[i].style->font.Size();
|
fGlyphInfos.Replace(i, glyph);
|
||||||
if (fGlyphInfoBuffer[i].style->ascent > maxAscent)
|
|
||||||
maxAscent = fGlyphInfoBuffer[i].style->ascent;
|
const CharacterStyle& style = glyph.style;
|
||||||
if (fGlyphInfoBuffer[i].style->descent > maxDescent)
|
|
||||||
maxDescent = fGlyphInfoBuffer[i].style->descent;
|
if (style.Font().Size() > lineHeight)
|
||||||
} else {
|
lineHeight = style.Font().Size();
|
||||||
if (fDefaultFont.Size() > lineHeight)
|
|
||||||
lineHeight = fDefaultFont.Size();
|
if (style.Ascent() > maxAscent)
|
||||||
if (fAscent > maxAscent)
|
maxAscent = style.Ascent();
|
||||||
maxAscent = fAscent;
|
|
||||||
if (fDescent > maxDescent)
|
if (style.Descent() > maxDescent)
|
||||||
maxDescent = fDescent;
|
maxDescent = style.Descent();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fLayoutLines.Add(LayoutLine(lineStart, y, lineHeight, maxAscent, maxDescent));
|
fLineInfos.Add(LineInfo(lineStart, y, lineHeight, maxAscent, maxDescent));
|
||||||
|
|
||||||
for (int i = lineStart; i <= lineEnd; i++) {
|
|
||||||
fGlyphInfoBuffer[i].maxAscent = maxAscent;
|
|
||||||
fGlyphInfoBuffer[i].maxDescent = maxDescent;
|
|
||||||
fGlyphInfoBuffer[i].lineIndex = lineIndex;
|
|
||||||
fGlyphInfoBuffer[i].y += maxAscent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ParagraphLayout::_DrawLine(BView* view, const LayoutLine& line) const
|
ParagraphLayout::_DrawLine(BView* view, const LineInfo& line) const
|
||||||
{
|
{
|
||||||
int textOffset = line.textOffset;
|
int textOffset = line.textOffset;
|
||||||
int spanCount = line.layoutedSpans.CountItems();
|
int spanCount = line.layoutedSpans.CountItems();
|
||||||
for (int i = 0; i < spanCount) {
|
for (int i = 0; i < spanCount; i++) {
|
||||||
const TextSpan& span = line.layoutedSpans.ItemAtFast(i);
|
const TextSpan& span = line.layoutedSpans.ItemAtFast(i);
|
||||||
_DrawSpan(view, span, textOffset);
|
_DrawSpan(view, span, textOffset);
|
||||||
textOffset += span.CharCount();
|
textOffset += span.CharCount();
|
||||||
@@ -579,15 +511,18 @@ ParagraphLayout::_DrawLine(BView* view, const LayoutLine& line) const
|
|||||||
|
|
||||||
void
|
void
|
||||||
ParagraphLayout::_DrawSpan(BView* view, const TextSpan& span,
|
ParagraphLayout::_DrawSpan(BView* view, const TextSpan& span,
|
||||||
int textOffset) const
|
int32 textOffset) const
|
||||||
{
|
{
|
||||||
float x = fGlyphInfoBuffer[textOffset].x;
|
const GlyphInfo& glyph = fGlyphInfos.ItemAtFast(textOffset);
|
||||||
float y = fGlyphInfoBuffer[textOffset].y;
|
const LineInfo& line = fLineInfos.ItemAtFast(glyph.lineIndex);
|
||||||
|
|
||||||
|
float x = glyph.x;
|
||||||
|
float y = line.y + line.maxAscent;
|
||||||
|
|
||||||
const TextStyle& style = span.Style();
|
const CharacterStyle& style = span.Style();
|
||||||
|
|
||||||
view->SetFont(&style.font);
|
view->SetFont(&style.Font());
|
||||||
view->SetHighColor(style.fgColor);
|
view->SetHighColor(style.ForegroundColor());
|
||||||
|
|
||||||
// TODO: Implement other style properties
|
// TODO: Implement other style properties
|
||||||
// TODO: Implement correct glyph spacing
|
// TODO: Implement correct glyph spacing
|
||||||
|
|||||||
@@ -9,26 +9,117 @@
|
|||||||
#include <Referenceable.h>
|
#include <Referenceable.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
|
||||||
#include "GlyphInfo.h"
|
|
||||||
#include "Paragraph.h"
|
#include "Paragraph.h"
|
||||||
|
#include "CharacterStyle.h"
|
||||||
|
|
||||||
|
|
||||||
class BView;
|
class BView;
|
||||||
|
|
||||||
|
|
||||||
class LayoutLine {
|
class GlyphInfo {
|
||||||
public:
|
public:
|
||||||
LayoutLine()
|
GlyphInfo()
|
||||||
|
:
|
||||||
|
charCode(0),
|
||||||
|
x(0.0f),
|
||||||
|
width(0.0f),
|
||||||
|
advanceX(0.0f),
|
||||||
|
lineIndex(0),
|
||||||
|
style()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GlyphInfo(uint32 charCode, float x, float width, float advanceX,
|
||||||
|
int32 lineIndex, const CharacterStyle& style)
|
||||||
|
:
|
||||||
|
charCode(charCode),
|
||||||
|
x(x),
|
||||||
|
width(width),
|
||||||
|
advanceX(advanceX),
|
||||||
|
lineIndex(lineIndex),
|
||||||
|
style(style)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GlyphInfo(const GlyphInfo& other)
|
||||||
|
:
|
||||||
|
charCode(other.charCode),
|
||||||
|
x(other.x),
|
||||||
|
width(other.width),
|
||||||
|
advanceX(other.advanceX),
|
||||||
|
lineIndex(other.lineIndex),
|
||||||
|
style(other.style)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GlyphInfo& operator=(const GlyphInfo& other)
|
||||||
|
{
|
||||||
|
charCode = other.charCode;
|
||||||
|
x = other.x;
|
||||||
|
width = other.width;
|
||||||
|
advanceX = other.advanceX;
|
||||||
|
lineIndex = other.lineIndex;
|
||||||
|
style = other.style;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const GlyphInfo& other) const
|
||||||
|
{
|
||||||
|
return charCode == other.charCode
|
||||||
|
&& x == other.x
|
||||||
|
&& width == other.width
|
||||||
|
&& advanceX == other.advanceX
|
||||||
|
&& lineIndex == other.lineIndex
|
||||||
|
&& style == other.style;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const GlyphInfo& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint32 charCode;
|
||||||
|
|
||||||
|
float x;
|
||||||
|
float width;
|
||||||
|
float advanceX;
|
||||||
|
|
||||||
|
int32 lineIndex;
|
||||||
|
|
||||||
|
CharacterStyle style;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef List<GlyphInfo, false> GlyphInfoList;
|
||||||
|
|
||||||
|
|
||||||
|
class LineInfo {
|
||||||
|
public:
|
||||||
|
LineInfo()
|
||||||
:
|
:
|
||||||
textOffset(0),
|
textOffset(0),
|
||||||
y(0.0f),
|
y(0.0f),
|
||||||
height(0.0f),
|
height(0.0f),
|
||||||
maxAscent(0.0f),
|
maxAscent(0.0f),
|
||||||
maxDescent(0.0f)
|
maxDescent(0.0f),
|
||||||
|
layoutedSpans()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutLine(const LayoutLine& other)
|
LineInfo(int32 textOffset, float y, float height, float maxAscent,
|
||||||
|
float maxDescent)
|
||||||
|
:
|
||||||
|
textOffset(textOffset),
|
||||||
|
y(y),
|
||||||
|
height(height),
|
||||||
|
maxAscent(maxAscent),
|
||||||
|
maxDescent(maxDescent),
|
||||||
|
layoutedSpans()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LineInfo(const LineInfo& other)
|
||||||
:
|
:
|
||||||
textOffset(other.textOffset),
|
textOffset(other.textOffset),
|
||||||
y(other.y),
|
y(other.y),
|
||||||
@@ -39,7 +130,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutLine& operator=(const LayoutLine& other)
|
LineInfo& operator=(const LineInfo& other)
|
||||||
{
|
{
|
||||||
textOffset = other.textOffset;
|
textOffset = other.textOffset;
|
||||||
y = other.y;
|
y = other.y;
|
||||||
@@ -50,23 +141,23 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const LayoutLine& other) const
|
bool operator==(const LineInfo& other) const
|
||||||
{
|
{
|
||||||
return textOffset == other.textOffset
|
return textOffset == other.textOffset
|
||||||
&& y == other.y
|
&& y == other.y
|
||||||
&& height == other.height
|
&& height == other.height
|
||||||
&& maxAscent == other.maxAscent
|
&& maxAscent == other.maxAscent
|
||||||
&& maxDescent == other.maxDescent
|
&& maxDescent == other.maxDescent
|
||||||
&& layoutedSpans == otner.layoutedSpans;
|
&& layoutedSpans == other.layoutedSpans;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const LayoutLine& other) const
|
bool operator!=(const LineInfo& other) const
|
||||||
{
|
{
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int textOffset;
|
int32 textOffset;
|
||||||
float y;
|
float y;
|
||||||
float height;
|
float height;
|
||||||
float maxAscent;
|
float maxAscent;
|
||||||
@@ -76,7 +167,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef List<LayoutLine, false> LayoutLineList;
|
typedef List<LineInfo, false> LineInfoList;
|
||||||
|
|
||||||
|
|
||||||
class ParagraphLayout : public BReferenceable {
|
class ParagraphLayout : public BReferenceable {
|
||||||
@@ -86,9 +177,7 @@ public:
|
|||||||
ParagraphLayout(const ParagraphLayout& other);
|
ParagraphLayout(const ParagraphLayout& other);
|
||||||
virtual ~ParagraphLayout();
|
virtual ~ParagraphLayout();
|
||||||
|
|
||||||
void SetParagraph(const ::Paragraph& paragraph);
|
void SetParagraph(const Paragraph& paragraph);
|
||||||
const ::Paragraph& Paragraph() const
|
|
||||||
{ return fParagraph; }
|
|
||||||
|
|
||||||
void SetWidth(float width);
|
void SetWidth(float width);
|
||||||
float Width() const
|
float Width() const
|
||||||
@@ -104,32 +193,26 @@ private:
|
|||||||
void _Init();
|
void _Init();
|
||||||
bool _AppendGlyphInfos(const TextSpan& span);
|
bool _AppendGlyphInfos(const TextSpan& span);
|
||||||
bool _AppendGlyphInfo(uint32 charCode,
|
bool _AppendGlyphInfo(uint32 charCode,
|
||||||
const TextStyleRef& span);
|
float advanceX,
|
||||||
|
const CharacterStyle& style);
|
||||||
|
|
||||||
void _GetGlyphAdvance(int offset,
|
|
||||||
float& advanceX, float& advanceY,
|
|
||||||
float escapementArray[]) const;
|
|
||||||
|
|
||||||
void _FinalizeLine(int lineStart, int lineEnd,
|
void _FinalizeLine(int lineStart, int lineEnd,
|
||||||
int lineIndex, float y, float& lineHeight);
|
int lineIndex, float y, float& lineHeight);
|
||||||
|
|
||||||
void _DrawLine(BView* view,
|
void _DrawLine(BView* view,
|
||||||
const LayoutLine& line) const;
|
const LineInfo& line) const;
|
||||||
void _DrawSpan(BView* view, const TextSpan& span,
|
void _DrawSpan(BView* view, const TextSpan& span,
|
||||||
int textOffset) const;
|
int32 textOffset) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TextSpanList fTextSpans;
|
TextSpanList fTextSpans;
|
||||||
|
ParagraphStyle fParagraphStyle;
|
||||||
|
|
||||||
float fWidth;
|
float fWidth;
|
||||||
|
|
||||||
bool fLayoutValid;
|
bool fLayoutValid;
|
||||||
|
|
||||||
GlyphInfo* fGlyphInfoBuffer;
|
GlyphInfoList fGlyphInfos;
|
||||||
int fGlpyhInfoBufferSize;
|
LineInfoList fLineInfos;
|
||||||
int fGlyphInfoCount;
|
|
||||||
|
|
||||||
LayoutLineList fLayoutLines;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PARAGRAPH_LAYOUT_H
|
#endif // PARAGRAPH_LAYOUT_H
|
||||||
|
|||||||
Reference in New Issue
Block a user