mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-05 23:27:38 +03:00
Refactor hyphenation logic and update settings for hyphenation toggle
This commit is contained in:
parent
3059cdbc11
commit
be233917ec
@ -52,90 +52,6 @@ bool endsWithExplicitHyphen(const std::string& word, const size_t offset) {
|
|||||||
return isExplicitHyphen(cp);
|
return isExplicitHyphen(cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool chooseSplitForWidth(const GfxRenderer& renderer, const int fontId, const std::string& word,
|
|
||||||
const EpdFontStyle style, const int availableWidth, const bool includeFallback,
|
|
||||||
HyphenSplitDecision* decision) {
|
|
||||||
if (!decision || availableWidth <= 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int hyphenWidth = renderer.getTextWidth(fontId, "-", style);
|
|
||||||
|
|
||||||
auto offsets = Hyphenator::breakOffsets(word, includeFallback);
|
|
||||||
if (offsets.empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t chosenOffset = std::numeric_limits<size_t>::max();
|
|
||||||
uint16_t chosenWidth = 0;
|
|
||||||
bool chosenAppendHyphen = true;
|
|
||||||
|
|
||||||
for (const size_t offset : offsets) {
|
|
||||||
const bool needsInsertedHyphen = !endsWithExplicitHyphen(word, offset);
|
|
||||||
const int budget = availableWidth - (needsInsertedHyphen ? hyphenWidth : 0);
|
|
||||||
if (budget <= 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const std::string prefix = word.substr(0, offset);
|
|
||||||
const int prefixWidth = renderer.getTextWidth(fontId, prefix.c_str(), style);
|
|
||||||
if (prefixWidth <= budget) {
|
|
||||||
chosenOffset = offset;
|
|
||||||
chosenWidth = static_cast<uint16_t>(prefixWidth + (needsInsertedHyphen ? hyphenWidth : 0));
|
|
||||||
chosenAppendHyphen = needsInsertedHyphen;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chosenOffset == std::numeric_limits<size_t>::max()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
decision->byteOffset = chosenOffset;
|
|
||||||
decision->prefixWidth = chosenWidth;
|
|
||||||
decision->appendHyphen = chosenAppendHyphen;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct HyphenSplitDecision {
|
|
||||||
size_t byteOffset;
|
|
||||||
uint16_t prefixWidth;
|
|
||||||
bool appendHyphen; // true when we must draw an extra hyphen after the prefix glyphs
|
|
||||||
};
|
|
||||||
|
|
||||||
// Verifies whether the substring ending at `offset` already contains a literal hyphen glyph, so we can avoid
|
|
||||||
// drawing a duplicate hyphen when breaking the word.
|
|
||||||
bool endsWithExplicitHyphen(const std::string& word, const size_t offset) {
|
|
||||||
if (offset == 0 || offset > word.size()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned char* base = reinterpret_cast<const unsigned char*>(word.data());
|
|
||||||
const unsigned char* ptr = base;
|
|
||||||
const unsigned char* target = base + offset;
|
|
||||||
const unsigned char* lastStart = nullptr;
|
|
||||||
|
|
||||||
while (ptr < target) {
|
|
||||||
lastStart = ptr;
|
|
||||||
utf8NextCodepoint(&ptr);
|
|
||||||
if (ptr > target) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lastStart || ptr != target) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned char* tmp = lastStart;
|
|
||||||
const uint32_t cp = utf8NextCodepoint(&tmp); // decode the codepoint immediately prior to the break
|
|
||||||
return isExplicitHyphen(cp);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool chooseSplitForWidth(const GfxRenderer& renderer, const int fontId, const std::string& word,
|
bool chooseSplitForWidth(const GfxRenderer& renderer, const int fontId, const std::string& word,
|
||||||
const EpdFontFamily::Style style, const int availableWidth, const bool includeFallback,
|
const EpdFontFamily::Style style, const int availableWidth, const bool includeFallback,
|
||||||
HyphenSplitDecision* decision) {
|
HyphenSplitDecision* decision) {
|
||||||
@ -373,7 +289,7 @@ std::vector<size_t> ParsedText::computeLineBreaks(const GfxRenderer& renderer, c
|
|||||||
prefix += "-";
|
prefix += "-";
|
||||||
}
|
}
|
||||||
|
|
||||||
const EpdFontStyle styleForSplit = *styleNodeIt;
|
const EpdFontFamily::Style styleForSplit = *styleNodeIt;
|
||||||
*wordNodeIt = tail;
|
*wordNodeIt = tail;
|
||||||
words.insert(wordNodeIt, prefix);
|
words.insert(wordNodeIt, prefix);
|
||||||
wordStyles.insert(styleNodeIt, styleForSplit);
|
wordStyles.insert(styleNodeIt, styleForSplit);
|
||||||
|
|||||||
@ -27,8 +27,7 @@ class ParsedText {
|
|||||||
std::vector<uint16_t> calculateWordWidths(const GfxRenderer& renderer, int fontId, int pageWidth);
|
std::vector<uint16_t> calculateWordWidths(const GfxRenderer& renderer, int fontId, int pageWidth);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ParsedText(const TextBlock::Style style, const bool extraParagraphSpacing,
|
explicit ParsedText(const TextBlock::Style style, const bool extraParagraphSpacing, const bool hyphenationEnabled)
|
||||||
const bool hyphenationEnabled)
|
|
||||||
: style(style), extraParagraphSpacing(extraParagraphSpacing), hyphenationEnabled(hyphenationEnabled) {}
|
: style(style), extraParagraphSpacing(extraParagraphSpacing), hyphenationEnabled(hyphenationEnabled) {}
|
||||||
~ParsedText() = default;
|
~ParsedText() = default;
|
||||||
|
|
||||||
|
|||||||
@ -86,7 +86,8 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con
|
|||||||
|
|
||||||
if (fontId != fileFontId || lineCompression != fileLineCompression ||
|
if (fontId != fileFontId || lineCompression != fileLineCompression ||
|
||||||
extraParagraphSpacing != fileExtraParagraphSpacing || paragraphAlignment != fileParagraphAlignment ||
|
extraParagraphSpacing != fileExtraParagraphSpacing || paragraphAlignment != fileParagraphAlignment ||
|
||||||
viewportWidth != fileViewportWidth || viewportHeight != fileViewportHeight || hyphenationEnabled != fileHyphenationEnabled) {
|
viewportWidth != fileViewportWidth || viewportHeight != fileViewportHeight ||
|
||||||
|
hyphenationEnabled != fileHyphenationEnabled) {
|
||||||
file.close();
|
file.close();
|
||||||
Serial.printf("[%lu] [SCT] Deserialization failed: Parameters do not match\n", millis());
|
Serial.printf("[%lu] [SCT] Deserialization failed: Parameters do not match\n", millis());
|
||||||
clearCache();
|
clearCache();
|
||||||
@ -179,8 +180,8 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
|||||||
std::vector<uint32_t> lut = {};
|
std::vector<uint32_t> lut = {};
|
||||||
|
|
||||||
ChapterHtmlSlimParser visitor(
|
ChapterHtmlSlimParser visitor(
|
||||||
tmpHtmlPath, renderer, fontId, lineCompression, extraParagraphSpacing, hyphenationEnabled, paragraphAlignment, viewportWidth,
|
tmpHtmlPath, renderer, fontId, lineCompression, extraParagraphSpacing, hyphenationEnabled, paragraphAlignment,
|
||||||
viewportHeight,
|
viewportWidth, viewportHeight,
|
||||||
[this, &lut](std::unique_ptr<Page> page) { lut.emplace_back(this->onPageComplete(std::move(page))); },
|
[this, &lut](std::unique_ptr<Page> page) { lut.emplace_back(this->onPageComplete(std::move(page))); },
|
||||||
progressFn);
|
progressFn);
|
||||||
success = visitor.parseAndBuildPages();
|
success = visitor.parseAndBuildPages();
|
||||||
|
|||||||
@ -34,6 +34,6 @@ class Section {
|
|||||||
bool createSectionFile(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
bool createSectionFile(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
||||||
uint16_t viewportWidth, uint16_t viewportHeight,
|
uint16_t viewportWidth, uint16_t viewportHeight,
|
||||||
const std::function<void()>& progressSetupFn = nullptr,
|
const std::function<void()>& progressSetupFn = nullptr,
|
||||||
const std::function<void(int)>& progressFn = nullptr, bool hyphenationEnabled);
|
const std::function<void(int)>& progressFn = nullptr, bool hyphenationEnabled = false);
|
||||||
std::unique_ptr<Page> loadPageFromSectionFile();
|
std::unique_ptr<Page> loadPageFromSectionFile();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -49,8 +49,7 @@ class ChapterHtmlSlimParser {
|
|||||||
explicit ChapterHtmlSlimParser(const std::string& filepath, GfxRenderer& renderer, const int fontId,
|
explicit ChapterHtmlSlimParser(const std::string& filepath, GfxRenderer& renderer, const int fontId,
|
||||||
const float lineCompression, const bool extraParagraphSpacing,
|
const float lineCompression, const bool extraParagraphSpacing,
|
||||||
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
||||||
const uint16_t viewportHeight,
|
const uint16_t viewportHeight, const bool hyphenationEnabled,
|
||||||
const bool hyphenationEnabled,
|
|
||||||
const std::function<void(std::unique_ptr<Page>)>& completePageFn,
|
const std::function<void(std::unique_ptr<Page>)>& completePageFn,
|
||||||
const std::function<void(int)>& progressFn = nullptr)
|
const std::function<void(int)>& progressFn = nullptr)
|
||||||
: filepath(filepath),
|
: filepath(filepath),
|
||||||
|
|||||||
@ -38,7 +38,7 @@ const SettingInfo settingsList[settingsCount] = {
|
|||||||
SettingType::ENUM,
|
SettingType::ENUM,
|
||||||
&CrossPointSettings::paragraphAlignment,
|
&CrossPointSettings::paragraphAlignment,
|
||||||
{"Justify", "Left", "Center", "Right"}},
|
{"Justify", "Left", "Center", "Right"}},
|
||||||
{"Hyphenation", SettingType::TOGGLE, &CrossPointSettings::hyphenationEnabled, {}}},
|
{"Hyphenation", SettingType::TOGGLE, &CrossPointSettings::hyphenationEnabled, {}},
|
||||||
{"Time to Sleep",
|
{"Time to Sleep",
|
||||||
SettingType::ENUM,
|
SettingType::ENUM,
|
||||||
&CrossPointSettings::sleepTimeout,
|
&CrossPointSettings::sleepTimeout,
|
||||||
@ -47,7 +47,7 @@ const SettingInfo settingsList[settingsCount] = {
|
|||||||
SettingType::ENUM,
|
SettingType::ENUM,
|
||||||
&CrossPointSettings::refreshFrequency,
|
&CrossPointSettings::refreshFrequency,
|
||||||
{"1 page", "5 pages", "10 pages", "15 pages", "30 pages"}},
|
{"1 page", "5 pages", "10 pages", "15 pages", "30 pages"}},
|
||||||
{"Check for updates", SettingType::ACTION, nullptr, {}};
|
{"Check for updates", SettingType::ACTION, nullptr, {}}};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void SettingsActivity::taskTrampoline(void* param) {
|
void SettingsActivity::taskTrampoline(void* param) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user