harfbuzz/src/graphite2/src/inc/Slot.h

395 lines
14 KiB
C++

// SPDX-License-Identifier: MIT
// Copyright 2010, SIL International, All rights reserved.
#pragma once
#include <cassert>
#include <cstring>
#include <limits>
#include <type_traits>
#include "graphite2/Segment.h"
#include "inc/GlyphFace.h"
#include "inc/Main.h"
#include "inc/Position.h"
namespace graphite2 {
class Segment;
// class Slot;
class ShapingContext;
class Font;
struct Slot_data {
int8_t m_parent_offset; // index to parent we are attached to
Position m_position; // absolute position of glyph
Position m_shift; // .shift slot attribute
Position m_advance; // .advance slot attribute
Position m_attach; // attachment point on us
Position m_with; // attachment point position on parent
float m_just; // Justification inserted space
uint32_t m_original; // charinfo that originated this slot (e.g. for feature values)
uint32_t m_before; // charinfo index of before association
uint32_t m_after; // charinfo index of after association
uint32_t m_index; // slot index given to this slot during finalising
uint16_t m_glyphid; // glyph id
uint16_t m_realglyphid;
byte m_attLevel; // attachment level
byte m_bidiLevel; // bidirectional level
int8_t m_bidiCls; // bidirectional class
struct {
bool deleted: 1,
inserted: 1,
copied: 1,
positioned: 1,
clusterhead:1,
last:1,
children:1;
} m_flags; // holds bit flags
};
class Slot : private Slot_data
{
static constexpr int NUMJUSTPARAMS = 5;
union attributes {
private:
struct {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
uint8_t n_attrs;
#endif
int16_t data[sizeof(uintptr_t)/sizeof(int16_t)-1];
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
uint8_t n_attrs;
#endif
} local;
struct {
uint8_t n_attrs, n_justs;
int16_t data[1];
} * external;
bool is_inline() const { return !external || uintptr_t(external) & 0x3;}
public:
constexpr attributes(): external{nullptr} {}
attributes(size_t n_attrs, size_t n_justs = 0): external{nullptr} { reserve(n_attrs, n_justs); }
attributes(attributes const & rhs): external{nullptr} { operator = (rhs); }
attributes(attributes && rhs) noexcept : external{rhs.external} { rhs.external = nullptr; }
~attributes() noexcept { if (!is_inline()) free(external); }
void reserve(size_t target_num_attrs, size_t target_num_justs);
attributes & operator = (attributes const & rhs);
attributes & operator = (attributes && rhs) noexcept;
size_t num_attrs() const { return is_inline() ? local.n_attrs : external->n_attrs; }
size_t num_justs() const { return is_inline() ? 0 : external->n_justs; }
int16_t * user_attributes() { return is_inline() ? local.data : external->data; }
int16_t const * user_attributes() const { return is_inline() ? local.data : external->data; }
int16_t * just_info() { return is_inline() ? nullptr : external->data + external->n_attrs; }
int16_t const * just_info() const { return is_inline() ? nullptr : external->data + external->n_attrs; }
};
bool has_justify() const { return m_attrs.num_justs() != 0; };
void init_just_infos(Segment const & seg);
void attachTo(Slot *ap);
attributes m_attrs;
#if !defined GRAPHITE2_NTRACING
uint8_t m_gen;
#endif
template<class S> class _cluster_iterator;
template<class S> class _child_iterator;
public:
using cluster_iterator = _cluster_iterator<Slot>;
using const_cluster_iterator = _cluster_iterator<Slot const>;
using child_iterator = _child_iterator<Slot>;
using const_child_iterator = _child_iterator<Slot const>;
struct sentinal {};
using attrCode = gr_attrCode;
// static bool is_sentinal(Slot const & s) noexcept {
// return s.m_index == 0xffffffff
// && s.m_glyphid == 0xffff
// && s.m_realglyphid == 0xffff;
// }
// template<class T>
constexpr Slot(sentinal const &)
: Slot_data{0, {}, {}, {}, {}, {}, 0, 0, 0, 0, -1u, uint16_t(-1), uint16_t(-1), 0, 0, 0, {true,false,false,false,true,true,false}},
m_attrs{}
#if !defined GRAPHITE2_NTRACING
, m_gen{0}
#endif
{}
Slot(size_t num_attrs = 0) : Slot_data{}, m_attrs{num_attrs} {}
Slot(Slot const &);
Slot(Slot &&) noexcept;
Slot & operator=(Slot const &);
Slot & operator=(Slot &&) noexcept;
// Glyph
uint16_t gid() const { return m_glyphid; }
uint16_t glyph() const { return m_realglyphid ? m_realglyphid : m_glyphid; }
void glyph(Segment &seg, uint16_t glyphid, const GlyphFace * theGlyph = nullptr);
// void setRealGid(uint16_t realGid) { m_realglyphid = realGid; }
// Positioning
Position const & origin() const { return m_position; }
Position & origin() { return m_position; }
Position const & shift() const { return m_shift; }
// void adjKern(const Position &pos) { m_shift = m_shift + pos; m_advance = m_advance + pos; }
float advance() const { return m_advance.x; }
void advance(Position &val) { m_advance = val; }
Position attachOffset() const { return m_attach - m_with; }
Position const & advancePos() const { return m_advance; }
void position_shift(Position const & p) { m_position += p; }
void floodShift(Position adj, int depth = 0);
void scale_by(float scale) { m_position *= scale; /*m_advance *= scale; m_shift *= scale; m_with *= scale; m_attach *= scale; */}
Position collision_shift(Segment const & seg) const;
// Slot ordering
uint32_t index() const { return m_index; }
void index(uint32_t val) { m_index = val; }
int before() const { return m_before; }
void before(int ind) { m_before = ind; }
int after() const { return m_after; }
void after(int ind) { m_after = ind; }
int original() const { return m_original; }
void original(int ind) { m_original = ind; }
// // Flags
bool deleted() const { return m_flags.deleted; }
void deleted(bool state) { m_flags.deleted = state; }
bool copied() const { return m_flags.copied; }
void copied(bool state) { m_flags.copied = state; }
// bool positioned() const { return m_flags.positioned; }
// void positioned(bool state) { m_flags.positioned = state; }
bool last() const { return m_flags.last; }
void last(bool state) { m_flags.last = state; }
bool insertBefore() const { return !m_flags.inserted; }
void insertBefore(bool state) { m_flags.inserted = !state; }
void clusterhead(bool state) { m_flags.clusterhead = state; }
bool clusterhead() const { return m_flags.clusterhead ;}
// Bidi
uint8_t bidiLevel() const { return m_bidiLevel; }
void bidiLevel(uint8_t level) { m_bidiLevel = level; }
int8_t bidiClass() const { return m_bidiCls; }
void bidiClass(int8_t cls) { m_bidiCls = cls; }
// Operations
Position update_cluster_metric(Segment const & seg, bool const rtl, bool const is_final, float & clsb, float & crsb, unsigned depth=100);
void update(int numSlots, int numCharInfo, Position &relpos);
Position finalise(const Segment & seg, const Font* font, Position & base, Rect & bbox, uint8_t attrLevel, float & clusterMin, bool rtl, bool isFinal, int depth = 0);
int32_t clusterMetric(Segment const & seg, metrics metric, uint8_t attrLevel, bool rtl) const;
// Attributes
void setAttr(Segment & seg, attrCode ind, uint8_t subindex, int16_t val, const ShapingContext & map);
int getAttr(const Segment &seg, attrCode ind, uint8_t subindex) const;
int16_t const *userAttrs() const { return m_attrs.user_attributes(); }
// // Justification
int getJustify(const Segment &seg, uint8_t level, uint8_t subindex) const;
void setJustify(Segment &seg, uint8_t level, uint8_t subindex, int16_t value);
float just() const { return m_just; }
void just(float j) { m_just = j; }
// Clustering
cluster_iterator cluster();
const_cluster_iterator cluster() const;
child_iterator children();
const_child_iterator children() const;
const_cluster_iterator end() const noexcept;
bool isBase() const { return !m_parent_offset; }
bool isParent() const { return m_flags.children; }
Slot const * base() const noexcept;
Slot * base() noexcept { return const_cast<Slot*>(const_cast<Slot const *>(this)->base()); }
Slot const * attachedTo() const;
Slot * attachedTo() { return const_cast<Slot *>(const_cast<Slot const *>(this)->attachedTo());}
bool add_child(Slot *ap);
bool remove_child(Slot *ap);
bool has_base(const Slot *base) const;
#if !defined GRAPHITE2_NTRACING
uint8_t & generation() { return m_gen; }
uint8_t generation() const { return m_gen; }
#else
uint8_t & generation() { static uint8_t _v; return _v; }
#endif
CLASS_NEW_DELETE
};
template<class S>
class Slot::_cluster_iterator {
protected:
S* _s;
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = S;
using pointer = value_type*;
using reference = value_type&;
constexpr _cluster_iterator() noexcept: _s{nullptr} {}
_cluster_iterator(pointer s) noexcept : _s{s} {}
bool operator == (_cluster_iterator<S const> const & rhs) const noexcept;
bool operator != (_cluster_iterator<S const> const & rhs) const noexcept;
reference operator*() const noexcept { return *_s; }
pointer operator->() const noexcept { return &operator*(); }
_cluster_iterator<S> & operator++() noexcept { assert(_s); if ((++_s)->clusterhead()) _s = nullptr; return *this; }
_cluster_iterator<S> operator++(int) noexcept { auto tmp(*this); operator++(); return tmp; }
_cluster_iterator<S> & operator--() noexcept { assert(_s); --_s; return *this; }
_cluster_iterator<S> operator--(int) noexcept { auto tmp(*this); operator--(); return tmp; }
operator _cluster_iterator<S const> const &() const noexcept { return *reinterpret_cast<_cluster_iterator<S const> const *>(this); }
};
template<class S>
inline
bool Slot::_cluster_iterator<S>::operator == (_cluster_iterator<S const> const & rhs) const noexcept {
return _s == rhs._s;
}
template<class S>
inline
bool Slot::_cluster_iterator<S>::operator != (_cluster_iterator<S const> const & rhs) const noexcept {
return !rhs.operator==(*this);
}
template<class S>
class Slot::_child_iterator: public _cluster_iterator<S> {
using base_t = Slot::_cluster_iterator<S>;
void _next_child(base_t & (base_t::*advfn)()) noexcept {
assert(base_t::_s);
auto parent = base_t::_s->attachedTo();
do {
(this->*advfn)();
} while (base_t::_s && base_t::_s->attachedTo() != parent);
}
public:
using base_t::iterator_category;
using base_t::value_type;
using base_t::pointer;
using base_t::reference;
constexpr _child_iterator(): _cluster_iterator<S>{} {}
_child_iterator(S * s): base_t{s} {}
_child_iterator<S> & operator++() noexcept { _next_child(&base_t::operator++); return *this; }
_child_iterator<S> operator++(int) noexcept { auto tmp(*this); operator++(); return tmp; }
_child_iterator<S> & operator--() noexcept { _next_child(&base_t::operator--); return *this; }
_child_iterator<S> operator--(int) noexcept { auto tmp(*this); operator--(); return tmp; }
gr_slot const * handle() const noexcept {
return base_t::_s
? base_t::_s->last() && base_t::_s->gid() == 0xffff && base_t::_s->deleted()
? nullptr
: static_cast<gr_slot const *>(base_t::_s)
: nullptr;
}
operator _child_iterator<S const>() const noexcept { return *reinterpret_cast<_child_iterator<S const> const *>(this); }
};
inline
auto Slot::cluster() -> cluster_iterator {
auto r = this;
while (!r->clusterhead()) --r;
return const_cast<Slot *>(r);
}
inline
auto Slot::cluster() const -> const_cluster_iterator {
auto r = this;
while (!r->clusterhead()) --r;
return const_cast<Slot *>(r);
}
inline
auto Slot::children() -> child_iterator {
for (auto ci = cluster(), end = cluster_iterator(); ci != end; ++ci)
if (ci->attachedTo() == this) return child_iterator(&*ci);
return child_iterator();
}
inline
auto Slot::children() const -> const_child_iterator {
for (auto ci = cluster(), end = const_cluster_iterator(); ci != end; ++ci)
if (ci->attachedTo() == this) return const_child_iterator(&*ci);
return const_child_iterator();
}
inline
auto Slot::end() const noexcept -> const_cluster_iterator {
return const_cluster_iterator();
}
inline
Slot::Slot(Slot && rhs) noexcept
: Slot_data(std::move(rhs)),
m_attrs(std::move(rhs.m_attrs))
#if !defined GRAPHITE2_NTRACING
,m_gen(rhs.m_gen)
#endif
{
m_parent_offset = 0;
}
inline
Slot::Slot(Slot const & rhs)
: Slot_data(rhs),
m_attrs(rhs.m_attrs)
#if !defined GRAPHITE2_NTRACING
,m_gen(rhs.m_gen)
#endif
{
m_parent_offset = 0;
}
inline
Slot const * Slot::base() const noexcept {
auto s = this;
while (s->m_parent_offset)
s += s->m_parent_offset;
return s;
}
inline
auto Slot::attachedTo() const -> Slot const * {
return m_parent_offset ? this + m_parent_offset : nullptr;
}
inline
void Slot::attachTo(Slot *ap) {
m_parent_offset = ap ? ap - this : 0;
}
} // namespace graphite2
struct gr_slot : public graphite2::Slot {};