* Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PARAGRAPH_LAYOUT_H
#define PARAGRAPH_LAYOUT_H
#include <vector>
#include <Font.h>
#include <Referenceable.h>
#include <String.h>
#include "CharacterStyle.h"
#include "List.h"
#include "Paragraph.h"
class BView;
class GlyphInfo {
public:
GlyphInfo()
:
charCode(0),
x(0.0f),
width(0.0f),
lineIndex(0)
{
}
GlyphInfo(uint32 charCode, float x, float width, int32 lineIndex)
:
charCode(charCode),
x(x),
width(width),
lineIndex(lineIndex)
{
}
GlyphInfo(const GlyphInfo& other)
:
charCode(other.charCode),
x(other.x),
width(other.width),
lineIndex(other.lineIndex)
{
}
GlyphInfo& operator=(const GlyphInfo& other)
{
charCode = other.charCode;
x = other.x;
width = other.width;
lineIndex = other.lineIndex;
return *this;
}
bool operator==(const GlyphInfo& other) const
{
return charCode == other.charCode
&& x == other.x
&& width == other.width
&& lineIndex == other.lineIndex;
}
bool operator!=(const GlyphInfo& other) const
{
return !(*this == other);
}
public:
uint32 charCode;
float x;
float width;
int32 lineIndex;
};
class LineInfo {
public:
LineInfo()
:
textOffset(0),
y(0.0f),
height(0.0f),
maxAscent(0.0f),
maxDescent(0.0f),
extraGlyphSpacing(0.0f),
extraWhiteSpacing(0.0f),
layoutedSpans()
{
}
LineInfo(int32 textOffset, float y, float height, float maxAscent,
float maxDescent)
:
textOffset(textOffset),
y(y),
height(height),
maxAscent(maxAscent),
maxDescent(maxDescent),
extraGlyphSpacing(0.0f),
extraWhiteSpacing(0.0f),
layoutedSpans()
{
}
LineInfo(const LineInfo& other)
:
textOffset(other.textOffset),
y(other.y),
height(other.height),
maxAscent(other.maxAscent),
maxDescent(other.maxDescent),
extraGlyphSpacing(other.extraGlyphSpacing),
extraWhiteSpacing(other.extraWhiteSpacing),
layoutedSpans(other.layoutedSpans)
{
}
LineInfo& operator=(const LineInfo& other)
{
textOffset = other.textOffset;
y = other.y;
height = other.height;
maxAscent = other.maxAscent;
maxDescent = other.maxDescent;
extraGlyphSpacing = other.extraGlyphSpacing;
extraWhiteSpacing = other.extraWhiteSpacing;
layoutedSpans = other.layoutedSpans;
return *this;
}
bool operator==(const LineInfo& other) const
{
return textOffset == other.textOffset
&& y == other.y
&& height == other.height
&& maxAscent == other.maxAscent
&& maxDescent == other.maxDescent
&& extraGlyphSpacing == other.extraGlyphSpacing
&& extraWhiteSpacing == other.extraWhiteSpacing
&& layoutedSpans == other.layoutedSpans;
}
bool operator!=(const LineInfo& other) const
{
return !(*this == other);
}
public:
int32 textOffset;
float y;
float height;
float maxAscent;
float maxDescent;
float extraGlyphSpacing;
float extraWhiteSpacing;
std::vector<TextSpan>
layoutedSpans;
};
class ParagraphLayout : public BReferenceable {
public:
ParagraphLayout();
ParagraphLayout(const Paragraph& paragraph);
ParagraphLayout(const ParagraphLayout& other);
virtual ~ParagraphLayout();
void SetParagraph(const Paragraph& paragraph);
const ParagraphStyle& Style() const
{ return fParagraphStyle; }
void SetWidth(float width);
float Width() const
{ return fWidth; }
float Height();
void Draw(BView* view, const BPoint& offset);
int32 CountGlyphs() const;
int32 CountLines();
int32 LineIndexForOffset(int32 textOffset);
int32 FirstOffsetOnLine(int32 lineIndex);
int32 LastOffsetOnLine(int32 lineIndex);
void GetLineBounds(int32 lineIndex,
float& x1, float& y1,
float& x2, float& y2);
void GetTextBounds(int32 textOffset,
float& x1, float& y1,
float& x2, float& y2);
int32 TextOffsetAt(float x, float y,
bool& rightOfCenter);
private:
void _Init();
void _ValidateLayout();
void _Layout();
void _ApplyAlignment();
bool _AppendGlyphInfos(const TextSpan& span);
bool _AppendGlyphInfo(uint32 charCode,
float advanceX,
const CharacterStyle& style);
bool _FinalizeLine(int lineStart, int lineEnd,
int lineIndex, float y, float& lineHeight);
void _IncludeStyleInLine(LineInfo& line,
const CharacterStyle& style);
void _DrawLine(BView* view, const BPoint& offset,
const LineInfo& line) const;
void _DrawSpan(BView* view, BPoint offset,
const TextSpan& span,
int32 textOffset) const;
void _GetEmptyLayoutBounds(float& x1, float& y1,
float& x2, float& y2) const;
void _AppendTextSpans(const Paragraph& paragraph);
private:
std::vector<TextSpan>
fTextSpans;
ParagraphStyle fParagraphStyle;
float fWidth;
bool fLayoutValid;
std::vector<GlyphInfo>
fGlyphInfos;
std::vector<LineInfo>
fLineInfos;
};
typedef BReference<ParagraphLayout> ParagraphLayoutRef;
#endif