2025-12-03 22:00:29 +11:00
|
|
|
// From
|
|
|
|
|
// https://github.com/vroland/epdiy/blob/c61e9e923ce2418150d54f88cea5d196cdc40c54/src/epd_internals.h
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
|
2026-03-01 10:43:37 -06:00
|
|
|
/// Font metrics use "fixed-point 4" (4 fractional bits, i.e. 1/16-pixel
|
|
|
|
|
/// resolution). Both the 12.4 glyph advances (uint16_t) and the 4.4 kern
|
|
|
|
|
/// values (int8_t) share the same 4 fractional bits, so they can be freely
|
2026-04-07 22:20:50 -05:00
|
|
|
/// added before snapping to whole pixels.
|
|
|
|
|
///
|
|
|
|
|
/// Rendering and measurement use "differential rounding": each glyph step
|
|
|
|
|
/// (previous advance + current kern) is combined in fixed-point and snapped
|
|
|
|
|
/// to a pixel as one unit. This guarantees identical character pairs always
|
|
|
|
|
/// produce the same pixel spacing, regardless of position on the line.
|
2026-03-01 10:43:37 -06:00
|
|
|
///
|
|
|
|
|
/// The helpers below eliminate the raw bit-shifts that would otherwise be
|
|
|
|
|
/// scattered across every layout / measurement call site.
|
|
|
|
|
namespace fp4 {
|
|
|
|
|
constexpr int FRAC_BITS = 4;
|
|
|
|
|
constexpr int32_t HALF = 1 << (FRAC_BITS - 1); // 8, added before shift for round-to-nearest
|
|
|
|
|
|
|
|
|
|
/// Convert an integer pixel value to 12.4 fixed-point.
|
|
|
|
|
constexpr int32_t fromPixel(int px) { return static_cast<int32_t>(px) << FRAC_BITS; }
|
|
|
|
|
|
|
|
|
|
/// Snap a fixed-point value to the nearest integer pixel.
|
|
|
|
|
constexpr int toPixel(int32_t fp) { return static_cast<int>((fp + HALF) >> FRAC_BITS); }
|
|
|
|
|
|
|
|
|
|
/// Convert a fixed-point value to float (mainly useful for debug logging).
|
|
|
|
|
constexpr float toFloat(int32_t fp) { return fp / static_cast<float>(1 << FRAC_BITS); }
|
|
|
|
|
} // namespace fp4
|
|
|
|
|
|
2026-04-14 14:35:50 -05:00
|
|
|
/// Helpers for positioning Unicode combining marks (U+0300 ff.) over a
|
|
|
|
|
/// preceding base glyph without GPOS anchor tables.
|
|
|
|
|
namespace combiningMark {
|
|
|
|
|
|
|
|
|
|
constexpr int MIN_GAP_PX = 1;
|
|
|
|
|
|
|
|
|
|
/// Compute the cursor-X at which to render a combining mark so its bitmap
|
|
|
|
|
/// is visually centered over the base glyph's bitmap.
|
|
|
|
|
constexpr int centerOver(int baseCursorPos, int baseLeft, int baseWidth, int markLeft, int markWidth) {
|
|
|
|
|
return baseCursorPos + baseLeft + baseWidth / 2 - markWidth / 2 - markLeft;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Rotated-90CW variant of centerOver. In the rotated coordinate system
|
|
|
|
|
/// renderCharImpl uses (cursorY - left) instead of (cursorX + left), so
|
|
|
|
|
/// every left/width term inverts sign.
|
|
|
|
|
constexpr int centerOverRotated90CW(int baseCursorPos, int baseLeft, int baseWidth, int markLeft, int markWidth) {
|
|
|
|
|
return baseCursorPos - baseLeft - baseWidth / 2 + markWidth / 2 + markLeft;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// For combining marks that sit entirely above the baseline, compute how many
|
|
|
|
|
/// pixels to raise the mark so there is at least MIN_GAP_PX between its bottom
|
|
|
|
|
/// edge and the top of the base glyph. Returns 0 for marks that extend to or
|
|
|
|
|
/// below the baseline (e.g. cedilla, dot-below, ogonek).
|
|
|
|
|
constexpr int raiseAboveBase(int markTop, int markHeight, int baseTop) {
|
|
|
|
|
if (markTop - markHeight <= 0) return 0;
|
|
|
|
|
const int gap = markTop - markHeight - baseTop;
|
|
|
|
|
return (gap < MIN_GAP_PX) ? (MIN_GAP_PX - gap) : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace combiningMark
|
|
|
|
|
|
2026-03-01 10:43:37 -06:00
|
|
|
/// Fixed-point conventions used by EpdGlyph and EpdFontData:
|
|
|
|
|
/// advanceX: 12.4 unsigned fixed-point in uint16_t (use fp4::toPixel)
|
|
|
|
|
/// kernMatrix: 4.4 signed fixed-point in int8_t (use fp4::toPixel)
|
|
|
|
|
/// Both share 4 fractional bits so they combine directly in an accumulator.
|
|
|
|
|
|
2025-12-03 22:00:29 +11:00
|
|
|
/// Font data stored PER GLYPH
|
|
|
|
|
typedef struct {
|
2025-12-07 01:26:49 +11:00
|
|
|
uint8_t width; ///< Bitmap dimensions in pixels
|
|
|
|
|
uint8_t height; ///< Bitmap dimensions in pixels
|
2026-03-01 10:43:37 -06:00
|
|
|
uint16_t advanceX; ///< Distance to advance cursor (x axis), 12.4 fixed-point in pixels
|
2025-12-07 01:26:49 +11:00
|
|
|
int16_t left; ///< X dist from cursor pos to UL corner
|
|
|
|
|
int16_t top; ///< Y dist from cursor pos to UL corner
|
|
|
|
|
uint16_t dataLength; ///< Size of the font data.
|
2026-02-19 20:30:15 +11:00
|
|
|
uint32_t dataOffset; ///< Pointer into EpdFont->bitmap (or within-group offset for compressed fonts)
|
2025-12-03 22:00:29 +11:00
|
|
|
} EpdGlyph;
|
|
|
|
|
|
2026-02-19 20:30:15 +11:00
|
|
|
/// Compressed font group: a DEFLATE-compressed block of glyph bitmaps
|
|
|
|
|
typedef struct {
|
|
|
|
|
uint32_t compressedOffset; ///< Byte offset into compressed data array
|
|
|
|
|
uint32_t compressedSize; ///< Compressed DEFLATE stream size
|
|
|
|
|
uint32_t uncompressedSize; ///< Decompressed size
|
|
|
|
|
uint16_t glyphCount; ///< Number of glyphs in this group
|
2026-03-12 07:05:46 +11:00
|
|
|
uint32_t firstGlyphIndex; ///< First glyph index in the global glyph array
|
2026-02-19 20:30:15 +11:00
|
|
|
} EpdFontGroup;
|
|
|
|
|
|
2025-12-03 22:00:29 +11:00
|
|
|
/// Glyph interval structure
|
|
|
|
|
typedef struct {
|
|
|
|
|
uint32_t first; ///< The first unicode code point of the interval
|
|
|
|
|
uint32_t last; ///< The last unicode code point of the interval
|
|
|
|
|
uint32_t offset; ///< Index of the first code point into the glyph array
|
|
|
|
|
} EpdUnicodeInterval;
|
|
|
|
|
|
2026-02-24 02:31:43 -06:00
|
|
|
/// Maps a codepoint to a kerning class ID, sorted by codepoint for binary search.
|
|
|
|
|
/// Class IDs are 1-based; codepoints not in the table have implicit class 0 (no kerning).
|
|
|
|
|
typedef struct {
|
|
|
|
|
uint16_t codepoint; ///< Unicode codepoint
|
|
|
|
|
uint8_t classId; ///< 1-based kerning class ID
|
|
|
|
|
} __attribute__((packed)) EpdKernClassEntry;
|
|
|
|
|
|
|
|
|
|
/// Ligature substitution for a specific glyph pair, sorted by `pair` for binary search.
|
|
|
|
|
/// `pair` encodes (leftCodepoint << 16 | rightCodepoint) for single-key lookup.
|
|
|
|
|
typedef struct {
|
|
|
|
|
uint32_t pair; ///< Packed codepoint pair (left << 16 | right)
|
|
|
|
|
uint32_t ligatureCp; ///< Codepoint of the replacement ligature glyph
|
|
|
|
|
} __attribute__((packed)) EpdLigaturePair;
|
|
|
|
|
|
2025-12-03 22:00:29 +11:00
|
|
|
/// Data stored for FONT AS A WHOLE
|
|
|
|
|
typedef struct {
|
|
|
|
|
const uint8_t* bitmap; ///< Glyph bitmaps, concatenated
|
|
|
|
|
const EpdGlyph* glyph; ///< Glyph array
|
|
|
|
|
const EpdUnicodeInterval* intervals; ///< Valid unicode intervals for this font
|
|
|
|
|
uint32_t intervalCount; ///< Number of unicode intervals.
|
|
|
|
|
uint8_t advanceY; ///< Newline distance (y axis)
|
|
|
|
|
int ascender; ///< Maximal height of a glyph above the base line
|
|
|
|
|
int descender; ///< Maximal height of a glyph below the base line
|
2025-12-08 19:48:49 +11:00
|
|
|
bool is2Bit;
|
2026-02-24 02:31:43 -06:00
|
|
|
const EpdFontGroup* groups; ///< NULL for uncompressed fonts
|
|
|
|
|
uint16_t groupCount; ///< 0 for uncompressed fonts
|
2026-03-12 07:05:46 +11:00
|
|
|
const uint16_t* glyphToGroup; ///< Per-glyph group ID (nullptr for contiguous-group fonts)
|
2026-02-24 02:31:43 -06:00
|
|
|
const EpdKernClassEntry* kernLeftClasses; ///< Sorted left-side class map (nullptr if none)
|
|
|
|
|
const EpdKernClassEntry* kernRightClasses; ///< Sorted right-side class map (nullptr if none)
|
2026-03-01 10:43:37 -06:00
|
|
|
const int8_t* kernMatrix; ///< Flat leftClassCount x rightClassCount matrix, 4.4 fixed-point in pixels
|
|
|
|
|
uint16_t kernLeftEntryCount; ///< Entries in kernLeftClasses
|
|
|
|
|
uint16_t kernRightEntryCount; ///< Entries in kernRightClasses
|
|
|
|
|
uint8_t kernLeftClassCount; ///< Number of distinct left classes (matrix rows)
|
|
|
|
|
uint8_t kernRightClassCount; ///< Number of distinct right classes (matrix cols)
|
|
|
|
|
const EpdLigaturePair* ligaturePairs; ///< Sorted ligature pair table (nullptr if none)
|
|
|
|
|
uint32_t ligaturePairCount; ///< Number of entries in ligaturePairs
|
2025-12-03 22:00:29 +11:00
|
|
|
} EpdFontData;
|