Recover parts of the regression fiasco

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
jpirnay
2026-05-02 18:19:23 +02:00
co-authored by Copilot
parent a5469c0bb9
commit 06dfc6c50b
21 changed files with 354 additions and 303 deletions
+12 -20
View File
@@ -1,5 +1,9 @@
#pragma once
#include <builtinFonts/bookerly_10_bold.h>
#include <builtinFonts/bookerly_10_bolditalic.h>
#include <builtinFonts/bookerly_10_italic.h>
#include <builtinFonts/bookerly_10_regular.h>
#include <builtinFonts/bookerly_12_bold.h>
#include <builtinFonts/bookerly_12_bolditalic.h>
#include <builtinFonts/bookerly_12_italic.h>
@@ -16,6 +20,14 @@
#include <builtinFonts/bookerly_18_bolditalic.h>
#include <builtinFonts/bookerly_18_italic.h>
#include <builtinFonts/bookerly_18_regular.h>
#include <builtinFonts/inter_ui_10_bold.h>
#include <builtinFonts/inter_ui_10_regular.h>
#include <builtinFonts/inter_ui_12_bold.h>
#include <builtinFonts/inter_ui_12_regular.h>
#include <builtinFonts/notosans_10_bold.h>
#include <builtinFonts/notosans_10_bolditalic.h>
#include <builtinFonts/notosans_10_italic.h>
#include <builtinFonts/notosans_10_regular.h>
#include <builtinFonts/notosans_8_regular.h>
#include <builtinFonts/notosans_12_bold.h>
#include <builtinFonts/notosans_12_bolditalic.h>
@@ -33,23 +45,3 @@
#include <builtinFonts/notosans_18_bolditalic.h>
#include <builtinFonts/notosans_18_italic.h>
#include <builtinFonts/notosans_18_regular.h>
#include <builtinFonts/opendyslexic_10_bold.h>
#include <builtinFonts/opendyslexic_10_bolditalic.h>
#include <builtinFonts/opendyslexic_10_italic.h>
#include <builtinFonts/opendyslexic_10_regular.h>
#include <builtinFonts/opendyslexic_12_bold.h>
#include <builtinFonts/opendyslexic_12_bolditalic.h>
#include <builtinFonts/opendyslexic_12_italic.h>
#include <builtinFonts/opendyslexic_12_regular.h>
#include <builtinFonts/opendyslexic_14_bold.h>
#include <builtinFonts/opendyslexic_14_bolditalic.h>
#include <builtinFonts/opendyslexic_14_italic.h>
#include <builtinFonts/opendyslexic_14_regular.h>
#include <builtinFonts/opendyslexic_8_bold.h>
#include <builtinFonts/opendyslexic_8_bolditalic.h>
#include <builtinFonts/opendyslexic_8_italic.h>
#include <builtinFonts/opendyslexic_8_regular.h>
#include <builtinFonts/ubuntu_10_bold.h>
#include <builtinFonts/ubuntu_10_regular.h>
#include <builtinFonts/ubuntu_12_bold.h>
#include <builtinFonts/ubuntu_12_regular.h>
+18 -36
View File
@@ -8,6 +8,15 @@ echo "// The contents of this file are generated by ./lib/EpdFont/scripts/build-
echo "#pragma once"
echo ""
echo "#define BOOKERLY_10_FONT_ID ($(
ruby -rdigest -e 'puts [
"./bookerly_10_regular.h",
"./bookerly_10_bold.h",
"./bookerly_10_bolditalic.h",
"./bookerly_10_italic.h",
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
))"
echo "#define BOOKERLY_12_FONT_ID ($(
ruby -rdigest -e 'puts [
"./bookerly_12_regular.h",
@@ -80,53 +89,26 @@ ruby -rdigest -e 'puts [
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
))"
echo "#define OPENDYSLEXIC_8_FONT_ID ($(
echo "#define NOTOSANS_10_FONT_ID ($(
ruby -rdigest -e 'puts [
"./opendyslexic_8_regular.h",
"./opendyslexic_8_bold.h",
"./opendyslexic_8_bolditalic.h",
"./opendyslexic_8_italic.h",
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
))"
echo "#define OPENDYSLEXIC_10_FONT_ID ($(
ruby -rdigest -e 'puts [
"./opendyslexic_10_regular.h",
"./opendyslexic_10_bold.h",
"./opendyslexic_10_bolditalic.h",
"./opendyslexic_10_italic.h",
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
))"
echo "#define OPENDYSLEXIC_12_FONT_ID ($(
ruby -rdigest -e 'puts [
"./opendyslexic_12_regular.h",
"./opendyslexic_12_bold.h",
"./opendyslexic_12_bolditalic.h",
"./opendyslexic_12_italic.h",
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
))"
echo "#define OPENDYSLEXIC_14_FONT_ID ($(
ruby -rdigest -e 'puts [
"./opendyslexic_14_regular.h",
"./opendyslexic_14_bold.h",
"./opendyslexic_14_bolditalic.h",
"./opendyslexic_14_italic.h",
"./notosans_10_regular.h",
"./notosans_10_bold.h",
"./notosans_10_bolditalic.h",
"./notosans_10_italic.h",
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
))"
echo "#define UI_10_FONT_ID ($(
ruby -rdigest -e 'puts [
"./ubuntu_10_regular.h",
"./ubuntu_10_bold.h",
"./inter_ui_10_regular.h",
"./inter_ui_10_bold.h",
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
))"
echo "#define UI_12_FONT_ID ($(
ruby -rdigest -e 'puts [
"./ubuntu_12_regular.h",
"./ubuntu_12_bold.h",
"./inter_ui_12_regular.h",
"./inter_ui_12_bold.h",
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
))"
+26 -19
View File
@@ -5,9 +5,8 @@ set -e
cd "$(dirname "$0")"
READER_FONT_STYLES=("Regular" "Italic" "Bold" "BoldItalic")
BOOKERLY_FONT_SIZES=(12 14 16 18)
NOTOSANS_FONT_SIZES=(12 14 16 18)
OPENDYSLEXIC_FONT_SIZES=(8 10 12 14)
BOOKERLY_FONT_SIZES=(10 12 14 16 18)
NOTOSANS_FONT_SIZES=(10 12 14 16 18)
for size in ${BOOKERLY_FONT_SIZES[@]}; do
for style in ${READER_FONT_STYLES[@]}; do
@@ -29,28 +28,36 @@ for size in ${NOTOSANS_FONT_SIZES[@]}; do
done
done
for size in ${OPENDYSLEXIC_FONT_SIZES[@]}; do
for style in ${READER_FONT_STYLES[@]}; do
font_name="opendyslexic_${size}_$(echo $style | tr '[:upper:]' '[:lower:]')"
font_path="../builtinFonts/source/OpenDyslexic/OpenDyslexic-${style}.otf"
output_path="../builtinFonts/${font_name}.h"
python fontconvert.py $font_name $size $font_path --2bit --compress > $output_path
echo "Generated $output_path"
done
done
UI_FONT_SIZES=(10 12)
UI_FONT_STYLES=("Regular" "Bold")
UI_LANG_INTERVALS=(
"0x0000,0x007F"
"0x0080,0x00FF"
"0x0100,0x017F"
"0x01A0,0x01A1"
"0x01AF,0x01B0"
"0x01C4,0x021F"
"0x0300,0x036F"
"0x0400,0x04FF"
"0x1EA0,0x1EF9"
"0x2010,0x206F"
"0x20A0,0x20CF"
"0xFB00,0xFB06"
"0xFFFD,0xFFFD"
)
for size in ${UI_FONT_SIZES[@]}; do
for style in ${UI_FONT_STYLES[@]}; do
font_name="ubuntu_${size}_$(echo $style | tr '[:upper:]' '[:lower:]')"
ubuntu_path="../builtinFonts/source/Ubuntu/Ubuntu-${style}.ttf"
# NotoSans used as fallback to fill missing glyphs (e.g. Vietnamese U+1EA0-1EF9)
# that are absent from the Ubuntu TTF source.
noto_path="../builtinFonts/source/NotoSans/NotoSans-${style}.ttf"
font_name="inter_ui_${size}_$(echo $style | tr '[:upper:]' '[:lower:]')"
inter_path="../builtinFonts/source/Inter/Inter-${style}.ttf"
output_path="../builtinFonts/${font_name}.h"
python fontconvert.py $font_name $size $ubuntu_path $noto_path > $output_path
cmd=(python fontconvert.py "$font_name" "$size" "$inter_path")
for interval in "${UI_LANG_INTERVALS[@]}"; do
cmd+=(--additional-intervals "$interval")
done
"${cmd[@]}" > "$output_path"
echo "Generated $output_path"
done
done
@@ -173,6 +173,84 @@ int32_t jpegSeek(JPEGFILE* pFile, int32_t pos) {
constexpr size_t JPEG_DECODER_APPROX_SIZE = 20 * 1024;
constexpr size_t MIN_FREE_HEAP_FOR_JPEG = JPEG_DECODER_APPROX_SIZE + 16 * 1024;
bool readJpegDimensionsFromHeader(const std::string& imagePath, ImageDimensions& out) {
FsFile f;
if (!Storage.openFileForRead("JPG", imagePath, f)) {
LOG_ERR("JPG", "Failed to open file for dimensions: %s", imagePath.c_str());
return false;
}
auto readByte = [&f](uint8_t& b) -> bool { return f.read(&b, 1) == 1; };
auto readU16BE = [&f](uint16_t& v) -> bool {
uint8_t b[2];
if (f.read(b, 2) != 2) return false;
v = static_cast<uint16_t>((static_cast<uint16_t>(b[0]) << 8) | b[1]);
return true;
};
uint8_t b0 = 0;
uint8_t b1 = 0;
if (!readByte(b0) || !readByte(b1) || b0 != 0xFF || b1 != 0xD8) {
f.close();
LOG_ERR("JPG", "Not a JPEG file: %s", imagePath.c_str());
return false;
}
while (f.available()) {
uint8_t prefix = 0;
if (!readByte(prefix)) break;
if (prefix != 0xFF) continue;
uint8_t marker = 0;
do {
if (!readByte(marker)) {
f.close();
return false;
}
} while (marker == 0xFF);
if (marker == 0x00 || marker == 0xD8 || marker == 0xD9 || (marker >= 0xD0 && marker <= 0xD7)) {
continue;
}
uint16_t segLen = 0;
if (!readU16BE(segLen) || segLen < 2) {
f.close();
return false;
}
const bool isSof = (marker >= 0xC0 && marker <= 0xC3) || (marker >= 0xC5 && marker <= 0xC7) ||
(marker >= 0xC9 && marker <= 0xCB) || (marker >= 0xCD && marker <= 0xCF);
if (isSof) {
uint8_t sof[5];
if (segLen < 7 || f.read(sof, sizeof(sof)) != static_cast<int>(sizeof(sof))) {
f.close();
return false;
}
uint16_t height = static_cast<uint16_t>((static_cast<uint16_t>(sof[1]) << 8) | sof[2]);
uint16_t width = static_cast<uint16_t>((static_cast<uint16_t>(sof[3]) << 8) | sof[4]);
f.close();
if (width == 0 || height == 0) {
LOG_ERR("JPG", "Invalid JPEG dimensions %ux%u: %s", width, height, imagePath.c_str());
return false;
}
out.width = static_cast<int16_t>(width);
out.height = static_cast<int16_t>(height);
return true;
}
const int32_t skip = static_cast<int32_t>(segLen) - 2;
if (!f.seek(f.position() + skip)) {
f.close();
return false;
}
}
f.close();
LOG_ERR("JPG", "No SOF marker found for dimensions: %s", imagePath.c_str());
return false;
}
// Choose JPEGDEC's built-in scale factor for coarse downscaling.
// Returns the scale denominator (1, 2, 4, or 8) and sets jpegScaleOption.
int chooseJpegScale(float targetScale, int& jpegScaleOption) {
@@ -401,29 +479,10 @@ int jpegDrawCallback(JPEGDRAW* pDraw) {
} // namespace
bool JpegToFramebufferConverter::getDimensionsStatic(const std::string& imagePath, ImageDimensions& out) {
size_t freeHeap = ESP.getFreeHeap();
if (freeHeap < MIN_FREE_HEAP_FOR_JPEG) {
LOG_ERR("JPG", "Not enough heap for JPEG decoder (%u free, need %u)", freeHeap, MIN_FREE_HEAP_FOR_JPEG);
if (!readJpegDimensionsFromHeader(imagePath, out)) {
return false;
}
std::unique_ptr<JPEGDEC> jpeg(new (std::nothrow) JPEGDEC());
if (!jpeg) {
LOG_ERR("JPG", "Failed to allocate JPEG decoder for dimensions");
return false;
}
int rc = jpeg->open(imagePath.c_str(), jpegOpen, jpegClose, jpegRead, jpegSeek, nullptr);
if (rc != 1) {
LOG_ERR("JPG", "Failed to open JPEG for dimensions (err=%d): %s", jpeg->getLastError(), imagePath.c_str());
return false;
}
out.width = jpeg->getWidth();
out.height = jpeg->getHeight();
LOG_DBG("JPG", "Image dimensions: %dx%d", out.width, out.height);
jpeg->close();
return true;
}
+1 -4
View File
@@ -89,7 +89,6 @@ void FontCacheManager::recordText(const char* text, int fontId, EpdFontFamily::S
FontCacheManager::PrewarmScope::PrewarmScope(FontCacheManager& manager) : manager_(&manager) {
manager_->scanMode_ = ScanMode::Scanning;
manager_->clearCache();
manager_->resetStats();
manager_->scanText_.clear();
manager_->scanText_.reserve(2048); // Pre-allocate to avoid heap fragmentation from repeated concat
@@ -110,15 +109,13 @@ void FontCacheManager::PrewarmScope::endScanAndPrewarm() {
manager_->prewarmCache(manager_->scanFontId_, manager_->scanText_.c_str(), styleMask);
// Free scan string memory
// Keep reserved capacity to avoid repeated alloc/free churn between pages.
manager_->scanText_.clear();
manager_->scanText_.shrink_to_fit();
}
FontCacheManager::PrewarmScope::~PrewarmScope() {
if (active_) {
endScanAndPrewarm(); // no-op if already called (scanText_ is empty)
manager_->clearCache();
}
}
+1
View File
@@ -219,6 +219,7 @@ STR_SMALL: "Small"
STR_MEDIUM: "Medium"
STR_LARGE: "Large"
STR_X_LARGE: "X Large"
STR_TINY: "Tiny"
STR_TIGHT: "Tight"
STR_NORMAL: "Normal"
STR_WIDE: "Wide"