## Summary **What is the goal of this PR?** Improved typesetting, including [kerning](https://en.wikipedia.org/wiki/Kerning) and [ligatures](https://en.wikipedia.org/wiki/Ligature_(writing)#Latin_alphabet). **What changes are included?** - The script to convert built-in fonts now adds kerning and ligature information to the generated font headers. - Epub page layout calculates proper kerning spaces and makes ligature substitutions according to the selected font.    ## Additional Context - I am not a typography expert. - The implementation has been reworked from the earlier version, so it is no longer necessary to omit Open Dyslexic, and kerning data now covers all fonts, styles, and codepoints for which we include bitmap data. - Claude Opus 4.6 helped with a lot of this. - There's an included test epub document with lots of kerning and ligature examples, shown in the photos. **_After some time to mature, I think this change is in decent shape to merge and get people testing._** After opening this PR I came across #660, which overlaps in adding ligature support. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**YES, Claude Opus 4.6**_ --------- Co-authored-by: Cursor <cursoragent@cursor.com>
51 lines
2.5 KiB
C++
51 lines
2.5 KiB
C++
#pragma once
|
|
|
|
#include <EpdFontFamily.h>
|
|
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "blocks/BlockStyle.h"
|
|
#include "blocks/TextBlock.h"
|
|
|
|
class GfxRenderer;
|
|
|
|
class ParsedText {
|
|
std::vector<std::string> words;
|
|
std::vector<EpdFontFamily::Style> wordStyles;
|
|
std::vector<bool> wordContinues; // true = word attaches to previous (no space before it)
|
|
BlockStyle blockStyle;
|
|
bool extraParagraphSpacing;
|
|
bool hyphenationEnabled;
|
|
|
|
void applyParagraphIndent();
|
|
std::vector<size_t> computeLineBreaks(const GfxRenderer& renderer, int fontId, int pageWidth, int spaceWidth,
|
|
std::vector<uint16_t>& wordWidths, std::vector<bool>& continuesVec);
|
|
std::vector<size_t> computeHyphenatedLineBreaks(const GfxRenderer& renderer, int fontId, int pageWidth,
|
|
int spaceWidth, std::vector<uint16_t>& wordWidths,
|
|
std::vector<bool>& continuesVec);
|
|
bool hyphenateWordAtIndex(size_t wordIndex, int availableWidth, const GfxRenderer& renderer, int fontId,
|
|
std::vector<uint16_t>& wordWidths, bool allowFallbackBreaks);
|
|
void extractLine(size_t breakIndex, int pageWidth, int spaceWidth, const std::vector<uint16_t>& wordWidths,
|
|
const std::vector<bool>& continuesVec, const std::vector<size_t>& lineBreakIndices,
|
|
const std::function<void(std::shared_ptr<TextBlock>)>& processLine, const GfxRenderer& renderer,
|
|
int fontId);
|
|
std::vector<uint16_t> calculateWordWidths(const GfxRenderer& renderer, int fontId);
|
|
|
|
public:
|
|
explicit ParsedText(const bool extraParagraphSpacing, const bool hyphenationEnabled = false,
|
|
const BlockStyle& blockStyle = BlockStyle())
|
|
: blockStyle(blockStyle), extraParagraphSpacing(extraParagraphSpacing), hyphenationEnabled(hyphenationEnabled) {}
|
|
~ParsedText() = default;
|
|
|
|
void addWord(std::string word, EpdFontFamily::Style fontStyle, bool underline = false, bool attachToPrevious = false);
|
|
void setBlockStyle(const BlockStyle& blockStyle) { this->blockStyle = blockStyle; }
|
|
BlockStyle& getBlockStyle() { return blockStyle; }
|
|
size_t size() const { return words.size(); }
|
|
bool isEmpty() const { return words.empty(); }
|
|
void layoutAndExtractLines(const GfxRenderer& renderer, int fontId, uint16_t viewportWidth,
|
|
const std::function<void(std::shared_ptr<TextBlock>)>& processLine,
|
|
bool includeLastLine = true);
|
|
}; |