blob: bed19f2d96a44b2a580df90c64928b5eaecee087 [file] [log] [blame]
#ifndef _RIVE_TEXT_CORE_HPP_
#define _RIVE_TEXT_CORE_HPP_
#include "rive/generated/text/text_base.hpp"
#include "rive/text/text_value_run.hpp"
#include "rive/text_engine.hpp"
#include "rive/simple_array.hpp"
#include <vector>
#include "rive/text/glyph_lookup.hpp"
namespace rive
{
enum class TextSizing : uint8_t
{
autoWidth,
autoHeight,
fixed
};
enum class TextOverflow : uint8_t
{
visible,
hidden,
clipped,
ellipsis
};
enum class TextOrigin : uint8_t
{
top,
baseline
};
class OrderedLine;
class TextModifierGroup;
class StyledText
{
private:
/// Represents the unicode characters making up the entire text string
/// displayed. Only valid after update.
std::vector<Unichar> m_value;
std::vector<TextRun> m_runs;
public:
bool empty() const;
void clear();
void append(rcp<Font> font,
float size,
float lineHeight,
float letterSpacing,
const std::string& text,
uint16_t styleId);
const std::vector<Unichar>& unichars() const { return m_value; }
const std::vector<TextRun>& runs() const { return m_runs; }
void swapRuns(std::vector<TextRun>& otherRuns) { m_runs.swap(otherRuns); }
};
// STL-style iterator for individual glyphs in a line, simplfies call sites from
// needing to iterate both runs and glyphs within those runs per line. A single
// iterator allows iterating all the glyphs in the line and provides the correct
// run they belong to (this also takes into account bidi which can put the runs
// in different order from how they were provided by the line breaker).
//
// for (auto [run, glyphIndex] : orderedLine) { ... }
//
class GlyphItr
{
public:
GlyphItr() = default;
GlyphItr(const OrderedLine* line, const rive::GlyphRun* const* run, uint32_t glyphIndex) :
m_line(line), m_run(run), m_glyphIndex(glyphIndex)
{}
void tryAdvanceRun();
bool operator!=(const GlyphItr& that) const
{
return m_run != that.m_run || m_glyphIndex != that.m_glyphIndex;
}
bool operator==(const GlyphItr& that) const
{
return m_run == that.m_run && m_glyphIndex == that.m_glyphIndex;
}
GlyphItr& operator++();
std::tuple<const GlyphRun*, uint32_t> operator*() const { return {*m_run, m_glyphIndex}; }
private:
const OrderedLine* m_line;
const rive::GlyphRun* const* m_run;
uint32_t m_glyphIndex;
};
// Represents a line of text with runs ordered visually. Also tracks logical
// start/end which will defer when using bidi.
class OrderedLine
{
public:
OrderedLine(const Paragraph& paragraph,
const GlyphLine& line,
float lineWidth, // for ellipsis
bool wantEllipsis,
bool isEllipsisLineLast,
GlyphRun* ellipsisRun);
bool buildEllipsisRuns(std::vector<const GlyphRun*>& logicalRuns,
const Paragraph& paragraph,
const GlyphLine& line,
float lineWidth,
bool isEllipsisLineLast,
GlyphRun* ellipsisRun);
const GlyphRun* startLogical() const { return m_startLogical; }
const GlyphRun* endLogical() const { return m_endLogical; }
const std::vector<const GlyphRun*>& runs() const { return m_runs; }
GlyphItr begin() const
{
auto runItr = m_runs.data();
auto itr = GlyphItr(this, runItr, startGlyphIndex(*runItr));
itr.tryAdvanceRun();
return itr;
}
GlyphItr end() const
{
auto runItr = m_runs.data() + (m_runs.size() == 0 ? 0 : m_runs.size() - 1);
return GlyphItr(this, runItr, endGlyphIndex(*runItr));
}
private:
const GlyphRun* m_startLogical = nullptr;
const GlyphRun* m_endLogical = nullptr;
uint32_t m_startGlyphIndex;
uint32_t m_endGlyphIndex;
std::vector<const GlyphRun*> m_runs;
public:
const GlyphRun* lastRun() const { return m_runs.back(); }
uint32_t startGlyphIndex(const GlyphRun* run) const
{
switch (run->dir)
{
case TextDirection::ltr:
return m_startLogical == run ? m_startGlyphIndex : 0;
case TextDirection::rtl:
return (m_endLogical == run ? m_endGlyphIndex : (uint32_t)run->glyphs.size()) - 1;
}
RIVE_UNREACHABLE();
}
uint32_t endGlyphIndex(const GlyphRun* run) const
{
switch (run->dir)
{
case TextDirection::ltr:
return m_endLogical == run ? m_endGlyphIndex : (uint32_t)run->glyphs.size();
case TextDirection::rtl:
return (m_startLogical == run ? m_startGlyphIndex : 0) - 1;
}
RIVE_UNREACHABLE();
}
};
class TextStyle;
class Text : public TextBase
{
public:
void draw(Renderer* renderer) override;
Core* hitTest(HitInfo*, const Mat2D&) override;
void addRun(TextValueRun* run);
void addModifierGroup(TextModifierGroup* group);
void markShapeDirty();
void modifierShapeDirty();
void markPaintDirty();
void update(ComponentDirt value) override;
TextSizing sizing() const { return (TextSizing)sizingValue(); }
TextOverflow overflow() const { return (TextOverflow)overflowValue(); }
TextOrigin textOrigin() const { return (TextOrigin)originValue(); }
void overflow(TextOverflow value) { return overflowValue((uint32_t)value); }
void buildRenderStyles();
const TextStyle* styleFromShaperId(uint16_t id) const;
bool modifierRangesNeedShape() const;
AABB localBounds() const override;
void originXChanged() override;
void originYChanged() override;
#ifdef WITH_RIVE_TEXT
const std::vector<TextValueRun*>& runs() const { return m_runs; }
#endif
bool haveModifiers() const
{
#ifdef WITH_RIVE_TEXT
return !m_modifierGroups.empty();
#else
return false;
#endif
}
#ifdef TESTING
const std::vector<OrderedLine>& orderedLines() const { return m_orderedLines; }
const std::vector<TextModifierGroup*>& modifierGroups() const { return m_modifierGroups; }
const SimpleArray<Paragraph>& shape() const { return m_shape; }
const std::vector<Unichar>& unichars() const { return m_styledText.unichars(); }
#endif
protected:
void alignValueChanged() override;
void sizingValueChanged() override;
void overflowValueChanged() override;
void widthChanged() override;
void heightChanged() override;
void paragraphSpacingChanged() override;
bool makeStyled(StyledText& styledText, bool withModifiers = true) const;
void originValueChanged() override;
private:
#ifdef WITH_RIVE_TEXT
void updateOriginWorldTransform();
std::vector<TextValueRun*> m_runs;
std::vector<TextStyle*> m_renderStyles;
SimpleArray<Paragraph> m_shape;
SimpleArray<Paragraph> m_modifierShape;
SimpleArray<SimpleArray<GlyphLine>> m_lines;
SimpleArray<SimpleArray<GlyphLine>> m_modifierLines;
// Runs ordered by paragraph line.
std::vector<OrderedLine> m_orderedLines;
GlyphRun m_ellipsisRun;
rcp<RenderPath> m_clipRenderPath;
AABB m_bounds;
std::vector<TextModifierGroup*> m_modifierGroups;
StyledText m_styledText;
StyledText m_modifierStyledText;
GlyphLookup m_glyphLookup;
#endif
};
} // namespace rive
#endif