diff --git a/lib/Epub/Epub/ParsedText.cpp b/lib/Epub/Epub/ParsedText.cpp index 3320da07..8edb8ddd 100644 --- a/lib/Epub/Epub/ParsedText.cpp +++ b/lib/Epub/Epub/ParsedText.cpp @@ -36,6 +36,7 @@ void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fo const int spaceWidth = renderer.getSpaceWidth(fontId); // Maintain classic prose indenting when extra paragraph spacing is disabled. const bool allowIndent = !extraParagraphSpacing && (style == TextBlock::JUSTIFIED || style == TextBlock::LEFT_ALIGN); + const bool allowHyphenation = hyphenationEnabled; const int indentWidth = allowIndent ? renderer.getTextWidth(fontId, "m", REGULAR) : 0; const int firstLinePageWidth = allowIndent ? std::max(pageWidth - indentWidth, 0) : pageWidth; auto pageWidthForLine = [&](const bool isFirstLine) -> int { return isFirstLine ? firstLinePageWidth : pageWidth; }; @@ -153,7 +154,7 @@ void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fo continue; } - if (lineWordCount > 0 && availableWidth > 0) { + if (allowHyphenation && lineWordCount > 0 && availableWidth > 0) { // Try hyphenating the next word so the current line stays compact. HyphenationResult split; if (Hyphenator::splitWord(renderer, fontId, *wordIt, *styleIt, availableWidth, &split, false)) { diff --git a/lib/Epub/Epub/ParsedText.h b/lib/Epub/Epub/ParsedText.h index 0bd25442..e7f57060 100644 --- a/lib/Epub/Epub/ParsedText.h +++ b/lib/Epub/Epub/ParsedText.h @@ -17,10 +17,12 @@ class ParsedText { std::list wordStyles; TextBlock::BLOCK_STYLE style; bool extraParagraphSpacing; + bool hyphenationEnabled; public: - explicit ParsedText(const TextBlock::BLOCK_STYLE style, const bool extraParagraphSpacing) - : style(style), extraParagraphSpacing(extraParagraphSpacing) {} + explicit ParsedText(const TextBlock::BLOCK_STYLE style, const bool extraParagraphSpacing, + const bool hyphenationEnabled) + : style(style), extraParagraphSpacing(extraParagraphSpacing), hyphenationEnabled(hyphenationEnabled) {} ~ParsedText() = default; void addWord(std::string word, EpdFontStyle fontStyle); diff --git a/lib/Epub/Epub/Section.cpp b/lib/Epub/Epub/Section.cpp index 7c9d241e..44ef8bd5 100644 --- a/lib/Epub/Epub/Section.cpp +++ b/lib/Epub/Epub/Section.cpp @@ -10,7 +10,7 @@ #include "parsers/ChapterHtmlSlimParser.h" namespace { -constexpr uint8_t SECTION_FILE_VERSION = 5; +constexpr uint8_t SECTION_FILE_VERSION = 6; } void Section::onPageComplete(std::unique_ptr page) { @@ -27,7 +27,7 @@ void Section::onPageComplete(std::unique_ptr page) { void Section::writeCacheMetadata(const int fontId, const float lineCompression, const int marginTop, const int marginRight, const int marginBottom, const int marginLeft, - const bool extraParagraphSpacing) const { + const bool extraParagraphSpacing, const bool hyphenationEnabled) const { std::ofstream outputFile(("/sd" + cachePath + "/section.bin").c_str()); serialization::writePod(outputFile, SECTION_FILE_VERSION); serialization::writePod(outputFile, fontId); @@ -37,13 +37,14 @@ void Section::writeCacheMetadata(const int fontId, const float lineCompression, serialization::writePod(outputFile, marginBottom); serialization::writePod(outputFile, marginLeft); serialization::writePod(outputFile, extraParagraphSpacing); + serialization::writePod(outputFile, hyphenationEnabled); serialization::writePod(outputFile, pageCount); outputFile.close(); } bool Section::loadCacheMetadata(const int fontId, const float lineCompression, const int marginTop, const int marginRight, const int marginBottom, const int marginLeft, - const bool extraParagraphSpacing) { + const bool extraParagraphSpacing, const bool hyphenationEnabled) { if (!SD.exists(cachePath.c_str())) { return false; } @@ -69,6 +70,7 @@ bool Section::loadCacheMetadata(const int fontId, const float lineCompression, c int fileFontId, fileMarginTop, fileMarginRight, fileMarginBottom, fileMarginLeft; float fileLineCompression; bool fileExtraParagraphSpacing; + bool fileHyphenationEnabled; serialization::readPod(inputFile, fileFontId); serialization::readPod(inputFile, fileLineCompression); serialization::readPod(inputFile, fileMarginTop); @@ -76,10 +78,11 @@ bool Section::loadCacheMetadata(const int fontId, const float lineCompression, c serialization::readPod(inputFile, fileMarginBottom); serialization::readPod(inputFile, fileMarginLeft); serialization::readPod(inputFile, fileExtraParagraphSpacing); + serialization::readPod(inputFile, fileHyphenationEnabled); if (fontId != fileFontId || lineCompression != fileLineCompression || marginTop != fileMarginTop || marginRight != fileMarginRight || marginBottom != fileMarginBottom || marginLeft != fileMarginLeft || - extraParagraphSpacing != fileExtraParagraphSpacing) { + extraParagraphSpacing != fileExtraParagraphSpacing || hyphenationEnabled != fileHyphenationEnabled) { inputFile.close(); Serial.printf("[%lu] [SCT] Deserialization failed: Parameters do not match\n", millis()); clearCache(); @@ -116,7 +119,7 @@ bool Section::clearCache() const { bool Section::persistPageDataToSD(const int fontId, const float lineCompression, const int marginTop, const int marginRight, const int marginBottom, const int marginLeft, - const bool extraParagraphSpacing) { + const bool extraParagraphSpacing, const bool hyphenationEnabled) { const auto localPath = epub->getSpineItem(spineIndex); // TODO: Should we get rid of this file all together? @@ -137,7 +140,7 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression, const auto sdTmpHtmlPath = "/sd" + tmpHtmlPath; ChapterHtmlSlimParser visitor(sdTmpHtmlPath.c_str(), renderer, fontId, lineCompression, marginTop, marginRight, - marginBottom, marginLeft, extraParagraphSpacing, + marginBottom, marginLeft, extraParagraphSpacing, hyphenationEnabled, [this](std::unique_ptr page) { this->onPageComplete(std::move(page)); }); success = visitor.parseAndBuildPages(); @@ -147,7 +150,8 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression, return false; } - writeCacheMetadata(fontId, lineCompression, marginTop, marginRight, marginBottom, marginLeft, extraParagraphSpacing); + writeCacheMetadata(fontId, lineCompression, marginTop, marginRight, marginBottom, marginLeft, extraParagraphSpacing, + hyphenationEnabled); return true; } diff --git a/lib/Epub/Epub/Section.h b/lib/Epub/Epub/Section.h index 35a17dfc..759afa78 100644 --- a/lib/Epub/Epub/Section.h +++ b/lib/Epub/Epub/Section.h @@ -13,7 +13,7 @@ class Section { std::string cachePath; void writeCacheMetadata(int fontId, float lineCompression, int marginTop, int marginRight, int marginBottom, - int marginLeft, bool extraParagraphSpacing) const; + int marginLeft, bool extraParagraphSpacing, bool hyphenationEnabled) const; void onPageComplete(std::unique_ptr page); public: @@ -26,10 +26,10 @@ class Section { } ~Section() = default; bool loadCacheMetadata(int fontId, float lineCompression, int marginTop, int marginRight, int marginBottom, - int marginLeft, bool extraParagraphSpacing); + int marginLeft, bool extraParagraphSpacing, bool hyphenationEnabled); void setupCacheDir() const; bool clearCache() const; bool persistPageDataToSD(int fontId, float lineCompression, int marginTop, int marginRight, int marginBottom, - int marginLeft, bool extraParagraphSpacing); + int marginLeft, bool extraParagraphSpacing, bool hyphenationEnabled); std::unique_ptr loadPageFromSD() const; }; diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp index d4edc331..08f3fb61 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp @@ -48,7 +48,7 @@ void ChapterHtmlSlimParser::startNewTextBlock(const TextBlock::BLOCK_STYLE style makePages(); } - currentTextBlock.reset(new ParsedText(style, extraParagraphSpacing)); + currentTextBlock.reset(new ParsedText(style, extraParagraphSpacing, hyphenationEnabled)); } void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* name, const XML_Char** atts) { diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h index f656b4a5..ed8521a9 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h @@ -36,6 +36,7 @@ class ChapterHtmlSlimParser { int marginBottom; int marginLeft; bool extraParagraphSpacing; + bool hyphenationEnabled; void startNewTextBlock(TextBlock::BLOCK_STYLE style); void makePages(); @@ -48,6 +49,7 @@ class ChapterHtmlSlimParser { explicit ChapterHtmlSlimParser(const char* filepath, GfxRenderer& renderer, const int fontId, const float lineCompression, const int marginTop, const int marginRight, const int marginBottom, const int marginLeft, const bool extraParagraphSpacing, + const bool hyphenationEnabled, const std::function)>& completePageFn) : filepath(filepath), renderer(renderer), @@ -58,6 +60,7 @@ class ChapterHtmlSlimParser { marginBottom(marginBottom), marginLeft(marginLeft), extraParagraphSpacing(extraParagraphSpacing), + hyphenationEnabled(hyphenationEnabled), completePageFn(completePageFn) {} ~ChapterHtmlSlimParser() = default; bool parseAndBuildPages(); diff --git a/src/CrossPointSettings.cpp b/src/CrossPointSettings.cpp index 1f8c3bde..1d6f5da7 100644 --- a/src/CrossPointSettings.cpp +++ b/src/CrossPointSettings.cpp @@ -12,7 +12,7 @@ CrossPointSettings CrossPointSettings::instance; namespace { constexpr uint8_t SETTINGS_FILE_VERSION = 1; -constexpr uint8_t SETTINGS_COUNT = 2; +constexpr uint8_t SETTINGS_COUNT = 3; constexpr char SETTINGS_FILE[] = "/sd/.crosspoint/settings.bin"; } // namespace @@ -25,6 +25,7 @@ bool CrossPointSettings::saveToFile() const { serialization::writePod(outputFile, SETTINGS_COUNT); serialization::writePod(outputFile, whiteSleepScreen); serialization::writePod(outputFile, extraParagraphSpacing); + serialization::writePod(outputFile, hyphenationEnabled); outputFile.close(); Serial.printf("[%lu] [CPS] Settings saved to file\n", millis()); @@ -50,15 +51,15 @@ bool CrossPointSettings::loadFromFile() { uint8_t fileSettingsCount = 0; serialization::readPod(inputFile, fileSettingsCount); - // load settings that exist - switch (fileSettingsCount) { - case 1: - serialization::readPod(inputFile, whiteSleepScreen); - break; - case 2: - serialization::readPod(inputFile, whiteSleepScreen); - serialization::readPod(inputFile, extraParagraphSpacing); - break; + // load settings that exist in the file (supports backward compatibility) + if (fileSettingsCount >= 1) { + serialization::readPod(inputFile, whiteSleepScreen); + } + if (fileSettingsCount >= 2) { + serialization::readPod(inputFile, extraParagraphSpacing); + } + if (fileSettingsCount >= 3) { + serialization::readPod(inputFile, hyphenationEnabled); } inputFile.close(); diff --git a/src/CrossPointSettings.h b/src/CrossPointSettings.h index b152eb71..7c8b8d0d 100644 --- a/src/CrossPointSettings.h +++ b/src/CrossPointSettings.h @@ -20,6 +20,7 @@ class CrossPointSettings { // Text rendering settings uint8_t extraParagraphSpacing = 1; + uint8_t hyphenationEnabled = 1; ~CrossPointSettings() = default; diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index f4e45363..65fb2d30 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -207,7 +207,7 @@ void EpubReaderActivity::renderScreen() { Serial.printf("[%lu] [ERS] Loading file: %s, index: %d\n", millis(), filepath.c_str(), currentSpineIndex); section = std::unique_ptr
(new Section(epub, currentSpineIndex, renderer)); if (!section->loadCacheMetadata(READER_FONT_ID, lineCompression, marginTop, marginRight, marginBottom, marginLeft, - SETTINGS.extraParagraphSpacing)) { + SETTINGS.extraParagraphSpacing, SETTINGS.hyphenationEnabled)) { Serial.printf("[%lu] [ERS] Cache not found, building...\n", millis()); { @@ -227,7 +227,7 @@ void EpubReaderActivity::renderScreen() { section->setupCacheDir(); if (!section->persistPageDataToSD(READER_FONT_ID, lineCompression, marginTop, marginRight, marginBottom, - marginLeft, SETTINGS.extraParagraphSpacing)) { + marginLeft, SETTINGS.extraParagraphSpacing, SETTINGS.hyphenationEnabled)) { Serial.printf("[%lu] [ERS] Failed to persist page data to SD\n", millis()); section.reset(); return; diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index 3b287d6d..f0f58e52 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -8,8 +8,9 @@ // Define the static settings list const SettingInfo SettingsActivity::settingsList[settingsCount] = { - {"White Sleep Screen", &CrossPointSettings::whiteSleepScreen}, - {"Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing}}; + {"White Sleep Screen", &CrossPointSettings::whiteSleepScreen}, + {"Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing}, + {"Hyphenation", &CrossPointSettings::hyphenationEnabled}}; void SettingsActivity::taskTrampoline(void* param) { auto* self = static_cast(param); diff --git a/src/activities/settings/SettingsActivity.h b/src/activities/settings/SettingsActivity.h index b7ace224..2464015a 100644 --- a/src/activities/settings/SettingsActivity.h +++ b/src/activities/settings/SettingsActivity.h @@ -25,7 +25,7 @@ class SettingsActivity final : public Activity { const std::function onGoHome; // Static settings list - static constexpr int settingsCount = 2; // Number of settings + static constexpr int settingsCount = 3; // Number of settings static const SettingInfo settingsList[settingsCount]; static void taskTrampoline(void* param);