Merge pull request #147 from jpirnay/feat-fonts-sd
feat: Add sd fonts (integrate and improve upstream #1327 by adriancaruana)
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "CrossPointState.h"
|
||||
#include "OpdsServerStore.h"
|
||||
#include "SdCardFontGlobals.h"
|
||||
#include "boot_sleep/BootActivity.h"
|
||||
#include "boot_sleep/SleepActivity.h"
|
||||
#include "browser/OpdsBookBrowserActivity.h"
|
||||
@@ -282,6 +283,8 @@ void ActivityManager::goToBrowser() {
|
||||
}
|
||||
|
||||
void ActivityManager::goToReader(std::string path) {
|
||||
RenderLock lock;
|
||||
ensureSdFontLoaded();
|
||||
replaceActivity(std::make_unique<ReaderActivity>(renderer, mappedInput, std::move(path)));
|
||||
}
|
||||
|
||||
@@ -301,6 +304,8 @@ void ActivityManager::goToKOReaderSync() {
|
||||
void ActivityManager::replaceWithReader(std::string path, ReturnHint hint) {
|
||||
returnHint = std::move(hint);
|
||||
hasReturnHint = true;
|
||||
RenderLock lock;
|
||||
ensureSdFontLoaded();
|
||||
replaceActivity(std::make_unique<ReaderActivity>(renderer, mappedInput, std::move(path)));
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "QrDisplayActivity.h"
|
||||
#include "ReaderUtils.h"
|
||||
#include "RecentBooksStore.h"
|
||||
#include "SdCardFontGlobals.h"
|
||||
#include "StarredPagesActivity.h"
|
||||
#include "components/UITheme.h"
|
||||
#include "fontIds.h"
|
||||
@@ -1072,49 +1073,68 @@ uint8_t EpubReaderActivity::getEffectiveImageRendering() const {
|
||||
return SETTINGS.imageRendering;
|
||||
}
|
||||
|
||||
int EpubReaderActivity::getEffectiveReaderFontId() const {
|
||||
const uint8_t fontFamily =
|
||||
(bookFontFamilyOverride >= 0) ? static_cast<uint8_t>(bookFontFamilyOverride) : SETTINGS.fontFamily;
|
||||
float EpubReaderActivity::getEffectiveReaderLineCompression() const {
|
||||
const uint8_t fontSize = (bookFontSizeOverride >= 0) ? static_cast<uint8_t>(bookFontSizeOverride) : SETTINGS.fontSize;
|
||||
switch (fontFamily) {
|
||||
case CrossPointSettings::NOTOSANS:
|
||||
switch (fontSize) {
|
||||
case CrossPointSettings::SMALL:
|
||||
return NOTOSANS_12_FONT_ID;
|
||||
case CrossPointSettings::MEDIUM:
|
||||
default:
|
||||
return NOTOSANS_14_FONT_ID;
|
||||
case CrossPointSettings::LARGE:
|
||||
return NOTOSANS_16_FONT_ID;
|
||||
case CrossPointSettings::EXTRA_LARGE:
|
||||
return NOTOSANS_18_FONT_ID;
|
||||
}
|
||||
case CrossPointSettings::OPENDYSLEXIC:
|
||||
switch (fontSize) {
|
||||
case CrossPointSettings::SMALL:
|
||||
return OPENDYSLEXIC_8_FONT_ID;
|
||||
case CrossPointSettings::MEDIUM:
|
||||
default:
|
||||
return OPENDYSLEXIC_10_FONT_ID;
|
||||
case CrossPointSettings::LARGE:
|
||||
return OPENDYSLEXIC_12_FONT_ID;
|
||||
case CrossPointSettings::EXTRA_LARGE:
|
||||
return OPENDYSLEXIC_14_FONT_ID;
|
||||
}
|
||||
case CrossPointSettings::BOOKERLY:
|
||||
default:
|
||||
switch (fontSize) {
|
||||
case CrossPointSettings::SMALL:
|
||||
return BOOKERLY_12_FONT_ID;
|
||||
case CrossPointSettings::MEDIUM:
|
||||
default:
|
||||
return BOOKERLY_14_FONT_ID;
|
||||
case CrossPointSettings::LARGE:
|
||||
return BOOKERLY_16_FONT_ID;
|
||||
case CrossPointSettings::EXTRA_LARGE:
|
||||
return BOOKERLY_18_FONT_ID;
|
||||
}
|
||||
const int effectiveFontId = getEffectiveReaderFontId();
|
||||
const int bookerlyId = CrossPointSettings::getBuiltinReaderFontId(CrossPointSettings::BOOKERLY, fontSize);
|
||||
const int notosansId = CrossPointSettings::getBuiltinReaderFontId(CrossPointSettings::NOTOSANS, fontSize);
|
||||
const int opendyslexicId = CrossPointSettings::getBuiltinReaderFontId(CrossPointSettings::OPENDYSLEXIC, fontSize);
|
||||
|
||||
if (effectiveFontId == notosansId) {
|
||||
switch (SETTINGS.lineSpacing) {
|
||||
case CrossPointSettings::TIGHT:
|
||||
return 0.90f;
|
||||
case CrossPointSettings::NORMAL:
|
||||
default:
|
||||
return 0.95f;
|
||||
case CrossPointSettings::WIDE:
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (effectiveFontId == opendyslexicId) {
|
||||
switch (SETTINGS.lineSpacing) {
|
||||
case CrossPointSettings::TIGHT:
|
||||
return 0.90f;
|
||||
case CrossPointSettings::NORMAL:
|
||||
default:
|
||||
return 0.95f;
|
||||
case CrossPointSettings::WIDE:
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
switch (SETTINGS.lineSpacing) {
|
||||
case CrossPointSettings::TIGHT:
|
||||
return 0.95f;
|
||||
case CrossPointSettings::NORMAL:
|
||||
default:
|
||||
return 1.0f;
|
||||
case CrossPointSettings::WIDE:
|
||||
return 1.1f;
|
||||
}
|
||||
}
|
||||
|
||||
int EpubReaderActivity::getEffectiveReaderFontId() const {
|
||||
// Per-book font override: when set, force a specific BUILT-IN family even if
|
||||
// an SD card font is the global default. This makes the override predictable
|
||||
// ("override forces back to a known built-in") and avoids surprising users
|
||||
// who set the override before they had any SD fonts.
|
||||
const uint8_t fontSize = (bookFontSizeOverride >= 0) ? static_cast<uint8_t>(bookFontSizeOverride) : SETTINGS.fontSize;
|
||||
if (bookFontFamilyOverride >= 0) {
|
||||
return CrossPointSettings::getBuiltinReaderFontId(static_cast<uint8_t>(bookFontFamilyOverride), fontSize);
|
||||
}
|
||||
// No override: defer to global resolution (which honors SD card font selection).
|
||||
// We synthesize a temporary lookup using the override fontSize if it's set; otherwise
|
||||
// SETTINGS.getReaderFontId() is the canonical answer.
|
||||
if (bookFontSizeOverride >= 0) {
|
||||
if (SETTINGS.sdFontFamilyName[0] != '\0') {
|
||||
const int id = resolveSdCardFontId(SETTINGS.sdFontFamilyName, fontSize);
|
||||
if (id != 0) return id;
|
||||
}
|
||||
return CrossPointSettings::getBuiltinReaderFontId(SETTINGS.fontFamily, fontSize);
|
||||
}
|
||||
return SETTINGS.getReaderFontId();
|
||||
}
|
||||
|
||||
bool EpubReaderActivity::stepPageState(const bool isForwardTurn) {
|
||||
@@ -1229,7 +1249,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
section = std::make_unique<Section>(epub, currentSpineIndex, renderer);
|
||||
const unsigned long sectionStart = millis();
|
||||
|
||||
if (!section->loadSectionFile(getEffectiveReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
if (!section->loadSectionFile(getEffectiveReaderFontId(), getEffectiveReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, embeddedStyle, imageRendering)) {
|
||||
LOG_DBG("ERS", "Cache not found, building...");
|
||||
@@ -1246,7 +1266,11 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
GUI.fillPopupProgress(renderer, popupRect, progress);
|
||||
};
|
||||
|
||||
if (!section->createSectionFile(getEffectiveReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
// Reset cumulative SD font metadata cache so this section starts fresh.
|
||||
// Pagination will rebuild only the cps it actually encounters, bounded
|
||||
// by MAX_PAGE_GLYPHS per style.
|
||||
renderer.clearSdCardFontAccumulation();
|
||||
if (!section->createSectionFile(getEffectiveReaderFontId(), getEffectiveReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, embeddedStyle, imageRendering,
|
||||
progressFn)) {
|
||||
@@ -1401,14 +1425,16 @@ void EpubReaderActivity::silentIndexNextChapterIfNeeded(const uint16_t viewportW
|
||||
const uint8_t imageRendering = getEffectiveImageRendering();
|
||||
|
||||
Section nextSection(epub, nextSpineIndex, renderer);
|
||||
if (nextSection.loadSectionFile(getEffectiveReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
if (nextSection.loadSectionFile(getEffectiveReaderFontId(), getEffectiveReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, embeddedStyle, imageRendering)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DBG("ERS", "Silently indexing next chapter: %d", nextSpineIndex);
|
||||
if (!nextSection.createSectionFile(getEffectiveReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
// Reset cumulative SD font metadata cache for the new section.
|
||||
renderer.clearSdCardFontAccumulation();
|
||||
if (!nextSection.createSectionFile(getEffectiveReaderFontId(), getEffectiveReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, embeddedStyle, imageRendering)) {
|
||||
LOG_ERR("ERS", "Failed silent indexing for chapter: %d", nextSpineIndex);
|
||||
@@ -1759,14 +1785,44 @@ bool EpubReaderActivity::drawCurrentPageToBuffer(const std::string& filePath, Gf
|
||||
}
|
||||
};
|
||||
|
||||
const int effectiveFontId = getEffectiveFontId(effectiveFontFamily, effectiveFontSize);
|
||||
const auto getEffectiveLineCompression = [&](int fontId) {
|
||||
const int notosansId = CrossPointSettings::getBuiltinReaderFontId(CrossPointSettings::NOTOSANS, effectiveFontSize);
|
||||
const int opendyslexicId =
|
||||
CrossPointSettings::getBuiltinReaderFontId(CrossPointSettings::OPENDYSLEXIC, effectiveFontSize);
|
||||
|
||||
if (fontId == notosansId || fontId == opendyslexicId) {
|
||||
switch (SETTINGS.lineSpacing) {
|
||||
case CrossPointSettings::TIGHT:
|
||||
return 0.90f;
|
||||
case CrossPointSettings::NORMAL:
|
||||
default:
|
||||
return 0.95f;
|
||||
case CrossPointSettings::WIDE:
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
switch (SETTINGS.lineSpacing) {
|
||||
case CrossPointSettings::TIGHT:
|
||||
return 0.95f;
|
||||
case CrossPointSettings::NORMAL:
|
||||
default:
|
||||
return 1.0f;
|
||||
case CrossPointSettings::WIDE:
|
||||
return 1.1f;
|
||||
}
|
||||
};
|
||||
|
||||
const float effectiveLineCompression = getEffectiveLineCompression(effectiveFontId);
|
||||
auto section = std::make_unique<Section>(epub, spineIndex, renderer);
|
||||
if (!section->loadSectionFile(getEffectiveFontId(effectiveFontFamily, effectiveFontSize),
|
||||
SETTINGS.getReaderLineCompression(), SETTINGS.extraParagraphSpacing,
|
||||
SETTINGS.paragraphAlignment, viewportWidth, viewportHeight, SETTINGS.hyphenationEnabled,
|
||||
SETTINGS.embeddedStyle, SETTINGS.imageRendering)) {
|
||||
if (!section->loadSectionFile(getEffectiveFontId(effectiveFontFamily, effectiveFontSize), effectiveLineCompression,
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle,
|
||||
SETTINGS.imageRendering)) {
|
||||
LOG_DBG("SLP", "EPUB: section cache not found for spine %d, rebuilding", spineIndex);
|
||||
if (!section->createSectionFile(getEffectiveFontId(effectiveFontFamily, effectiveFontSize),
|
||||
SETTINGS.getReaderLineCompression(), SETTINGS.extraParagraphSpacing,
|
||||
effectiveLineCompression, SETTINGS.extraParagraphSpacing,
|
||||
SETTINGS.paragraphAlignment, viewportWidth, viewportHeight,
|
||||
SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, SETTINGS.imageRendering)) {
|
||||
LOG_ERR("SLP", "EPUB: failed to rebuild section cache for spine %d", spineIndex);
|
||||
|
||||
@@ -181,6 +181,7 @@ class EpubReaderActivity final : public Activity {
|
||||
bool getEffectiveEmbeddedStyle() const;
|
||||
uint8_t getEffectiveImageRendering() const;
|
||||
int getEffectiveReaderFontId() const;
|
||||
float getEffectiveReaderLineCompression() const;
|
||||
bool stepPageState(bool isForwardTurn);
|
||||
void pageTurn(bool isForwardTurn);
|
||||
void runRenderBenchmark();
|
||||
|
||||
@@ -5,10 +5,31 @@
|
||||
|
||||
#include "KOReaderCredentialStore.h"
|
||||
#include "MappedInputManager.h"
|
||||
#include "SdCardFontGlobals.h"
|
||||
#include "activities/settings/SettingsSubmenuActivity.h"
|
||||
#include "components/UITheme.h"
|
||||
#include "fontIds.h"
|
||||
|
||||
namespace {
|
||||
// Returns the localized name of the family currently used as the global default
|
||||
// for the reader. When the user has selected an SD card font globally, the
|
||||
// override menu's "Default" label should reflect that family by name even
|
||||
// though the per-book override list itself is built-in only.
|
||||
std::string defaultFontFamilyLabel(const SettingInfo& item) {
|
||||
if (SETTINGS.sdFontFamilyName[0] != '\0') {
|
||||
return std::string(SETTINGS.sdFontFamilyName);
|
||||
}
|
||||
// Built-in: enumValues[0] is STR_DEFAULT_VALUE, [1..3] are the three families
|
||||
// in the same order as CrossPointSettings::FONT_FAMILY (BOOKERLY, NOTOSANS,
|
||||
// OPENDYSLEXIC).
|
||||
const auto idx = static_cast<size_t>(SETTINGS.fontFamily + 1);
|
||||
if (idx < item.enumValues.size()) {
|
||||
return I18N.get(item.enumValues[idx]);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
EpubReaderMenuActivity::EpubReaderMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||
const std::string& title, const int currentPage, const int totalPages,
|
||||
const int bookProgressPercent, const uint8_t currentOrientation,
|
||||
@@ -290,9 +311,9 @@ std::string EpubReaderMenuActivity::getItemValueString(int index) const {
|
||||
}
|
||||
}
|
||||
if (item.nameId == StrId::STR_FONT_FAMILY && pendingFontFamilyOverride < 0) {
|
||||
const auto defaultIndex = static_cast<size_t>(SETTINGS.fontFamily + 1);
|
||||
if (defaultIndex < item.enumValues.size()) {
|
||||
return std::string(tr(STR_DEFAULT_VALUE)) + " (" + I18N.get(item.enumValues[defaultIndex]) + ")";
|
||||
const auto label = defaultFontFamilyLabel(item);
|
||||
if (!label.empty()) {
|
||||
return std::string(tr(STR_DEFAULT_VALUE)) + " (" + label + ")";
|
||||
}
|
||||
}
|
||||
if (item.nameId == StrId::STR_FONT_SIZE && pendingFontSizeOverride < 0) {
|
||||
@@ -324,9 +345,9 @@ void EpubReaderMenuActivity::openSubmenu(const SettingInfo& submenuEntry) {
|
||||
}
|
||||
}
|
||||
if (item.nameId == StrId::STR_FONT_FAMILY && pendingFontFamilyOverride < 0) {
|
||||
const auto valueIndex = static_cast<size_t>(SETTINGS.fontFamily + 1);
|
||||
if (valueIndex < item.enumValues.size()) {
|
||||
return std::string(tr(STR_DEFAULT_VALUE)) + " (" + I18N.get(item.enumValues[valueIndex]) + ")";
|
||||
const auto label = defaultFontFamilyLabel(item);
|
||||
if (!label.empty()) {
|
||||
return std::string(tr(STR_DEFAULT_VALUE)) + " (" + label + ")";
|
||||
}
|
||||
}
|
||||
if (item.nameId == StrId::STR_FONT_SIZE && pendingFontSizeOverride < 0) {
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <HalGPIO.h>
|
||||
#include <Logging.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
#include "MappedInputManager.h"
|
||||
#include "SettingActionDispatch.h"
|
||||
@@ -66,14 +68,23 @@ void SettingsActivity::onEnter() {
|
||||
setting.nameId == StrId::STR_TIMEZONE)) {
|
||||
continue;
|
||||
}
|
||||
if (setting.category == StrId::STR_CAT_DISPLAY) {
|
||||
addTo(displaySettings, lastDisplaySub, setting);
|
||||
} else if (setting.category == StrId::STR_CAT_READER) {
|
||||
addTo(readerSettings, lastReaderSub, setting);
|
||||
} else if (setting.category == StrId::STR_CAT_CONTROLS) {
|
||||
addTo(controlsSettings, lastControlsSub, setting);
|
||||
} else if (setting.category == StrId::STR_CAT_SYSTEM) {
|
||||
addTo(systemSettings, lastSystemSub, setting);
|
||||
// Enrich the font-family entry with SD card families discovered at boot.
|
||||
// The list itself is a namespace-static; we only mutate our local copy here.
|
||||
SettingInfo enriched = setting;
|
||||
if (setting.key && std::strcmp(setting.key, "fontFamily") == 0) {
|
||||
const uint8_t n = fontFamilyOptionCount();
|
||||
enriched.enumLabels.clear();
|
||||
enriched.enumLabels.reserve(n);
|
||||
for (uint8_t i = 0; i < n; i++) enriched.enumLabels.push_back(fontFamilyOptionLabel(i));
|
||||
}
|
||||
if (enriched.category == StrId::STR_CAT_DISPLAY) {
|
||||
addTo(displaySettings, lastDisplaySub, enriched);
|
||||
} else if (enriched.category == StrId::STR_CAT_READER) {
|
||||
addTo(readerSettings, lastReaderSub, enriched);
|
||||
} else if (enriched.category == StrId::STR_CAT_CONTROLS) {
|
||||
addTo(controlsSettings, lastControlsSub, enriched);
|
||||
} else if (enriched.category == StrId::STR_CAT_SYSTEM) {
|
||||
addTo(systemSettings, lastSystemSub, enriched);
|
||||
}
|
||||
// Web-only categories (KOReader Sync, OPDS Browser) are skipped for device UI
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user