blob: 34654307c207fcacd82214ae8268c79a07b2f7ba [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"
namespace rive
{
enum class TextSizing : uint8_t
{
autoWidth,
autoHeight,
fixed
};
enum class TextOverflow : uint8_t
{
visible,
hidden,
clipped,
ellipsis
};
class OrderedLine;
// 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 GlyphRun* run, uint32_t glyphIndex) :
m_line(line), m_run(run), m_glyphIndex(glyphIndex)
{}
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 GlyphRun* 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);
const GlyphRun* startLogical() const { return m_startLogical; }
const GlyphRun* endLogical() const { return m_endLogical; }
const GlyphLine* glyphLine() const { return m_line; }
const std::vector<const GlyphRun*>& runs() const { return m_runs; }
GlyphItr begin() const
{
auto run = m_runs[0];
return GlyphItr(this, run, startGlyphIndex(run));
}
GlyphItr end() const
{
auto run = lastRun();
return GlyphItr(this, run, endGlyphIndex(run));
}
private:
const GlyphRun* m_startLogical;
const GlyphRun* m_endLogical;
const GlyphLine* m_line;
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_line->startGlyphIndex : 0;
case TextDirection::rtl:
return (m_endLogical == run ? m_line->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_line->endGlyphIndex : (uint32_t)run->glyphs.size();
case TextDirection::rtl:
return (m_startLogical == run ? m_line->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 markShapeDirty();
void update(ComponentDirt value) override;
TextSizing sizing() { return (TextSizing)sizingValue(); }
TextOverflow overflow() { return (TextOverflow)overflowValue(); }
void buildRenderStyles();
protected:
void alignValueChanged() override;
void sizingValueChanged() override;
void overflowValueChanged() override;
void widthChanged() override;
void heightChanged() override;
private:
#ifdef WITH_RIVE_TEXT
std::vector<TextValueRun*> m_runs;
std::vector<TextStyle*> m_renderStyles;
SimpleArray<Paragraph> m_shape;
SimpleArray<SimpleArray<GlyphLine>> m_lines;
// Runs ordered by paragraph line.
std::vector<OrderedLine> m_orderedLines;
#endif
};
} // namespace rive
#endif