diff --git a/lib/EpdFont/EpdFont.cpp b/lib/EpdFont/EpdFont.cpp index 7dde633f..8550cba4 100644 --- a/lib/EpdFont/EpdFont.cpp +++ b/lib/EpdFont/EpdFont.cpp @@ -22,8 +22,7 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star const EpdGlyph* glyph = getGlyph(cp); if (!glyph) { - // TODO: Replace with fallback glyph property? - glyph = getGlyph('?'); + glyph = getGlyph(REPLACEMENT_GLYPH); } if (!glyph) { diff --git a/lib/EpdFont/builtinFonts/bookerly_12_bold.h b/lib/EpdFont/builtinFonts/bookerly_12_bold.h index 3d38b148..7ba50cc9 100644 --- a/lib/EpdFont/builtinFonts/bookerly_12_bold.h +++ b/lib/EpdFont/builtinFonts/bookerly_12_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_12_boldBitmaps[51217] = { +static const uint8_t bookerly_12_boldBitmaps[51367] = { 0x0A, 0x83, 0xFC, 0x3F, 0x87, 0xF4, 0x7F, 0x43, 0xF4, 0x3F, 0x03, 0xF0, 0x3F, 0x03, 0xF0, 0x3F, 0x03, 0xF0, 0x2F, 0x01, 0xF0, 0x00, 0x00, 0x10, 0x2F, 0xC3, 0xFC, 0x3F, 0xC0, 0x50, 0x7E, 0x1F, 0x7F, 0x8F, 0xDF, 0xD3, 0xF3, 0xF4, 0xFC, 0xFD, 0x3F, 0x2F, 0x0F, 0xCB, 0xC3, 0xF2, 0xE0, 0xF8, @@ -3209,7 +3209,16 @@ static const uint8_t bookerly_12_boldBitmaps[51217] = { 0x2F, 0xFF, 0xFF, 0xFE, 0xBF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF, 0xE0, 0x2F, 0x47, 0xFC, 0x7F, 0xC3, 0xF4, 0x00, 0x00, 0x1F, 0x80, 0x0B, 0xC0, 0x0B, 0xD0, 0xFF, 0x40, 0xBF, 0x80, 0x7F, 0xC3, 0xFD, 0x02, 0xFE, 0x01, 0xFF, 0x0B, 0xE0, 0x07, 0xF0, 0x03, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1F, 0x80, 0x00, + 0x00, 0x00, 0x74, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7D, 0x04, 0x0B, 0x80, 0x00, 0x00, 0x7F, 0xFF, + 0xE0, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFD, 0x2F, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0x87, 0xF8, 0x00, + 0x7F, 0xFF, 0xFF, 0xE1, 0xFF, 0x80, 0x7F, 0xFF, 0xFF, 0x80, 0xBF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, + 0x3F, 0xFE, 0x02, 0xFF, 0xFC, 0x00, 0xBF, 0xFE, 0x00, 0x2F, 0xFF, 0x42, 0xFF, 0xFE, 0x00, 0x02, + 0xFF, 0xE2, 0xFF, 0xFE, 0x00, 0x00, 0x2F, 0xFC, 0xBF, 0xFE, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFE, + 0x00, 0x00, 0x00, 0x2F, 0xD2, 0xFE, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x3E, 0x00, 0x00, 0x00, 0x00, + 0x2D, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_12_boldGlyphs[] = { @@ -3941,6 +3950,7 @@ static const EpdGlyph bookerly_12_boldGlyphs[] = { { 15, 18, 25, 5, 18, 68, 51112 }, // ⊥ { 6, 5, 16, 5, 9, 8, 51180 }, // ⋅ { 23, 5, 25, 1, 9, 29, 51188 }, // ⋯ + { 25, 24, 25, 0, 21, 150, 51217 }, // � }; static const EpdUnicodeInterval bookerly_12_boldIntervals[] = { @@ -4004,13 +4014,14 @@ static const EpdUnicodeInterval bookerly_12_boldIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_12_bold = { bookerly_12_boldBitmaps, bookerly_12_boldGlyphs, bookerly_12_boldIntervals, - 60, + 61, 33, 27, -7, diff --git a/lib/EpdFont/builtinFonts/bookerly_12_bolditalic.h b/lib/EpdFont/builtinFonts/bookerly_12_bolditalic.h index 9fd2471d..e2077955 100644 --- a/lib/EpdFont/builtinFonts/bookerly_12_bolditalic.h +++ b/lib/EpdFont/builtinFonts/bookerly_12_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_12_bolditalicBitmaps[52522] = { +static const uint8_t bookerly_12_bolditalicBitmaps[52672] = { 0x00, 0x68, 0x01, 0xFC, 0x03, 0xF8, 0x07, 0xF4, 0x07, 0xF0, 0x0B, 0xE0, 0x0F, 0xD0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0x80, 0x1F, 0x40, 0x1F, 0x00, 0x2F, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x04, 0x00, 0x7F, 0x00, 0xBF, 0x00, 0xBD, 0x00, 0x10, 0x00, 0x0B, 0x87, 0xC2, 0xF4, 0xFC, 0x3F, 0x2F, 0x83, @@ -3290,7 +3290,16 @@ static const uint8_t bookerly_12_bolditalicBitmaps[52522] = { 0xC0, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x2F, 0xFF, 0xFF, 0xFE, 0xBF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF, 0xE0, 0x2F, 0x47, 0xFC, 0x7F, 0xC3, 0xF4, 0x00, 0x00, 0x1F, 0x80, 0x0B, 0xC0, 0x0B, 0xD0, 0xFF, 0x40, 0xBF, 0x80, 0x7F, 0xC3, 0xFD, 0x02, 0xFE, 0x01, 0xFF, 0x0B, 0xE0, - 0x07, 0xF0, 0x03, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0xF0, 0x03, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7F, + 0xF8, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x74, 0x00, 0x78, 0x00, 0x00, + 0x00, 0x7D, 0x04, 0x0B, 0x80, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFD, + 0x2F, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0x87, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0xE1, 0xFF, 0x80, 0x7F, + 0xFF, 0xFF, 0x80, 0xBF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, 0x3F, 0xFE, 0x02, 0xFF, 0xFC, 0x00, 0xBF, + 0xFE, 0x00, 0x2F, 0xFF, 0x42, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xE2, 0xFF, 0xFE, 0x00, 0x00, 0x2F, + 0xFC, 0xBF, 0xFE, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x2F, 0xD2, 0xFE, 0x00, + 0x00, 0x00, 0x02, 0xF0, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_12_bolditalicGlyphs[] = { @@ -4022,6 +4031,7 @@ static const EpdGlyph bookerly_12_bolditalicGlyphs[] = { { 15, 18, 25, 5, 18, 68, 52417 }, // ⊥ { 6, 5, 16, 5, 9, 8, 52485 }, // ⋅ { 23, 5, 25, 1, 9, 29, 52493 }, // ⋯ + { 25, 24, 25, 0, 21, 150, 52522 }, // � }; static const EpdUnicodeInterval bookerly_12_bolditalicIntervals[] = { @@ -4085,13 +4095,14 @@ static const EpdUnicodeInterval bookerly_12_bolditalicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_12_bolditalic = { bookerly_12_bolditalicBitmaps, bookerly_12_bolditalicGlyphs, bookerly_12_bolditalicIntervals, - 60, + 61, 33, 27, -7, diff --git a/lib/EpdFont/builtinFonts/bookerly_12_italic.h b/lib/EpdFont/builtinFonts/bookerly_12_italic.h index a323a97e..9c965a92 100644 --- a/lib/EpdFont/builtinFonts/bookerly_12_italic.h +++ b/lib/EpdFont/builtinFonts/bookerly_12_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_12_italicBitmaps[48812] = { +static const uint8_t bookerly_12_italicBitmaps[48962] = { 0x00, 0x14, 0x03, 0xD0, 0x1F, 0x00, 0xF8, 0x03, 0xD0, 0x0F, 0x00, 0x7C, 0x02, 0xD0, 0x0B, 0x00, 0x3C, 0x00, 0xE0, 0x03, 0x80, 0x1D, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x01, 0xF8, 0x07, 0xC0, 0x04, 0x00, 0x0A, 0x07, 0x0B, 0x87, 0xC3, 0xD2, 0xE0, 0xF0, 0xB4, 0x38, 0x3C, 0x0D, 0x0E, @@ -3058,7 +3058,17 @@ static const uint8_t bookerly_12_italicBitmaps[48812] = { 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x00, 0x0B, 0x80, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x05, 0x56, 0xE5, 0x54, 0xBF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF, 0xE0, 0x10, 0xBD, 0xFE, 0xBC, 0x04, 0x00, 0x04, 0x00, 0x05, 0x1F, 0xC0, 0x0F, 0xC0, - 0x0B, 0xDB, 0xF0, 0x03, 0xF0, 0x03, 0xF8, 0xF4, 0x00, 0xF8, 0x00, 0x7C, + 0x0B, 0xDB, 0xF0, 0x03, 0xF0, 0x03, 0xF8, 0xF4, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x74, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x7D, 0x04, 0x0B, 0x80, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0xF8, 0x00, 0x00, 0x7F, + 0xFF, 0xFD, 0x2F, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0x87, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0xE1, 0xFF, + 0x80, 0x7F, 0xFF, 0xFF, 0x80, 0xBF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, 0x3F, 0xFE, 0x02, 0xFF, 0xFC, + 0x00, 0xBF, 0xFE, 0x00, 0x2F, 0xFF, 0x42, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xE2, 0xFF, 0xFE, 0x00, + 0x00, 0x2F, 0xFC, 0xBF, 0xFE, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x2F, 0xD2, + 0xFE, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x2E, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, }; static const EpdGlyph bookerly_12_italicGlyphs[] = { @@ -3790,6 +3800,7 @@ static const EpdGlyph bookerly_12_italicGlyphs[] = { { 15, 18, 25, 5, 18, 68, 48719 }, // ⊥ { 4, 4, 16, 6, 9, 4, 48787 }, // ⋅ { 21, 4, 25, 2, 9, 21, 48791 }, // ⋯ + { 25, 24, 25, 0, 21, 150, 48812 }, // � }; static const EpdUnicodeInterval bookerly_12_italicIntervals[] = { @@ -3853,13 +3864,14 @@ static const EpdUnicodeInterval bookerly_12_italicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_12_italic = { bookerly_12_italicBitmaps, bookerly_12_italicGlyphs, bookerly_12_italicIntervals, - 60, + 61, 33, 27, -7, diff --git a/lib/EpdFont/builtinFonts/bookerly_12_regular.h b/lib/EpdFont/builtinFonts/bookerly_12_regular.h index baa107de..822369ee 100644 --- a/lib/EpdFont/builtinFonts/bookerly_12_regular.h +++ b/lib/EpdFont/builtinFonts/bookerly_12_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_12_regularBitmaps[47071] = { +static const uint8_t bookerly_12_regularBitmaps[47221] = { 0x28, 0xBC, 0xFC, 0xF8, 0xF8, 0xF8, 0xF4, 0xF4, 0xF4, 0xF4, 0xB4, 0xB4, 0x74, 0x74, 0x00, 0x00, 0x78, 0xFD, 0xFC, 0x10, 0x28, 0x2E, 0xE1, 0xFB, 0x47, 0xED, 0x1E, 0xB4, 0x7A, 0xD1, 0xEB, 0x03, 0x94, 0x04, 0x00, 0x0E, 0x02, 0xC0, 0x00, 0x0D, 0x03, 0x80, 0x00, 0x1D, 0x03, 0x40, 0x00, 0x2C, @@ -2949,7 +2949,17 @@ static const uint8_t bookerly_12_regularBitmaps[47071] = { 0x00, 0x0B, 0x80, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x00, 0x0B, 0x80, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x05, 0x56, 0xE5, 0x54, 0xBF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF, 0xE0, 0x10, 0xBD, 0xFE, 0xBC, 0x04, 0x00, 0x04, 0x00, 0x05, 0x1F, - 0xC0, 0x0F, 0xC0, 0x0B, 0xDB, 0xF0, 0x03, 0xF0, 0x03, 0xF8, 0xF4, 0x00, 0xF8, 0x00, 0x7C, + 0xC0, 0x0F, 0xC0, 0x0B, 0xDB, 0xF0, 0x03, 0xF0, 0x03, 0xF8, 0xF4, 0x00, 0xF8, 0x00, 0x7C, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1F, 0x80, 0x00, 0x00, 0x00, + 0x74, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7D, 0x04, 0x0B, 0x80, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0xF8, + 0x00, 0x00, 0x7F, 0xFF, 0xFD, 0x2F, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0x87, 0xF8, 0x00, 0x7F, 0xFF, + 0xFF, 0xE1, 0xFF, 0x80, 0x7F, 0xFF, 0xFF, 0x80, 0xBF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, 0x3F, 0xFE, + 0x02, 0xFF, 0xFC, 0x00, 0xBF, 0xFE, 0x00, 0x2F, 0xFF, 0x42, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xE2, + 0xFF, 0xFE, 0x00, 0x00, 0x2F, 0xFC, 0xBF, 0xFE, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFE, 0x00, 0x00, + 0x00, 0x2F, 0xD2, 0xFE, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x2E, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_12_regularGlyphs[] = { @@ -3681,6 +3691,7 @@ static const EpdGlyph bookerly_12_regularGlyphs[] = { { 15, 18, 25, 5, 18, 68, 46978 }, // ⊥ { 4, 4, 16, 6, 9, 4, 47046 }, // ⋅ { 21, 4, 25, 2, 9, 21, 47050 }, // ⋯ + { 25, 24, 25, 0, 21, 150, 47071 }, // � }; static const EpdUnicodeInterval bookerly_12_regularIntervals[] = { @@ -3744,13 +3755,14 @@ static const EpdUnicodeInterval bookerly_12_regularIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_12_regular = { bookerly_12_regularBitmaps, bookerly_12_regularGlyphs, bookerly_12_regularIntervals, - 60, + 61, 33, 27, -7, diff --git a/lib/EpdFont/builtinFonts/bookerly_14_bold.h b/lib/EpdFont/builtinFonts/bookerly_14_bold.h index e6b98785..39de4d1d 100644 --- a/lib/EpdFont/builtinFonts/bookerly_14_bold.h +++ b/lib/EpdFont/builtinFonts/bookerly_14_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_14_boldBitmaps[67020] = { +static const uint8_t bookerly_14_boldBitmaps[67209] = { 0x1A, 0x4B, 0xF8, 0xFF, 0x8F, 0xF4, 0xFF, 0x4F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xBF, 0x0B, 0xF0, 0x7F, 0x07, 0xF0, 0x3F, 0x03, 0xF0, 0x10, 0x00, 0x00, 0x2F, 0x4B, 0xFC, 0xBF, 0xC7, 0xFC, 0x15, 0x00, 0x2F, 0x42, 0xE7, 0xF4, 0xFF, 0xBF, 0x0F, 0xEB, 0xF0, 0xFE, 0xBF, 0x0F, 0xEB, @@ -4196,7 +4196,19 @@ static const uint8_t bookerly_14_boldBitmaps[67020] = { 0xFF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF, 0xFE, 0xBF, 0xFF, 0xFF, 0xFF, 0x80, 0x01, 0x03, 0xFC, 0xBF, 0xEB, 0xFE, 0x3F, 0xC0, 0x00, 0x05, 0x00, 0x00, 0x40, 0x00, 0x04, 0x0F, 0xF0, 0x02, 0xFE, 0x00, 0x3F, 0xDB, 0xFD, 0x00, 0xFF, 0xC0, 0x1F, 0xFA, 0xFF, 0x40, 0x3F, 0xF0, 0x07, 0xFE, 0x7F, - 0xC0, 0x0B, 0xF4, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x0B, 0xF4, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x02, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x5B, 0xE0, 0x00, 0x00, 0x00, 0x02, + 0xC0, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x02, 0xFC, 0x69, 0x02, + 0xE0, 0x00, 0x00, 0x2F, 0xFF, 0xFF, 0x03, 0xE0, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x0F, 0xE0, 0x00, + 0x2F, 0xFF, 0xFF, 0xFC, 0x2F, 0xE0, 0x02, 0xFF, 0xFF, 0xFF, 0xF0, 0xBF, 0xE0, 0x2F, 0xFF, 0xFF, + 0xFF, 0x42, 0xFF, 0xE2, 0xFF, 0xFF, 0xFE, 0x40, 0x0F, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, + 0xFF, 0x03, 0xFF, 0xFF, 0x00, 0x2F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0x00, 0x03, + 0xFF, 0xF0, 0xBF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xD1, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, + 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xEF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x0F, 0xF0, 0x00, + 0x00, 0x00, 0x03, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xD2, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_14_boldGlyphs[] = { @@ -4928,6 +4940,7 @@ static const EpdGlyph bookerly_14_boldGlyphs[] = { { 17, 21, 29, 6, 21, 90, 66883 }, // ⊥ { 6, 6, 18, 6, 11, 9, 66973 }, // ⋅ { 25, 6, 29, 2, 11, 38, 66982 }, // ⋯ + { 27, 28, 29, 1, 24, 189, 67020 }, // � }; static const EpdUnicodeInterval bookerly_14_boldIntervals[] = { @@ -4991,13 +5004,14 @@ static const EpdUnicodeInterval bookerly_14_boldIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_14_bold = { bookerly_14_boldBitmaps, bookerly_14_boldGlyphs, bookerly_14_boldIntervals, - 60, + 61, 38, 31, -8, diff --git a/lib/EpdFont/builtinFonts/bookerly_14_bolditalic.h b/lib/EpdFont/builtinFonts/bookerly_14_bolditalic.h index 6081791a..807d85fc 100644 --- a/lib/EpdFont/builtinFonts/bookerly_14_bolditalic.h +++ b/lib/EpdFont/builtinFonts/bookerly_14_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_14_bolditalicBitmaps[70024] = { +static const uint8_t bookerly_14_bolditalicBitmaps[70213] = { 0x00, 0x1A, 0x40, 0x2F, 0xD0, 0x0F, 0xF0, 0x0B, 0xF8, 0x03, 0xFD, 0x00, 0xFF, 0x00, 0x3F, 0x80, 0x1F, 0xD0, 0x07, 0xF0, 0x02, 0xFC, 0x00, 0xBE, 0x00, 0x3F, 0x40, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xF8, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xF4, 0x01, 0xFF, 0x00, 0xBF, 0x80, 0x1F, @@ -4384,7 +4384,19 @@ static const uint8_t bookerly_14_bolditalicBitmaps[70024] = { 0xFF, 0xFF, 0xFF, 0xFE, 0xBF, 0xFF, 0xFF, 0xFF, 0x80, 0x01, 0x03, 0xFC, 0xBF, 0xEB, 0xFE, 0x3F, 0xC0, 0x00, 0x05, 0x00, 0x00, 0x40, 0x00, 0x04, 0x0F, 0xF0, 0x02, 0xFE, 0x00, 0x3F, 0xDB, 0xFD, 0x00, 0xFF, 0xC0, 0x1F, 0xFA, 0xFF, 0x40, 0x3F, 0xF0, 0x07, 0xFE, 0x7F, 0xC0, 0x0B, 0xF4, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x5B, 0xE0, 0x00, 0x00, 0x00, 0x02, 0xC0, 0x02, 0xE0, 0x00, + 0x00, 0x00, 0x2E, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x02, 0xFC, 0x69, 0x02, 0xE0, 0x00, 0x00, 0x2F, + 0xFF, 0xFF, 0x03, 0xE0, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x0F, 0xE0, 0x00, 0x2F, 0xFF, 0xFF, 0xFC, + 0x2F, 0xE0, 0x02, 0xFF, 0xFF, 0xFF, 0xF0, 0xBF, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0x42, 0xFF, 0xE2, + 0xFF, 0xFF, 0xFE, 0x40, 0x0F, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, + 0x00, 0x2F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xF0, 0xBF, 0xFF, + 0xF0, 0x00, 0x03, 0xFF, 0xD1, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, + 0x03, 0xFF, 0xEF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xF0, + 0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xD2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_14_bolditalicGlyphs[] = { @@ -5116,6 +5128,7 @@ static const EpdGlyph bookerly_14_bolditalicGlyphs[] = { { 17, 21, 29, 6, 21, 90, 69887 }, // ⊥ { 6, 6, 18, 6, 11, 9, 69977 }, // ⋅ { 25, 6, 29, 2, 11, 38, 69986 }, // ⋯ + { 27, 28, 29, 1, 24, 189, 70024 }, // � }; static const EpdUnicodeInterval bookerly_14_bolditalicIntervals[] = { @@ -5179,13 +5192,14 @@ static const EpdUnicodeInterval bookerly_14_bolditalicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_14_bolditalic = { bookerly_14_bolditalicBitmaps, bookerly_14_bolditalicGlyphs, bookerly_14_bolditalicIntervals, - 60, + 61, 38, 31, -8, diff --git a/lib/EpdFont/builtinFonts/bookerly_14_italic.h b/lib/EpdFont/builtinFonts/bookerly_14_italic.h index 5edb8798..8710dab2 100644 --- a/lib/EpdFont/builtinFonts/bookerly_14_italic.h +++ b/lib/EpdFont/builtinFonts/bookerly_14_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_14_italicBitmaps[64856] = { +static const uint8_t bookerly_14_italicBitmaps[65045] = { 0x00, 0x05, 0x00, 0x0F, 0x80, 0x0B, 0xD0, 0x03, 0xF0, 0x00, 0xF8, 0x00, 0x7D, 0x00, 0x2F, 0x00, 0x0F, 0x80, 0x03, 0xD0, 0x00, 0xF0, 0x00, 0x7C, 0x00, 0x1E, 0x00, 0x0B, 0x40, 0x02, 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x3F, 0x40, 0x0F, @@ -4061,7 +4061,19 @@ static const uint8_t bookerly_14_italicBitmaps[64856] = { 0xFC, 0x00, 0x06, 0xAA, 0xBF, 0xAA, 0xA6, 0xFF, 0xFF, 0xFF, 0xFE, 0xBF, 0xFF, 0xFF, 0xFF, 0x80, 0x0A, 0x43, 0xFC, 0x3F, 0xC2, 0xF8, 0x00, 0x00, 0x0A, 0x00, 0x01, 0xA0, 0x00, 0x29, 0x0F, 0xF0, 0x01, 0xFD, 0x00, 0x2F, 0xC3, 0xFC, 0x00, 0xBF, 0x80, 0x0F, 0xF0, 0xFD, 0x00, 0x0F, 0xC0, 0x01, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x5B, 0xE0, 0x00, 0x00, 0x00, 0x02, 0xC0, 0x02, 0xE0, 0x00, + 0x00, 0x00, 0x2E, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x02, 0xFC, 0x69, 0x02, 0xE0, 0x00, 0x00, 0x2F, + 0xFF, 0xFF, 0x03, 0xE0, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x0F, 0xE0, 0x00, 0x2F, 0xFF, 0xFF, 0xFC, + 0x2F, 0xE0, 0x02, 0xFF, 0xFF, 0xFF, 0xF0, 0xBF, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0x42, 0xFF, 0xE2, + 0xFF, 0xFF, 0xFE, 0x40, 0x0F, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, + 0x00, 0x2F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xF0, 0xBF, 0xFF, + 0xF0, 0x00, 0x03, 0xFF, 0xD1, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, + 0x03, 0xFF, 0xEF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xF0, + 0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xD2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_14_italicGlyphs[] = { @@ -4793,6 +4805,7 @@ static const EpdGlyph bookerly_14_italicGlyphs[] = { { 17, 21, 29, 6, 21, 90, 64726 }, // ⊥ { 6, 5, 18, 6, 10, 8, 64816 }, // ⋅ { 25, 5, 29, 2, 10, 32, 64824 }, // ⋯ + { 27, 28, 29, 1, 24, 189, 64856 }, // � }; static const EpdUnicodeInterval bookerly_14_italicIntervals[] = { @@ -4856,13 +4869,14 @@ static const EpdUnicodeInterval bookerly_14_italicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_14_italic = { bookerly_14_italicBitmaps, bookerly_14_italicGlyphs, bookerly_14_italicIntervals, - 60, + 61, 38, 31, -8, diff --git a/lib/EpdFont/builtinFonts/bookerly_14_regular.h b/lib/EpdFont/builtinFonts/bookerly_14_regular.h index f178d44c..1fec866c 100644 --- a/lib/EpdFont/builtinFonts/bookerly_14_regular.h +++ b/lib/EpdFont/builtinFonts/bookerly_14_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_14_regularBitmaps[62675] = { +static const uint8_t bookerly_14_regularBitmaps[62864] = { 0x1A, 0x1F, 0xCB, 0xE2, 0xF4, 0xBD, 0x2F, 0x4B, 0xC2, 0xF0, 0xBC, 0x2F, 0x07, 0xC1, 0xF0, 0x7C, 0x0F, 0x03, 0xC0, 0xF0, 0x00, 0x00, 0x00, 0x40, 0xFC, 0xBF, 0x5F, 0xC1, 0x40, 0x18, 0x06, 0x1F, 0x07, 0xCB, 0xC2, 0xF1, 0xF0, 0xBC, 0x7C, 0x1F, 0x1F, 0x07, 0xC7, 0xC1, 0xF1, 0xF0, 0x7C, 0x34, @@ -3925,7 +3925,18 @@ static const uint8_t bookerly_14_regularBitmaps[62675] = { 0xAA, 0xA6, 0xFF, 0xFF, 0xFF, 0xFE, 0xBF, 0xFF, 0xFF, 0xFF, 0x80, 0x0A, 0x43, 0xFC, 0x3F, 0xC2, 0xF8, 0x00, 0x00, 0x0A, 0x00, 0x01, 0xA0, 0x00, 0x29, 0x0F, 0xF0, 0x01, 0xFD, 0x00, 0x2F, 0xC3, 0xFC, 0x00, 0xBF, 0x80, 0x0F, 0xF0, 0xFD, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, + 0x2E, 0x5B, 0xE0, 0x00, 0x00, 0x00, 0x02, 0xC0, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x01, + 0xE0, 0x00, 0x00, 0x02, 0xFC, 0x69, 0x02, 0xE0, 0x00, 0x00, 0x2F, 0xFF, 0xFF, 0x03, 0xE0, 0x00, + 0x02, 0xFF, 0xFF, 0xFF, 0x0F, 0xE0, 0x00, 0x2F, 0xFF, 0xFF, 0xFC, 0x2F, 0xE0, 0x02, 0xFF, 0xFF, + 0xFF, 0xF0, 0xBF, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0x42, 0xFF, 0xE2, 0xFF, 0xFF, 0xFE, 0x40, 0x0F, + 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0x00, 0x2F, 0xFF, 0xF0, 0x03, + 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xF0, 0xBF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xD1, + 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xEF, 0xFF, 0x00, + 0x00, 0x00, 0x03, 0xFC, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xD2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_14_regularGlyphs[] = { @@ -4657,6 +4668,7 @@ static const EpdGlyph bookerly_14_regularGlyphs[] = { { 17, 21, 29, 6, 21, 90, 62545 }, // ⊥ { 6, 5, 18, 6, 10, 8, 62635 }, // ⋅ { 25, 5, 29, 2, 10, 32, 62643 }, // ⋯ + { 27, 28, 29, 1, 24, 189, 62675 }, // � }; static const EpdUnicodeInterval bookerly_14_regularIntervals[] = { @@ -4720,13 +4732,14 @@ static const EpdUnicodeInterval bookerly_14_regularIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_14_regular = { bookerly_14_regularBitmaps, bookerly_14_regularGlyphs, bookerly_14_regularIntervals, - 60, + 61, 38, 31, -8, diff --git a/lib/EpdFont/builtinFonts/bookerly_16_bold.h b/lib/EpdFont/builtinFonts/bookerly_16_bold.h index 67bdff95..71694b75 100644 --- a/lib/EpdFont/builtinFonts/bookerly_16_bold.h +++ b/lib/EpdFont/builtinFonts/bookerly_16_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_16_boldBitmaps[85154] = { +static const uint8_t bookerly_16_boldBitmaps[85402] = { 0x0A, 0x90, 0xFF, 0x87, 0xFE, 0x2F, 0xF4, 0xBF, 0xC2, 0xFF, 0x0B, 0xFC, 0x2F, 0xF0, 0xBF, 0xC2, 0xFF, 0x0B, 0xFC, 0x1F, 0xF0, 0x7F, 0xC0, 0xFE, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0xC0, 0xBF, 0x01, 0x40, 0x00, 0x00, 0x05, 0x40, 0xFF, 0xC7, 0xFF, 0x1F, 0xFC, 0x3F, 0xF0, 0x19, 0x00, 0x0A, 0x80, @@ -5330,7 +5330,22 @@ static const uint8_t bookerly_16_boldBitmaps[85154] = { 0x2F, 0xFC, 0x7F, 0xE0, 0x15, 0x00, 0x0A, 0x90, 0x00, 0x2A, 0x40, 0x00, 0xA9, 0x0F, 0xFC, 0x00, 0x3F, 0xF0, 0x00, 0xFF, 0xC7, 0xFF, 0x40, 0x1F, 0xFD, 0x00, 0x7F, 0xF5, 0xFF, 0xD0, 0x07, 0xFF, 0x40, 0x1F, 0xFD, 0x3F, 0xF0, 0x00, 0xFF, 0xC0, 0x03, 0xFF, 0x01, 0x50, 0x00, 0x05, 0x40, 0x00, - 0x15, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xEF, 0xFC, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x01, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xBC, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x0F, 0xF9, 0xBE, 0x40, 0xFC, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0x81, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x43, 0xFC, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFE, 0x0F, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFC, 0x2F, 0xFC, 0x00, 0xFF, + 0xFF, 0xFF, 0xFF, 0xD0, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xFF, 0xE4, 0x03, 0xFF, 0xFC, 0x7F, 0xFF, + 0xFF, 0xD0, 0x00, 0x2F, 0xFF, 0xF4, 0x7F, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xFF, 0x40, 0x7F, 0xFF, + 0xF8, 0x00, 0x7F, 0xFF, 0xF4, 0x00, 0x7F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0x40, 0x00, 0x7F, 0xFF, + 0xC2, 0xFF, 0xFF, 0xF4, 0x00, 0x00, 0x7F, 0xFF, 0x07, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x7F, 0xFE, + 0x7F, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xF4, + 0x7F, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x03, + 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0x2F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_16_boldGlyphs[] = { @@ -6062,6 +6077,7 @@ static const EpdGlyph bookerly_16_boldGlyphs[] = { { 19, 23, 33, 7, 23, 110, 84989 }, // ⊥ { 7, 6, 21, 7, 12, 11, 85099 }, // ⋅ { 29, 6, 33, 2, 12, 44, 85110 }, // ⋯ + { 31, 32, 33, 1, 28, 248, 85154 }, // � }; static const EpdUnicodeInterval bookerly_16_boldIntervals[] = { @@ -6125,13 +6141,14 @@ static const EpdUnicodeInterval bookerly_16_boldIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_16_bold = { bookerly_16_boldBitmaps, bookerly_16_boldGlyphs, bookerly_16_boldIntervals, - 60, + 61, 44, 36, -9, diff --git a/lib/EpdFont/builtinFonts/bookerly_16_bolditalic.h b/lib/EpdFont/builtinFonts/bookerly_16_bolditalic.h index 4a7a9e25..75f34b6a 100644 --- a/lib/EpdFont/builtinFonts/bookerly_16_bolditalic.h +++ b/lib/EpdFont/builtinFonts/bookerly_16_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_16_bolditalicBitmaps[88512] = { +static const uint8_t bookerly_16_bolditalicBitmaps[88760] = { 0x00, 0x06, 0xA0, 0x00, 0xBF, 0xC0, 0x07, 0xFD, 0x00, 0x3F, 0xF0, 0x00, 0xFF, 0x80, 0x07, 0xFD, 0x00, 0x1F, 0xF0, 0x00, 0xBF, 0x80, 0x03, 0xFD, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0xFE, 0x00, 0x07, 0xF4, 0x00, 0x1F, 0xC0, 0x00, 0xBF, 0x00, 0x02, 0xF8, 0x00, 0x0B, 0xD0, 0x00, 0x3F, @@ -5540,6 +5540,22 @@ static const uint8_t bookerly_16_bolditalicBitmaps[88512] = { 0x7F, 0xE0, 0x15, 0x00, 0x0A, 0x90, 0x00, 0x2A, 0x40, 0x00, 0xA9, 0x0F, 0xFC, 0x00, 0x3F, 0xF0, 0x00, 0xFF, 0xC7, 0xFF, 0x40, 0x1F, 0xFD, 0x00, 0x7F, 0xF5, 0xFF, 0xD0, 0x07, 0xFF, 0x40, 0x1F, 0xFD, 0x3F, 0xF0, 0x00, 0xFF, 0xC0, 0x03, 0xFF, 0x01, 0x50, 0x00, 0x05, 0x40, 0x00, 0x15, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xEF, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xF0, 0x01, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x0F, 0xF9, 0xBE, 0x40, 0xFC, 0x00, 0x00, 0x00, 0xFF, + 0xFF, 0xFF, 0x81, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x43, 0xFC, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xFE, 0x0F, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFC, 0x2F, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xD0, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xFF, 0xE4, 0x03, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xD0, + 0x00, 0x2F, 0xFF, 0xF4, 0x7F, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xFF, 0x40, 0x7F, 0xFF, 0xF8, 0x00, + 0x7F, 0xFF, 0xF4, 0x00, 0x7F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0x40, 0x00, 0x7F, 0xFF, 0xC2, 0xFF, + 0xFF, 0xF4, 0x00, 0x00, 0x7F, 0xFF, 0x07, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFF, + 0xF4, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xF4, 0x7F, 0xF4, + 0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x03, 0xF4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7D, 0x2F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_16_bolditalicGlyphs[] = { @@ -6271,6 +6287,7 @@ static const EpdGlyph bookerly_16_bolditalicGlyphs[] = { { 19, 23, 33, 7, 23, 110, 88347 }, // ⊥ { 7, 6, 21, 7, 12, 11, 88457 }, // ⋅ { 29, 6, 33, 2, 12, 44, 88468 }, // ⋯ + { 31, 32, 33, 1, 28, 248, 88512 }, // � }; static const EpdUnicodeInterval bookerly_16_bolditalicIntervals[] = { @@ -6334,13 +6351,14 @@ static const EpdUnicodeInterval bookerly_16_bolditalicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_16_bolditalic = { bookerly_16_bolditalicBitmaps, bookerly_16_bolditalicGlyphs, bookerly_16_bolditalicIntervals, - 60, + 61, 44, 36, -9, diff --git a/lib/EpdFont/builtinFonts/bookerly_16_italic.h b/lib/EpdFont/builtinFonts/bookerly_16_italic.h index 2a4b5ef6..fbbd0069 100644 --- a/lib/EpdFont/builtinFonts/bookerly_16_italic.h +++ b/lib/EpdFont/builtinFonts/bookerly_16_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_16_italicBitmaps[82412] = { +static const uint8_t bookerly_16_italicBitmaps[82660] = { 0x00, 0x01, 0x40, 0x00, 0xFC, 0x00, 0x3F, 0x80, 0x03, 0xF0, 0x00, 0x7F, 0x00, 0x0B, 0xE0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x40, 0x02, 0xF0, 0x00, 0x2F, 0x00, 0x03, 0xE0, 0x00, 0x3D, 0x00, 0x03, 0xC0, 0x00, 0x7C, 0x00, 0x07, 0x80, 0x00, 0x74, 0x00, 0x0A, 0x00, 0x00, @@ -5158,7 +5158,23 @@ static const uint8_t bookerly_16_italicBitmaps[82412] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFC, 0x3F, 0xE3, 0xFE, 0x2F, 0xC0, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x00, 0x03, 0xF0, 0x00, 0x0B, 0xDB, 0xFC, 0x00, 0x2F, 0xF0, 0x00, 0xBF, 0xFF, 0xF0, 0x00, 0xFF, 0xC0, 0x03, 0xFF, 0x7F, 0x40, - 0x01, 0xFD, 0x00, 0x07, 0xF4, 0x10, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, + 0x01, 0xFD, 0x00, 0x07, 0xF4, 0x10, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xEF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x01, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xBC, + 0x00, 0x00, 0x00, 0x0F, 0xF9, 0xBE, 0x40, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x81, 0xFC, + 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x43, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x0F, 0xFC, + 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFC, 0x2F, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xD0, 0xFF, 0xFC, + 0x0F, 0xFF, 0xFF, 0xFF, 0xE4, 0x03, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xD0, 0x00, 0x2F, 0xFF, 0xF4, + 0x7F, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xFF, 0x40, 0x7F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF4, 0x00, + 0x7F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0x40, 0x00, 0x7F, 0xFF, 0xC2, 0xFF, 0xFF, 0xF4, 0x00, 0x00, + 0x7F, 0xFF, 0x07, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFF, 0xF4, 0x00, 0x00, 0x00, + 0x7F, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xF4, 0x7F, 0xF4, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0x80, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x03, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7D, 0x2F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_16_italicGlyphs[] = { @@ -5890,6 +5906,7 @@ static const EpdGlyph bookerly_16_italicGlyphs[] = { { 19, 23, 33, 7, 23, 110, 82252 }, // ⊥ { 6, 6, 21, 7, 12, 9, 82362 }, // ⋅ { 27, 6, 33, 3, 12, 41, 82371 }, // ⋯ + { 31, 32, 33, 1, 28, 248, 82412 }, // � }; static const EpdUnicodeInterval bookerly_16_italicIntervals[] = { @@ -5953,13 +5970,14 @@ static const EpdUnicodeInterval bookerly_16_italicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_16_italic = { bookerly_16_italicBitmaps, bookerly_16_italicGlyphs, bookerly_16_italicIntervals, - 60, + 61, 44, 36, -9, diff --git a/lib/EpdFont/builtinFonts/bookerly_16_regular.h b/lib/EpdFont/builtinFonts/bookerly_16_regular.h index 92ba41ad..e40411fe 100644 --- a/lib/EpdFont/builtinFonts/bookerly_16_regular.h +++ b/lib/EpdFont/builtinFonts/bookerly_16_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_16_regularBitmaps[79871] = { +static const uint8_t bookerly_16_regularBitmaps[80119] = { 0x0A, 0x83, 0xF8, 0x3F, 0x47, 0xF4, 0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x3F, 0x03, 0xF0, 0x3F, 0x03, 0xF0, 0x3F, 0x03, 0xF0, 0x3F, 0x03, 0xF0, 0x2F, 0x02, 0xF0, 0x04, 0x00, 0x00, 0x00, 0x01, 0xA4, 0x3F, 0xC3, 0xFC, 0x3F, 0xC0, 0x50, 0x05, 0x01, 0x93, 0xE0, 0x7D, 0x7E, 0x0B, 0xD7, 0xE0, @@ -4999,7 +4999,23 @@ static const uint8_t bookerly_16_regularBitmaps[79871] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFC, 0x3F, 0xE3, 0xFE, 0x2F, 0xC0, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x00, 0x03, 0xF0, 0x00, 0x0B, 0xDB, 0xFC, 0x00, 0x2F, 0xF0, 0x00, 0xBF, 0xFF, 0xF0, 0x00, 0xFF, 0xC0, 0x03, - 0xFF, 0x7F, 0x40, 0x01, 0xFD, 0x00, 0x07, 0xF4, 0x10, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, + 0xFF, 0x7F, 0x40, 0x01, 0xFD, 0x00, 0x07, 0xF4, 0x10, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xEF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0x01, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x00, 0xFC, + 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x0F, 0xF9, 0xBE, 0x40, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0x81, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x43, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0xFE, 0x0F, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFC, 0x2F, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xD0, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xFF, 0xE4, 0x03, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xD0, 0x00, + 0x2F, 0xFF, 0xF4, 0x7F, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xFF, 0x40, 0x7F, 0xFF, 0xF8, 0x00, 0x7F, + 0xFF, 0xF4, 0x00, 0x7F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0x40, 0x00, 0x7F, 0xFF, 0xC2, 0xFF, 0xFF, + 0xF4, 0x00, 0x00, 0x7F, 0xFF, 0x07, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFF, 0xF4, + 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xF4, 0x7F, 0xF4, 0x00, + 0x00, 0x00, 0x00, 0x7F, 0x80, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x03, 0xF4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7D, 0x2F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_16_regularGlyphs[] = { @@ -5731,6 +5747,7 @@ static const EpdGlyph bookerly_16_regularGlyphs[] = { { 19, 23, 33, 7, 23, 110, 79711 }, // ⊥ { 6, 6, 21, 7, 12, 9, 79821 }, // ⋅ { 27, 6, 33, 3, 12, 41, 79830 }, // ⋯ + { 31, 32, 33, 1, 28, 248, 79871 }, // � }; static const EpdUnicodeInterval bookerly_16_regularIntervals[] = { @@ -5794,13 +5811,14 @@ static const EpdUnicodeInterval bookerly_16_regularIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_16_regular = { bookerly_16_regularBitmaps, bookerly_16_regularGlyphs, bookerly_16_regularIntervals, - 60, + 61, 44, 36, -9, diff --git a/lib/EpdFont/builtinFonts/bookerly_18_bold.h b/lib/EpdFont/builtinFonts/bookerly_18_bold.h index 74590181..db3d2d55 100644 --- a/lib/EpdFont/builtinFonts/bookerly_18_bold.h +++ b/lib/EpdFont/builtinFonts/bookerly_18_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_18_boldBitmaps[112410] = { +static const uint8_t bookerly_18_boldBitmaps[112734] = { 0x01, 0x54, 0x1F, 0xFC, 0x3F, 0xF8, 0x3F, 0xF8, 0x7F, 0xF4, 0x7F, 0xF4, 0x7F, 0xF0, 0x7F, 0xF0, 0x7F, 0xF0, 0x7F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x2F, 0xF0, 0x2F, 0xF0, 0x1F, 0xF0, 0x1F, 0xF0, 0x0F, 0xF0, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -7033,7 +7033,27 @@ static const uint8_t bookerly_18_boldBitmaps[112410] = { 0x00, 0x00, 0x54, 0x00, 0x00, 0x54, 0x01, 0xFF, 0xC0, 0x00, 0xBF, 0xF0, 0x00, 0x3F, 0xF4, 0x3F, 0xFE, 0x00, 0x0F, 0xFF, 0x40, 0x0B, 0xFF, 0xC3, 0xFF, 0xF0, 0x01, 0xFF, 0xF4, 0x00, 0xBF, 0xFC, 0x3F, 0xFE, 0x00, 0x1F, 0xFF, 0x00, 0x0B, 0xFF, 0xC1, 0xFF, 0xC0, 0x00, 0xFF, 0xE0, 0x00, 0x3F, - 0xF4, 0x01, 0x50, 0x00, 0x01, 0x50, 0x00, 0x00, 0x54, 0x00, + 0xF4, 0x01, 0x50, 0x00, 0x01, 0x50, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0B, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xFF, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xBE, 0x56, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x2F, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x0B, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xC0, 0x00, + 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xD1, 0xA9, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xF0, 0x2F, 0xE0, 0x00, 0x00, + 0x2F, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x00, 0x00, 0xBF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFE, + 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0x80, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, + 0x1F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0xFE, 0x40, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, + 0x80, 0x00, 0x3F, 0xFF, 0xFD, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF4, 0x07, 0xFF, + 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xD0, 0x01, 0xFF, 0xFF, 0xF8, 0x00, 0xBF, 0xFF, 0xFF, 0x40, + 0x00, 0x7F, 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, + 0xF4, 0x00, 0x00, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xD0, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x1F, + 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x1F, + 0xFF, 0xEB, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xFE, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFD, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x97, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_18_boldGlyphs[] = { @@ -7765,6 +7785,7 @@ static const EpdGlyph bookerly_18_boldGlyphs[] = { { 22, 27, 38, 8, 27, 149, 112187 }, // ⊥ { 8, 7, 24, 8, 14, 14, 112336 }, // ⋅ { 34, 7, 38, 2, 14, 60, 112350 }, // ⋯ + { 36, 36, 38, 1, 32, 324, 112410 }, // � }; static const EpdUnicodeInterval bookerly_18_boldIntervals[] = { @@ -7828,13 +7849,14 @@ static const EpdUnicodeInterval bookerly_18_boldIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_18_bold = { bookerly_18_boldBitmaps, bookerly_18_boldGlyphs, bookerly_18_boldIntervals, - 60, + 61, 49, 40, -10, diff --git a/lib/EpdFont/builtinFonts/bookerly_18_bolditalic.h b/lib/EpdFont/builtinFonts/bookerly_18_bolditalic.h index f0484d6d..ca65d6a4 100644 --- a/lib/EpdFont/builtinFonts/bookerly_18_bolditalic.h +++ b/lib/EpdFont/builtinFonts/bookerly_18_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_18_bolditalicBitmaps[115736] = { +static const uint8_t bookerly_18_bolditalicBitmaps[116060] = { 0x00, 0x00, 0x54, 0x00, 0x07, 0xFE, 0x00, 0x0F, 0xFC, 0x00, 0x2F, 0xFC, 0x00, 0x3F, 0xF4, 0x00, 0x7F, 0xF0, 0x00, 0xBF, 0xF0, 0x00, 0xFF, 0xD0, 0x00, 0xFF, 0xC0, 0x00, 0xFF, 0xC0, 0x01, 0xFF, 0x80, 0x01, 0xFF, 0x40, 0x02, 0xFF, 0x00, 0x02, 0xFE, 0x00, 0x03, 0xFD, 0x00, 0x03, 0xFC, 0x00, @@ -7241,7 +7241,27 @@ static const uint8_t bookerly_18_bolditalicBitmaps[115736] = { 0x54, 0x00, 0x00, 0x54, 0x01, 0xFF, 0xC0, 0x00, 0xBF, 0xF0, 0x00, 0x3F, 0xF4, 0x3F, 0xFE, 0x00, 0x0F, 0xFF, 0x40, 0x0B, 0xFF, 0xC3, 0xFF, 0xF0, 0x01, 0xFF, 0xF4, 0x00, 0xBF, 0xFC, 0x3F, 0xFE, 0x00, 0x1F, 0xFF, 0x00, 0x0B, 0xFF, 0xC1, 0xFF, 0xC0, 0x00, 0xFF, 0xE0, 0x00, 0x3F, 0xF4, 0x01, - 0x50, 0x00, 0x01, 0x50, 0x00, 0x00, 0x54, 0x00, + 0x50, 0x00, 0x01, 0x50, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, + 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xBE, 0x56, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x2F, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x0B, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xC0, 0x00, 0x01, 0xF8, + 0x00, 0x00, 0x00, 0x00, 0xBF, 0xD1, 0xA9, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, + 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xF0, 0x2F, 0xE0, 0x00, 0x00, 0x2F, 0xFF, + 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x00, 0x00, 0xBF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFE, 0x00, 0x02, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0x80, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, 0x1F, 0xFF, + 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0xFE, 0x40, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, + 0x3F, 0xFF, 0xFD, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF4, 0x07, 0xFF, 0xFF, 0xF8, + 0x00, 0x07, 0xFF, 0xFF, 0xD0, 0x01, 0xFF, 0xFF, 0xF8, 0x00, 0xBF, 0xFF, 0xFF, 0x40, 0x00, 0x7F, + 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xF4, 0x00, + 0x00, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xD0, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, + 0x40, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xEB, + 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xFE, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0x97, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_18_bolditalicGlyphs[] = { @@ -7973,6 +7993,7 @@ static const EpdGlyph bookerly_18_bolditalicGlyphs[] = { { 22, 27, 38, 8, 27, 149, 115513 }, // ⊥ { 8, 7, 24, 8, 14, 14, 115662 }, // ⋅ { 34, 7, 38, 2, 14, 60, 115676 }, // ⋯ + { 36, 36, 38, 1, 32, 324, 115736 }, // � }; static const EpdUnicodeInterval bookerly_18_bolditalicIntervals[] = { @@ -8036,13 +8057,14 @@ static const EpdUnicodeInterval bookerly_18_bolditalicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_18_bolditalic = { bookerly_18_bolditalicBitmaps, bookerly_18_bolditalicGlyphs, bookerly_18_bolditalicIntervals, - 60, + 61, 49, 40, -10, diff --git a/lib/EpdFont/builtinFonts/bookerly_18_italic.h b/lib/EpdFont/builtinFonts/bookerly_18_italic.h index e7735b16..a04a75fa 100644 --- a/lib/EpdFont/builtinFonts/bookerly_18_italic.h +++ b/lib/EpdFont/builtinFonts/bookerly_18_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_18_italicBitmaps[108017] = { +static const uint8_t bookerly_18_italicBitmaps[108341] = { 0x00, 0x00, 0x00, 0x00, 0xBE, 0x00, 0x2F, 0xD0, 0x03, 0xFC, 0x00, 0x7F, 0x80, 0x0B, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0xC0, 0x02, 0xF8, 0x00, 0x2F, 0x40, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xE0, 0x00, 0x7D, 0x00, 0x07, 0xC0, 0x00, 0xBC, 0x00, 0x0F, 0x80, 0x00, @@ -6759,7 +6759,27 @@ static const uint8_t bookerly_18_italicBitmaps[108017] = { 0x50, 0x0A, 0x80, 0x00, 0x02, 0x90, 0x00, 0x01, 0xA0, 0x3F, 0xF0, 0x00, 0x1F, 0xF4, 0x00, 0x0B, 0xFC, 0x7F, 0xF0, 0x00, 0x2F, 0xF8, 0x00, 0x0F, 0xFD, 0x7F, 0xF0, 0x00, 0x2F, 0xF8, 0x00, 0x0F, 0xFD, 0x3F, 0xD0, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xF8, 0x05, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, - 0x40, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x2F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x56, 0xFE, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0xE0, 0x00, 0x2F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xC0, 0x00, 0x07, 0xE0, + 0x00, 0x00, 0x00, 0x00, 0x2F, 0xC0, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xD1, 0xA9, + 0x00, 0xBE, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x0B, 0xFF, + 0xFF, 0xFF, 0xF0, 0x2F, 0xE0, 0x00, 0x00, 0x2F, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x00, 0x00, + 0xBF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFE, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, + 0x80, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, 0x1F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0xFE, 0x40, + 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xFD, 0x1F, 0xFF, 0xFF, 0xF8, + 0x00, 0x00, 0xFF, 0xFF, 0xF4, 0x07, 0xFF, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xD0, 0x01, 0xFF, + 0xFF, 0xF8, 0x00, 0xBF, 0xFF, 0xFF, 0x40, 0x00, 0x7F, 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0xFD, 0x00, + 0x00, 0x1F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xF4, 0x00, 0x00, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, + 0xD0, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xEB, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xFF, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFE, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7F, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x97, 0xF4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_18_italicGlyphs[] = { @@ -7491,6 +7511,7 @@ static const EpdGlyph bookerly_18_italicGlyphs[] = { { 22, 27, 38, 8, 27, 149, 107811 }, // ⊥ { 6, 6, 24, 9, 13, 9, 107960 }, // ⋅ { 32, 6, 38, 3, 13, 48, 107969 }, // ⋯ + { 36, 36, 38, 1, 32, 324, 108017 }, // � }; static const EpdUnicodeInterval bookerly_18_italicIntervals[] = { @@ -7554,13 +7575,14 @@ static const EpdUnicodeInterval bookerly_18_italicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_18_italic = { bookerly_18_italicBitmaps, bookerly_18_italicGlyphs, bookerly_18_italicIntervals, - 60, + 61, 49, 40, -10, diff --git a/lib/EpdFont/builtinFonts/bookerly_18_regular.h b/lib/EpdFont/builtinFonts/bookerly_18_regular.h index 08d657db..0b860dbd 100644 --- a/lib/EpdFont/builtinFonts/bookerly_18_regular.h +++ b/lib/EpdFont/builtinFonts/bookerly_18_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_18_regularBitmaps[105210] = { +static const uint8_t bookerly_18_regularBitmaps[105534] = { 0x05, 0x43, 0xF8, 0xBF, 0x4F, 0xF4, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFE, 0x0F, 0xE0, 0xBE, 0x0B, 0xE0, 0xBE, 0x0B, 0xE0, 0x7E, 0x07, 0xE0, 0x7E, 0x03, 0xE0, 0x3E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0xFC, 0xBF, 0xCF, 0xFC, 0xBF, 0xC1, 0x90, 0x00, 0x00, 0x00, @@ -6583,7 +6583,27 @@ static const uint8_t bookerly_18_regularBitmaps[105210] = { 0xF0, 0x1A, 0x47, 0xFC, 0xFF, 0xDF, 0xFD, 0x7F, 0xC0, 0x50, 0x0A, 0x80, 0x00, 0x02, 0x90, 0x00, 0x01, 0xA0, 0x3F, 0xF0, 0x00, 0x1F, 0xF4, 0x00, 0x0B, 0xFC, 0x7F, 0xF0, 0x00, 0x2F, 0xF8, 0x00, 0x0F, 0xFD, 0x7F, 0xF0, 0x00, 0x2F, 0xF8, 0x00, 0x0F, 0xFD, 0x3F, 0xD0, 0x00, 0x0F, 0xF0, 0x00, - 0x07, 0xF8, 0x05, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x40, + 0x07, 0xF8, 0x05, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0B, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xFF, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xBE, 0x56, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x2F, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x0B, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xC0, 0x00, + 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xD1, 0xA9, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xF0, 0x2F, 0xE0, 0x00, 0x00, + 0x2F, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x00, 0x00, 0xBF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFE, + 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0x80, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, + 0x1F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0xFE, 0x40, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, + 0x80, 0x00, 0x3F, 0xFF, 0xFD, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF4, 0x07, 0xFF, + 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xD0, 0x01, 0xFF, 0xFF, 0xF8, 0x00, 0xBF, 0xFF, 0xFF, 0x40, + 0x00, 0x7F, 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, + 0xF4, 0x00, 0x00, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xD0, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x1F, + 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x1F, + 0xFF, 0xEB, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xFE, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFD, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x97, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_18_regularGlyphs[] = { @@ -7315,6 +7335,7 @@ static const EpdGlyph bookerly_18_regularGlyphs[] = { { 22, 27, 38, 8, 27, 149, 105004 }, // ⊥ { 6, 6, 24, 9, 13, 9, 105153 }, // ⋅ { 32, 6, 38, 3, 13, 48, 105162 }, // ⋯ + { 36, 36, 38, 1, 32, 324, 105210 }, // � }; static const EpdUnicodeInterval bookerly_18_regularIntervals[] = { @@ -7378,13 +7399,14 @@ static const EpdUnicodeInterval bookerly_18_regularIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_18_regular = { bookerly_18_regularBitmaps, bookerly_18_regularGlyphs, bookerly_18_regularIntervals, - 60, + 61, 49, 40, -10, diff --git a/lib/EpdFont/builtinFonts/notosans_12_bold.h b/lib/EpdFont/builtinFonts/notosans_12_bold.h index 69540f55..5843a599 100644 --- a/lib/EpdFont/builtinFonts/notosans_12_bold.h +++ b/lib/EpdFont/builtinFonts/notosans_12_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_12_boldBitmaps[49639] = { +static const uint8_t notosans_12_boldBitmaps[49772] = { 0x7F, 0xAF, 0xE7, 0xF9, 0xFD, 0x7F, 0x5F, 0xD7, 0xF4, 0xFD, 0x3F, 0x0F, 0xC3, 0xF0, 0xFC, 0x00, 0x00, 0x02, 0xE2, 0xFE, 0xBF, 0x9F, 0xD0, 0x40, 0x7F, 0x0F, 0xD7, 0xF0, 0xFD, 0x7F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xE0, 0xBC, 0x29, 0x06, 0x80, 0x00, 0x0F, 0x43, 0xD0, 0x00, 0x1F, @@ -3110,7 +3110,15 @@ static const uint8_t notosans_12_boldBitmaps[49639] = { 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xBF, 0x40, 0x00, 0x7F, 0xC0, 0x14, 0x3F, 0xFF, 0xF8, 0x0F, 0xFF, 0xF8, 0x02, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFC, 0x55, 0x55, 0x54, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xDF, 0xFF, 0xFF, 0xF5, 0xAA, 0xAA, 0xA8, + 0xDF, 0xFF, 0xFF, 0xF5, 0xAA, 0xAA, 0xA8, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x03, + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x2F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x2F, 0x00, 0x00, + 0x3F, 0xC6, 0xD0, 0x7F, 0x00, 0x03, 0xFF, 0xFF, 0xC1, 0xFF, 0x00, 0x3F, 0xFF, 0xFE, 0x07, 0xFF, + 0x03, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0x2F, 0xFF, 0xFE, 0x03, 0xFF, 0xFE, 0x3F, 0xFF, 0xF0, 0x3F, + 0xFF, 0xF0, 0x3F, 0xFF, 0x82, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0x5F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, + 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xF5, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0x41, 0xFF, 0x00, 0x00, 0x00, + 0x3D, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x3E, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_12_boldGlyphs[] = { @@ -3948,6 +3956,7 @@ static const EpdGlyph notosans_12_boldGlyphs[] = { { 12, 24, 14, 2, 21, 72, 49497 }, // ₿ { 12, 19, 13, 1, 14, 57, 49569 }, // ⃀ { 13, 4, 15, 1, 11, 13, 49626 }, // − + { 23, 23, 25, 1, 19, 133, 49639 }, // � }; static const EpdUnicodeInterval notosans_12_boldIntervals[] = { @@ -3962,13 +3971,14 @@ static const EpdUnicodeInterval notosans_12_boldIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_12_bold = { notosans_12_boldBitmaps, notosans_12_boldGlyphs, notosans_12_boldIntervals, - 11, + 12, 34, 27, -8, diff --git a/lib/EpdFont/builtinFonts/notosans_12_bolditalic.h b/lib/EpdFont/builtinFonts/notosans_12_bolditalic.h index 1cb1536d..cd44fdb2 100644 --- a/lib/EpdFont/builtinFonts/notosans_12_bolditalic.h +++ b/lib/EpdFont/builtinFonts/notosans_12_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_12_bolditalicBitmaps[52863] = { +static const uint8_t notosans_12_bolditalicBitmaps[52996] = { 0x01, 0xFE, 0x02, 0xFE, 0x02, 0xFD, 0x03, 0xFC, 0x03, 0xFC, 0x03, 0xF8, 0x07, 0xF4, 0x0B, 0xF0, 0x0B, 0xF0, 0x0F, 0xE0, 0x0F, 0xD0, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x7F, 0x80, 0xBF, 0x80, 0x7F, 0x00, 0x04, 0x00, 0x2F, 0x4B, 0xD3, 0xF4, 0xFD, 0x3F, 0x0F, 0xC3, 0xE0, 0xF8, @@ -3311,7 +3311,16 @@ static const uint8_t notosans_12_bolditalicBitmaps[52863] = { 0xFC, 0x0F, 0xE0, 0x3F, 0x82, 0xFD, 0x03, 0xFF, 0xFF, 0x40, 0x7F, 0xFF, 0x80, 0x0B, 0xFF, 0xFD, 0x00, 0xFF, 0x1F, 0xF0, 0x0F, 0xE0, 0x7F, 0x80, 0xFD, 0x03, 0xF8, 0x1F, 0xC0, 0x7F, 0x42, 0xFC, 0x1F, 0xF0, 0x3F, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0x90, 0x00, 0x34, 0xF0, 0x00, - 0x07, 0x0E, 0x00, 0x00, 0x50, 0x40, 0x00, 0x05, 0x54, 0x3F, 0xFD, 0x7F, 0xFC, 0x7F, 0xFC, + 0x07, 0x0E, 0x00, 0x00, 0x50, 0x40, 0x00, 0x05, 0x54, 0x3F, 0xFD, 0x7F, 0xFC, 0x7F, 0xFC, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x2F, + 0x00, 0x00, 0x03, 0xE0, 0x00, 0x2F, 0x00, 0x00, 0x3F, 0xC6, 0xD0, 0x7F, 0x00, 0x03, 0xFF, 0xFF, + 0xC1, 0xFF, 0x00, 0x3F, 0xFF, 0xFE, 0x07, 0xFF, 0x03, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0x2F, 0xFF, + 0xFE, 0x03, 0xFF, 0xFE, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0x82, 0xFF, 0xFF, 0x00, + 0x3F, 0xFF, 0x5F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xF5, 0xFF, 0xF0, + 0x00, 0x00, 0x3F, 0x41, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x3E, 0xBF, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_12_bolditalicGlyphs[] = { @@ -4148,6 +4157,7 @@ static const EpdGlyph notosans_12_bolditalicGlyphs[] = { { 18, 21, 15, -1, 21, 95, 52676 }, // ₾ { 14, 24, 14, 0, 21, 84, 52771 }, // ₿ { 8, 4, 8, 0, 9, 8, 52855 }, // − + { 23, 23, 25, 1, 19, 133, 52863 }, // � }; static const EpdUnicodeInterval notosans_12_bolditalicIntervals[] = { @@ -4162,13 +4172,14 @@ static const EpdUnicodeInterval notosans_12_bolditalicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_12_bolditalic = { notosans_12_bolditalicBitmaps, notosans_12_bolditalicGlyphs, notosans_12_bolditalicIntervals, - 11, + 12, 34, 27, -8, diff --git a/lib/EpdFont/builtinFonts/notosans_12_italic.h b/lib/EpdFont/builtinFonts/notosans_12_italic.h index e4b05ad5..6dad453e 100644 --- a/lib/EpdFont/builtinFonts/notosans_12_italic.h +++ b/lib/EpdFont/builtinFonts/notosans_12_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_12_italicBitmaps[48397] = { +static const uint8_t notosans_12_italicBitmaps[48530] = { 0x00, 0xB8, 0x03, 0xE0, 0x0F, 0x40, 0x7C, 0x02, 0xF0, 0x0F, 0x80, 0x3D, 0x00, 0xF0, 0x07, 0xC0, 0x1E, 0x00, 0xB4, 0x03, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x40, 0x7E, 0x01, 0xF4, 0x01, 0x00, 0x00, 0x1E, 0x0F, 0x0B, 0x87, 0xC2, 0xD1, 0xE0, 0xF0, 0xB4, 0x38, 0x2C, 0x0D, 0x0E, 0x02, @@ -3032,7 +3032,16 @@ static const uint8_t notosans_12_italicBitmaps[48397] = { 0x0F, 0x00, 0x2E, 0x07, 0xC0, 0x0B, 0x82, 0xE0, 0x07, 0xC0, 0xF9, 0x5B, 0xD0, 0x3F, 0xFF, 0x80, 0x0F, 0xAB, 0xF4, 0x07, 0xC0, 0x1F, 0x02, 0xE0, 0x03, 0xD0, 0xF4, 0x00, 0xF8, 0x3C, 0x00, 0x3D, 0x0F, 0x00, 0x1F, 0x07, 0xC0, 0x1F, 0x82, 0xFF, 0xFF, 0x80, 0xFF, 0xFE, 0x40, 0x03, 0x8B, 0x00, - 0x00, 0xD3, 0x80, 0x00, 0x10, 0x40, 0x00, 0x2A, 0xA8, 0xFF, 0xE1, 0x55, 0x00, + 0x00, 0xD3, 0x80, 0x00, 0x10, 0x40, 0x00, 0x2A, 0xA8, 0xFF, 0xE1, 0x55, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x2F, 0x00, 0x00, + 0x03, 0xE0, 0x00, 0x2F, 0x00, 0x00, 0x3F, 0xC6, 0xD0, 0x7F, 0x00, 0x03, 0xFF, 0xFF, 0xC1, 0xFF, + 0x00, 0x3F, 0xFF, 0xFE, 0x07, 0xFF, 0x03, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0x2F, 0xFF, 0xFE, 0x03, + 0xFF, 0xFE, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0x82, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, + 0x5F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xF5, 0xFF, 0xF0, 0x00, 0x00, + 0x3F, 0x41, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x3E, 0xBF, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, }; static const EpdGlyph notosans_12_italicGlyphs[] = { @@ -3869,6 +3878,7 @@ static const EpdGlyph notosans_12_italicGlyphs[] = { { 17, 21, 15, -1, 21, 90, 48223 }, // ₾ { 13, 24, 14, 1, 21, 78, 48313 }, // ₿ { 7, 3, 8, 0, 8, 6, 48391 }, // − + { 23, 23, 25, 1, 19, 133, 48397 }, // � }; static const EpdUnicodeInterval notosans_12_italicIntervals[] = { @@ -3883,13 +3893,14 @@ static const EpdUnicodeInterval notosans_12_italicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_12_italic = { notosans_12_italicBitmaps, notosans_12_italicGlyphs, notosans_12_italicIntervals, - 11, + 12, 34, 27, -8, diff --git a/lib/EpdFont/builtinFonts/notosans_12_regular.h b/lib/EpdFont/builtinFonts/notosans_12_regular.h index fd0d91f3..e580f83f 100644 --- a/lib/EpdFont/builtinFonts/notosans_12_regular.h +++ b/lib/EpdFont/builtinFonts/notosans_12_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_12_regularBitmaps[45168] = { +static const uint8_t notosans_12_regularBitmaps[45301] = { 0x3E, 0x3E, 0x3E, 0x3E, 0x3D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2C, 0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x3E, 0x3F, 0x3E, 0x04, 0x7C, 0x2D, 0x7C, 0x2D, 0x3C, 0x2D, 0x38, 0x2D, 0x38, 0x1C, 0x38, 0x1C, 0x24, 0x08, 0x00, 0x0B, 0x01, 0xC0, 0x00, 0x0E, 0x02, 0xC0, 0x00, 0x0E, 0x03, 0xC0, 0x00, 0x1D, 0x03, @@ -2831,6 +2831,15 @@ static const uint8_t notosans_12_regularBitmaps[45168] = { 0x95, 0x93, 0xE0, 0x00, 0x7C, 0x00, 0x0B, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x40, 0x00, 0xB8, 0x00, 0x0B, 0x80, 0x00, 0x7C, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xEA, 0xF0, 0x2F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xFF, 0xF6, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x00, + 0x2F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x2F, 0x00, 0x00, 0x3F, 0xC6, 0xD0, 0x7F, 0x00, 0x03, 0xFF, + 0xFF, 0xC1, 0xFF, 0x00, 0x3F, 0xFF, 0xFE, 0x07, 0xFF, 0x03, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0x2F, + 0xFF, 0xFE, 0x03, 0xFF, 0xFE, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0x82, 0xFF, 0xFF, + 0x00, 0x3F, 0xFF, 0x5F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xF5, 0xFF, + 0xF0, 0x00, 0x00, 0x3F, 0x41, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x3E, + 0xBF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_12_regularGlyphs[] = { @@ -3668,6 +3677,7 @@ static const EpdGlyph notosans_12_regularGlyphs[] = { { 12, 24, 14, 2, 21, 72, 45042 }, // ₿ { 10, 18, 12, 1, 14, 45, 45114 }, // ⃀ { 12, 3, 14, 1, 10, 9, 45159 }, // − + { 23, 23, 25, 1, 19, 133, 45168 }, // � }; static const EpdUnicodeInterval notosans_12_regularIntervals[] = { @@ -3682,13 +3692,14 @@ static const EpdUnicodeInterval notosans_12_regularIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_12_regular = { notosans_12_regularBitmaps, notosans_12_regularGlyphs, notosans_12_regularIntervals, - 11, + 12, 34, 27, -8, diff --git a/lib/EpdFont/builtinFonts/notosans_14_bold.h b/lib/EpdFont/builtinFonts/notosans_14_bold.h index 968dbb73..1f6931e1 100644 --- a/lib/EpdFont/builtinFonts/notosans_14_bold.h +++ b/lib/EpdFont/builtinFonts/notosans_14_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_14_boldBitmaps[67224] = { +static const uint8_t notosans_14_boldBitmaps[67413] = { 0x7F, 0xD7, 0xFE, 0x3F, 0xD3, 0xFD, 0x3F, 0xD3, 0xFD, 0x3F, 0xD3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x2F, 0xC2, 0xFC, 0x00, 0x00, 0x00, 0x05, 0x03, 0xFD, 0x7F, 0xE7, 0xFE, 0x3F, 0xC0, 0x50, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0x82, 0xFC, 0x3F, 0x82, 0xFC, @@ -4209,7 +4209,19 @@ static const uint8_t notosans_14_boldBitmaps[67224] = { 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x03, 0xFF, 0x95, 0xB8, 0x1F, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xF8, 0x00, 0xBF, 0xFE, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x06, 0xAA, 0xAA, 0xA8, 0xBF, 0xFF, 0xFF, 0xCB, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xFF, 0xFF, 0xF6, 0xFF, 0xFF, 0xFF, - 0xEB, 0xFF, 0xFF, 0xFF, 0x85, 0x55, 0x55, 0x54, + 0xEB, 0xFF, 0xFF, 0xFF, 0x85, 0x55, 0x55, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xD0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xD0, 0x00, + 0x00, 0x00, 0x0F, 0xE9, 0x6F, 0xD0, 0x00, 0x00, 0x00, 0xF4, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0x0F, + 0xC0, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0xFF, 0x86, 0xE0, 0x2F, 0xD0, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, + 0x7F, 0xD0, 0x00, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xD0, 0x0F, 0xFF, 0xFF, 0xF4, 0x0F, 0xFF, 0xD0, + 0xFF, 0xFF, 0xFF, 0x40, 0xBF, 0xFF, 0xD7, 0xFF, 0xFF, 0xF4, 0x0B, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, + 0x80, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xF8, 0x2F, 0xFF, + 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, + 0x07, 0xFD, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xF0, 0x0F, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xD0, + 0x3F, 0x80, 0x00, 0x00, 0x00, 0x07, 0xD7, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_14_boldGlyphs[] = { @@ -5047,6 +5059,7 @@ static const EpdGlyph notosans_14_boldGlyphs[] = { { 14, 27, 17, 2, 24, 95, 67033 }, // ₿ { 14, 23, 15, 1, 17, 81, 67128 }, // ⃀ { 15, 4, 17, 1, 12, 15, 67209 }, // − + { 27, 28, 29, 1, 23, 189, 67224 }, // � }; static const EpdUnicodeInterval notosans_14_boldIntervals[] = { @@ -5061,13 +5074,14 @@ static const EpdUnicodeInterval notosans_14_boldIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_14_bold = { notosans_14_boldBitmaps, notosans_14_boldGlyphs, notosans_14_boldIntervals, - 11, + 12, 40, 32, -9, diff --git a/lib/EpdFont/builtinFonts/notosans_14_bolditalic.h b/lib/EpdFont/builtinFonts/notosans_14_bolditalic.h index b7ab87aa..a867cf01 100644 --- a/lib/EpdFont/builtinFonts/notosans_14_bolditalic.h +++ b/lib/EpdFont/builtinFonts/notosans_14_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_14_bolditalicBitmaps[71405] = { +static const uint8_t notosans_14_bolditalicBitmaps[71594] = { 0x00, 0xBF, 0xC0, 0x0F, 0xFC, 0x00, 0xFF, 0x80, 0x0F, 0xF4, 0x01, 0xFF, 0x00, 0x2F, 0xF0, 0x02, 0xFE, 0x00, 0x3F, 0xD0, 0x03, 0xFC, 0x00, 0x3F, 0xC0, 0x07, 0xF8, 0x00, 0xBF, 0x40, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0xFC, 0x00, 0xBF, 0xD0, 0x0B, @@ -4470,7 +4470,19 @@ static const uint8_t notosans_14_bolditalicBitmaps[71405] = { 0x00, 0x1F, 0xE0, 0x7F, 0xD0, 0x0B, 0xF4, 0x0F, 0xF8, 0x03, 0xFC, 0x03, 0xFE, 0x00, 0xFF, 0x00, 0xFF, 0x80, 0x7F, 0xC0, 0xBF, 0xD0, 0x1F, 0xFA, 0xFF, 0xF0, 0x0B, 0xFF, 0xFF, 0xF4, 0x03, 0xFF, 0xFF, 0xF4, 0x00, 0xFF, 0xFF, 0xD0, 0x00, 0x03, 0xC3, 0xC0, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, - 0x38, 0x38, 0x00, 0x00, 0x2A, 0xAA, 0x4F, 0xFF, 0xE3, 0xFF, 0xF5, 0xFF, 0xFC, + 0x38, 0x38, 0x00, 0x00, 0x2A, 0xAA, 0x4F, 0xFF, 0xE3, 0xFF, 0xF5, 0xFF, 0xFC, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xD0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xD0, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x0F, 0xE9, 0x6F, 0xD0, 0x00, 0x00, 0x00, 0xF4, 0x00, + 0x0F, 0xD0, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0xFF, 0x86, 0xE0, 0x2F, 0xD0, + 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x7F, 0xD0, 0x00, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xD0, 0x0F, 0xFF, + 0xFF, 0xF4, 0x0F, 0xFF, 0xD0, 0xFF, 0xFF, 0xFF, 0x40, 0xBF, 0xFF, 0xD7, 0xFF, 0xFF, 0xF4, 0x0B, + 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0x80, + 0x07, 0xFF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, + 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFD, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xF0, 0x0F, 0xF8, + 0x00, 0x00, 0x00, 0x07, 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x07, 0xD7, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_14_bolditalicGlyphs[] = { @@ -5307,6 +5319,7 @@ static const EpdGlyph notosans_14_bolditalicGlyphs[] = { { 20, 24, 18, -1, 24, 120, 71161 }, // ₾ { 17, 27, 16, 0, 24, 115, 71281 }, // ₿ { 9, 4, 9, 0, 10, 9, 71396 }, // − + { 27, 28, 29, 1, 23, 189, 71405 }, // � }; static const EpdUnicodeInterval notosans_14_bolditalicIntervals[] = { @@ -5321,13 +5334,14 @@ static const EpdUnicodeInterval notosans_14_bolditalicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_14_bolditalic = { notosans_14_bolditalicBitmaps, notosans_14_bolditalicGlyphs, notosans_14_bolditalicIntervals, - 11, + 12, 40, 32, -9, diff --git a/lib/EpdFont/builtinFonts/notosans_14_italic.h b/lib/EpdFont/builtinFonts/notosans_14_italic.h index d0091c08..b112b3ae 100644 --- a/lib/EpdFont/builtinFonts/notosans_14_italic.h +++ b/lib/EpdFont/builtinFonts/notosans_14_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_14_italicBitmaps[65135] = { +static const uint8_t notosans_14_italicBitmaps[65324] = { 0x00, 0x3F, 0x00, 0x1F, 0x80, 0x0B, 0xD0, 0x02, 0xF0, 0x00, 0xFC, 0x00, 0x3E, 0x00, 0x0F, 0x40, 0x07, 0xC0, 0x02, 0xF0, 0x00, 0xF8, 0x00, 0x3D, 0x00, 0x0F, 0x00, 0x07, 0xC0, 0x01, 0xE0, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x03, 0xF0, 0x01, 0xFC, 0x00, 0x7F, 0x00, 0x05, @@ -4078,7 +4078,19 @@ static const uint8_t notosans_14_italicBitmaps[65135] = { 0x0B, 0xFF, 0xFD, 0x00, 0x0F, 0xC0, 0x6F, 0x80, 0x0F, 0x80, 0x0B, 0xD0, 0x0F, 0x40, 0x03, 0xE0, 0x1F, 0x00, 0x03, 0xE0, 0x2F, 0x00, 0x03, 0xE0, 0x3E, 0x00, 0x07, 0xD0, 0x3E, 0x00, 0x0F, 0xC0, 0x7D, 0x01, 0xBF, 0x40, 0x7F, 0xFF, 0xFD, 0x00, 0xBF, 0xFF, 0xD0, 0x00, 0x07, 0x4B, 0x00, 0x00, - 0x0B, 0x0F, 0x00, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x3F, 0xFF, 0x0F, 0xFF, 0xC1, 0x55, 0x50, + 0x0B, 0x0F, 0x00, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x3F, 0xFF, 0x0F, 0xFF, 0xC1, 0x55, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xD0, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x0F, 0xE9, 0x6F, 0xD0, 0x00, 0x00, 0x00, + 0xF4, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0xFF, 0x86, 0xE0, + 0x2F, 0xD0, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x7F, 0xD0, 0x00, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xD0, + 0x0F, 0xFF, 0xFF, 0xF4, 0x0F, 0xFF, 0xD0, 0xFF, 0xFF, 0xFF, 0x40, 0xBF, 0xFF, 0xD7, 0xFF, 0xFF, + 0xF4, 0x0B, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFE, 0x07, 0xFF, + 0xFF, 0x80, 0x07, 0xFF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, + 0x07, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFD, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xF0, + 0x0F, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x07, 0xD7, 0xF8, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_14_italicGlyphs[] = { @@ -4915,6 +4927,7 @@ static const EpdGlyph notosans_14_italicGlyphs[] = { { 20, 24, 17, -1, 24, 120, 64900 }, // ₾ { 16, 27, 16, 1, 24, 108, 65020 }, // ₿ { 9, 3, 9, 0, 9, 7, 65128 }, // − + { 27, 28, 29, 1, 23, 189, 65135 }, // � }; static const EpdUnicodeInterval notosans_14_italicIntervals[] = { @@ -4929,13 +4942,14 @@ static const EpdUnicodeInterval notosans_14_italicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_14_italic = { notosans_14_italicBitmaps, notosans_14_italicGlyphs, notosans_14_italicIntervals, - 11, + 12, 40, 32, -9, diff --git a/lib/EpdFont/builtinFonts/notosans_14_regular.h b/lib/EpdFont/builtinFonts/notosans_14_regular.h index 429c50d0..edc03246 100644 --- a/lib/EpdFont/builtinFonts/notosans_14_regular.h +++ b/lib/EpdFont/builtinFonts/notosans_14_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_14_regularBitmaps[61202] = { +static const uint8_t notosans_14_regularBitmaps[61391] = { 0xBD, 0xBD, 0xBD, 0x7D, 0x7D, 0x7C, 0x7C, 0x7C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x14, 0xBE, 0xFE, 0xBD, 0x14, 0x3E, 0x0B, 0xCF, 0x82, 0xF3, 0xD0, 0xBC, 0xF4, 0x2E, 0x3D, 0x07, 0x8B, 0x41, 0xE2, 0xC0, 0x78, 0x60, 0x09, 0x00, 0x02, 0xC0, 0x1D, 0x00, 0x00, 0x0F, 0x00, @@ -3833,7 +3833,18 @@ static const uint8_t notosans_14_regularBitmaps[61202] = { 0x00, 0x00, 0xBC, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x1F, 0xD0, 0x05, 0x07, 0xFF, 0xFE, 0x00, 0xBF, 0xFD, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFE, 0x7F, 0xFF, 0xFE, 0x15, 0x55, 0x54, 0x15, 0x55, 0x55, 0x52, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, - 0xFF, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x0F, 0xE9, 0x6F, 0xD0, + 0x00, 0x00, 0x00, 0xF4, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x0F, 0xD0, 0x00, 0x00, + 0xFF, 0x86, 0xE0, 0x2F, 0xD0, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x7F, 0xD0, 0x00, 0xFF, 0xFF, 0xFF, + 0x02, 0xFF, 0xD0, 0x0F, 0xFF, 0xFF, 0xF4, 0x0F, 0xFF, 0xD0, 0xFF, 0xFF, 0xFF, 0x40, 0xBF, 0xFF, + 0xD7, 0xFF, 0xFF, 0xF4, 0x0B, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, + 0xFE, 0x07, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, + 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFD, 0x07, 0xFF, 0x80, 0x00, + 0x00, 0x07, 0xF0, 0x0F, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x07, + 0xD7, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_14_regularGlyphs[] = { @@ -4671,6 +4682,7 @@ static const EpdGlyph notosans_14_regularGlyphs[] = { { 14, 27, 17, 2, 24, 95, 61032 }, // ₿ { 12, 21, 14, 1, 16, 63, 61127 }, // ⃀ { 15, 3, 17, 1, 12, 12, 61190 }, // − + { 27, 28, 29, 1, 23, 189, 61202 }, // � }; static const EpdUnicodeInterval notosans_14_regularIntervals[] = { @@ -4685,13 +4697,14 @@ static const EpdUnicodeInterval notosans_14_regularIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_14_regular = { notosans_14_regularBitmaps, notosans_14_regularGlyphs, notosans_14_regularIntervals, - 11, + 12, 40, 32, -9, diff --git a/lib/EpdFont/builtinFonts/notosans_16_bold.h b/lib/EpdFont/builtinFonts/notosans_16_bold.h index 29b0bd21..b273a2f7 100644 --- a/lib/EpdFont/builtinFonts/notosans_16_bold.h +++ b/lib/EpdFont/builtinFonts/notosans_16_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_16_boldBitmaps[86944] = { +static const uint8_t notosans_16_boldBitmaps[87192] = { 0x3F, 0xF4, 0xFF, 0xD3, 0xFF, 0x4F, 0xFD, 0x3F, 0xF4, 0xFF, 0xD3, 0xFF, 0x0F, 0xFC, 0x2F, 0xF0, 0xBF, 0xC2, 0xFF, 0x0B, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xF8, 0x05, 0x40, 0x00, 0x00, 0x00, 0x07, 0xF8, 0x3F, 0xF4, 0xFF, 0xE3, 0xFF, 0x4B, 0xFC, 0x01, 0x40, 0xFF, 0x82, 0xFE, 0xFF, @@ -5442,6 +5442,22 @@ static const uint8_t notosans_16_boldBitmaps[86944] = { 0xFF, 0xE0, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x55, 0x55, 0x54, 0x7F, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFC, 0x2A, 0xAA, 0xAA, 0xAA, 0x5F, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE4, 0x06, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0xFF, + 0xC1, 0xA8, 0x03, 0xFD, 0x00, 0x00, 0x0F, 0xFF, 0xBF, 0xF4, 0x0B, 0xFD, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xE0, 0x2F, 0xFD, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFD, 0x00, 0xFF, 0xFF, 0xFF, + 0xF0, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFD, 0x3F, 0xFF, 0xFF, 0xF0, + 0x07, 0xFF, 0xFF, 0xF4, 0x3F, 0xFF, 0xFF, 0x80, 0xBF, 0xFF, 0xFF, 0x40, 0x3F, 0xFF, 0xFD, 0x03, + 0xFF, 0xFF, 0xF4, 0x00, 0x3F, 0xFF, 0xF4, 0x1F, 0xFF, 0xFF, 0x40, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF4, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x3F, 0xFF, 0x5B, 0xFF, + 0xF4, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x0F, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x2F, 0xF4, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x5B, 0xF4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_16_boldGlyphs[] = { @@ -6279,6 +6295,7 @@ static const EpdGlyph notosans_16_boldGlyphs[] = { { 15, 32, 19, 3, 28, 120, 86702 }, // ₿ { 16, 25, 17, 1, 19, 100, 86822 }, // ⃀ { 17, 5, 19, 1, 14, 22, 86922 }, // − + { 31, 32, 33, 1, 26, 248, 86944 }, // � }; static const EpdUnicodeInterval notosans_16_boldIntervals[] = { @@ -6293,13 +6310,14 @@ static const EpdUnicodeInterval notosans_16_boldIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_16_bold = { notosans_16_boldBitmaps, notosans_16_boldGlyphs, notosans_16_boldIntervals, - 11, + 12, 45, 36, -10, diff --git a/lib/EpdFont/builtinFonts/notosans_16_bolditalic.h b/lib/EpdFont/builtinFonts/notosans_16_bolditalic.h index 8b0d1e85..e92077e2 100644 --- a/lib/EpdFont/builtinFonts/notosans_16_bolditalic.h +++ b/lib/EpdFont/builtinFonts/notosans_16_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_16_bolditalicBitmaps[92423] = { +static const uint8_t notosans_16_bolditalicBitmaps[92671] = { 0x00, 0x3F, 0xF4, 0x01, 0xFF, 0xD0, 0x07, 0xFF, 0x00, 0x2F, 0xF8, 0x00, 0xFF, 0xD0, 0x03, 0xFF, 0x00, 0x0F, 0xFC, 0x00, 0x7F, 0xE0, 0x01, 0xFF, 0x40, 0x0B, 0xFC, 0x00, 0x3F, 0xF0, 0x00, 0xFF, 0x80, 0x03, 0xFD, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0xC0, 0x02, 0xFE, 0x00, 0x01, 0x50, 0x00, 0x00, @@ -5784,7 +5784,22 @@ static const uint8_t notosans_16_bolditalicBitmaps[92423] = { 0xFE, 0x07, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xFE, 0x00, 0xBF, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFF, 0x40, 0x00, 0x01, 0xF0, 0xF4, 0x00, 0x00, 0x07, 0x83, 0xC0, 0x00, 0x00, 0x2E, 0x1F, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x2F, 0xFF, 0xF3, 0xFF, 0xFE, 0x3F, - 0xFF, 0xD7, 0xFF, 0xFD, 0x00, 0x00, 0x00, + 0xFF, 0xD7, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0F, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0xE4, 0x06, 0xFD, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x0F, 0xE0, + 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0xFF, 0xC1, 0xA8, 0x03, 0xFD, 0x00, 0x00, 0x0F, 0xFF, 0xBF, + 0xF4, 0x0B, 0xFD, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE0, 0x2F, 0xFD, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, + 0x00, 0xFF, 0xFD, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, + 0x7F, 0xFF, 0xFD, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF4, 0x3F, 0xFF, 0xFF, 0x80, 0xBF, + 0xFF, 0xFF, 0x40, 0x3F, 0xFF, 0xFD, 0x03, 0xFF, 0xFF, 0xF4, 0x00, 0x3F, 0xFF, 0xF4, 0x1F, 0xFF, + 0xFF, 0x40, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, + 0x40, 0x00, 0x00, 0x3F, 0xFF, 0x5B, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x0F, 0xFF, 0x40, + 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x2F, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0xFF, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x3F, 0x5B, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3F, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_16_bolditalicGlyphs[] = { @@ -6621,6 +6636,7 @@ static const EpdGlyph notosans_16_bolditalicGlyphs[] = { { 23, 28, 20, -1, 28, 161, 92097 }, // ₾ { 19, 32, 18, 0, 28, 152, 92258 }, // ₿ { 10, 5, 11, 0, 11, 13, 92410 }, // − + { 31, 32, 33, 1, 26, 248, 92423 }, // � }; static const EpdUnicodeInterval notosans_16_bolditalicIntervals[] = { @@ -6635,13 +6651,14 @@ static const EpdUnicodeInterval notosans_16_bolditalicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_16_bolditalic = { notosans_16_bolditalicBitmaps, notosans_16_bolditalicGlyphs, notosans_16_bolditalicIntervals, - 11, + 12, 45, 36, -10, diff --git a/lib/EpdFont/builtinFonts/notosans_16_italic.h b/lib/EpdFont/builtinFonts/notosans_16_italic.h index fed176a0..86fedbfb 100644 --- a/lib/EpdFont/builtinFonts/notosans_16_italic.h +++ b/lib/EpdFont/builtinFonts/notosans_16_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_16_italicBitmaps[83982] = { +static const uint8_t notosans_16_italicBitmaps[84230] = { 0x00, 0x1F, 0xC0, 0x02, 0xFC, 0x00, 0x3F, 0x80, 0x03, 0xF4, 0x00, 0x3F, 0x00, 0x07, 0xF0, 0x00, 0xBE, 0x00, 0x0B, 0xD0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x40, 0x02, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xE0, 0x00, 0x3D, 0x00, 0x07, 0xC0, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, @@ -5256,7 +5256,23 @@ static const uint8_t notosans_16_italicBitmaps[83982] = { 0x00, 0x7F, 0x01, 0xF8, 0x00, 0x07, 0xE0, 0x1F, 0x40, 0x00, 0xBE, 0x02, 0xF4, 0x00, 0x0F, 0xC0, 0x3F, 0x00, 0x07, 0xF8, 0x03, 0xFA, 0xAB, 0xFF, 0x00, 0x7F, 0xFF, 0xFF, 0x80, 0x0B, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xC2, 0xD0, 0x00, 0x00, 0x3C, 0x3C, 0x00, 0x00, 0x07, 0x83, 0xC0, 0x00, 0x00, - 0x10, 0x10, 0x00, 0x00, 0x05, 0x55, 0x42, 0xFF, 0xFC, 0x3F, 0xFF, 0xC1, 0x55, 0x54, + 0x10, 0x10, 0x00, 0x00, 0x05, 0x55, 0x42, 0xFF, 0xFC, 0x3F, 0xFF, 0xC1, 0x55, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE4, 0x06, 0xFD, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, + 0x00, 0xFD, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0xFF, 0xC1, 0xA8, + 0x03, 0xFD, 0x00, 0x00, 0x0F, 0xFF, 0xBF, 0xF4, 0x0B, 0xFD, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE0, + 0x2F, 0xFD, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFD, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, + 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFD, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, + 0xFF, 0xF4, 0x3F, 0xFF, 0xFF, 0x80, 0xBF, 0xFF, 0xFF, 0x40, 0x3F, 0xFF, 0xFD, 0x03, 0xFF, 0xFF, + 0xF4, 0x00, 0x3F, 0xFF, 0xF4, 0x1F, 0xFF, 0xFF, 0x40, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, + 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x3F, 0xFF, 0x5B, 0xFF, 0xF4, 0x00, + 0x00, 0x00, 0x3F, 0xF0, 0x0F, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x2F, 0xF4, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x5B, 0xF4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_16_italicGlyphs[] = { @@ -6093,6 +6109,7 @@ static const EpdGlyph notosans_16_italicGlyphs[] = { { 22, 28, 20, -1, 28, 154, 83674 }, // ₾ { 18, 32, 18, 1, 28, 144, 83828 }, // ₿ { 10, 4, 10, 0, 11, 10, 83972 }, // − + { 31, 32, 33, 1, 26, 248, 83982 }, // � }; static const EpdUnicodeInterval notosans_16_italicIntervals[] = { @@ -6107,13 +6124,14 @@ static const EpdUnicodeInterval notosans_16_italicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_16_italic = { notosans_16_italicBitmaps, notosans_16_italicGlyphs, notosans_16_italicIntervals, - 11, + 12, 45, 36, -10, diff --git a/lib/EpdFont/builtinFonts/notosans_16_regular.h b/lib/EpdFont/builtinFonts/notosans_16_regular.h index 1604c06d..a2ee89ff 100644 --- a/lib/EpdFont/builtinFonts/notosans_16_regular.h +++ b/lib/EpdFont/builtinFonts/notosans_16_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_16_regularBitmaps[78480] = { +static const uint8_t notosans_16_regularBitmaps[78728] = { 0x3F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xF0, 0xF8, 0x2E, 0x0B, 0x82, 0xE0, 0xB8, 0x2D, 0x01, 0x00, 0x00, 0x00, 0x3F, 0x2F, 0xDB, 0xF9, 0xFC, 0x04, 0x00, 0xBC, 0x0B, 0xDB, 0xC0, 0xBD, 0xBC, 0x0B, 0xDB, 0xC0, 0x7C, 0xBC, 0x07, 0xC7, 0xC0, 0x7C, 0x7C, @@ -4913,6 +4913,22 @@ static const uint8_t notosans_16_regularBitmaps[78480] = { 0x2F, 0x80, 0x00, 0x01, 0xFD, 0x00, 0x00, 0x0B, 0xF9, 0x06, 0xD0, 0x2F, 0xFF, 0xFD, 0x00, 0x7F, 0xFF, 0x80, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x55, 0x55, 0x54, 0x3F, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFD, 0x7F, 0xFF, 0xFF, 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xD1, 0x55, 0x55, 0x55, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE4, 0x06, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0xFF, + 0xC1, 0xA8, 0x03, 0xFD, 0x00, 0x00, 0x0F, 0xFF, 0xBF, 0xF4, 0x0B, 0xFD, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xE0, 0x2F, 0xFD, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFD, 0x00, 0xFF, 0xFF, 0xFF, + 0xF0, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFD, 0x3F, 0xFF, 0xFF, 0xF0, + 0x07, 0xFF, 0xFF, 0xF4, 0x3F, 0xFF, 0xFF, 0x80, 0xBF, 0xFF, 0xFF, 0x40, 0x3F, 0xFF, 0xFD, 0x03, + 0xFF, 0xFF, 0xF4, 0x00, 0x3F, 0xFF, 0xF4, 0x1F, 0xFF, 0xFF, 0x40, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF4, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x3F, 0xFF, 0x5B, 0xFF, + 0xF4, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x0F, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x2F, 0xF4, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x5B, 0xF4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_16_regularGlyphs[] = { @@ -5750,6 +5766,7 @@ static const EpdGlyph notosans_16_regularGlyphs[] = { { 15, 32, 19, 3, 28, 120, 78263 }, // ₿ { 14, 24, 16, 1, 19, 84, 78383 }, // ⃀ { 17, 3, 19, 1, 13, 13, 78467 }, // − + { 31, 32, 33, 1, 26, 248, 78480 }, // � }; static const EpdUnicodeInterval notosans_16_regularIntervals[] = { @@ -5764,13 +5781,14 @@ static const EpdUnicodeInterval notosans_16_regularIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_16_regular = { notosans_16_regularBitmaps, notosans_16_regularGlyphs, notosans_16_regularIntervals, - 11, + 12, 45, 36, -10, diff --git a/lib/EpdFont/builtinFonts/notosans_18_bold.h b/lib/EpdFont/builtinFonts/notosans_18_bold.h index b3e925e8..982b1dcc 100644 --- a/lib/EpdFont/builtinFonts/notosans_18_bold.h +++ b/lib/EpdFont/builtinFonts/notosans_18_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_18_boldBitmaps[108125] = { +static const uint8_t notosans_18_boldBitmaps[108432] = { 0xBF, 0xF7, 0xFF, 0xDF, 0xFF, 0x6F, 0xFD, 0xBF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFC, 0x7F, 0xF1, 0xFF, 0xC7, 0xFF, 0x1F, 0xFC, 0x7F, 0xF0, 0xFF, 0xC3, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x81, 0x54, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x0B, 0xFF, 0x3F, 0xFD, 0xFF, 0xF7, 0xFF, 0xD7, 0xFE, 0x01, @@ -6765,7 +6765,26 @@ static const uint8_t notosans_18_boldBitmaps[108125] = { 0xF8, 0x00, 0x1F, 0xFF, 0xFD, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xC2, 0xAA, 0xAA, 0xAA, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, - 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, + 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFA, 0xFF, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFC, 0x00, + 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x01, 0xFF, + 0xD0, 0x6A, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0xDF, 0xFE, 0x00, 0xFF, 0xE0, 0x00, 0x01, + 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xE0, + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, + 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFF, 0xE2, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, + 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0x40, 0x7F, 0xFF, 0xFF, 0xF0, 0x02, 0xFF, 0xFF, 0xFC, + 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x02, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x02, 0xFF, + 0xFF, 0xEA, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, + 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xF4, 0x0F, 0xFF, 0xF0, 0x00, + 0x00, 0x00, 0x02, 0xFF, 0x80, 0x1F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFE, 0x00, 0x7F, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xFC, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF9, 0x6F, + 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_18_boldGlyphs[] = { @@ -7603,6 +7622,7 @@ static const EpdGlyph notosans_18_boldGlyphs[] = { { 18, 35, 21, 3, 31, 158, 107817 }, // ₿ { 18, 28, 20, 1, 21, 126, 107975 }, // ⃀ { 19, 5, 22, 1, 16, 24, 108101 }, // − + { 35, 35, 38, 1, 29, 307, 108125 }, // � }; static const EpdUnicodeInterval notosans_18_boldIntervals[] = { @@ -7617,13 +7637,14 @@ static const EpdUnicodeInterval notosans_18_boldIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_18_bold = { notosans_18_boldBitmaps, notosans_18_boldGlyphs, notosans_18_boldIntervals, - 11, + 12, 51, 41, -11, diff --git a/lib/EpdFont/builtinFonts/notosans_18_bolditalic.h b/lib/EpdFont/builtinFonts/notosans_18_bolditalic.h index 4a34f197..aff1b253 100644 --- a/lib/EpdFont/builtinFonts/notosans_18_bolditalic.h +++ b/lib/EpdFont/builtinFonts/notosans_18_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_18_bolditalicBitmaps[115270] = { +static const uint8_t notosans_18_bolditalicBitmaps[115577] = { 0x00, 0x1F, 0xFE, 0x00, 0x2F, 0xFE, 0x00, 0x3F, 0xFD, 0x00, 0x3F, 0xFC, 0x00, 0x3F, 0xFC, 0x00, 0x7F, 0xF8, 0x00, 0x7F, 0xF4, 0x00, 0xBF, 0xF0, 0x00, 0xFF, 0xF0, 0x00, 0xFF, 0xE0, 0x00, 0xFF, 0xD0, 0x01, 0xFF, 0xC0, 0x02, 0xFF, 0x80, 0x02, 0xFF, 0x40, 0x03, 0xFF, 0x00, 0x03, 0xFF, 0x00, @@ -7212,7 +7212,26 @@ static const uint8_t notosans_18_bolditalicBitmaps[115270] = { 0xFF, 0xFF, 0xFF, 0x40, 0x0B, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x03, 0xE0, 0xF8, 0x00, 0x00, 0x00, 0xF8, 0x3E, 0x00, 0x00, 0x00, 0x3D, 0x0F, 0x40, 0x00, 0x00, 0x1A, 0x06, 0x80, 0x00, 0x00, 0x05, 0x55, 0x54, 0x2F, 0xFF, 0xFC, 0x3F, 0xFF, 0xFC, 0x3F, 0xFF, 0xF8, - 0x3F, 0xFF, 0xF4, 0x15, 0x55, 0x50, + 0x3F, 0xFF, 0xF4, 0x15, 0x55, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFA, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xE0, + 0x00, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x00, 0x1F, + 0xF0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xD0, 0x6A, 0x00, 0x3F, 0xE0, 0x00, 0x00, + 0x1F, 0xFF, 0xDF, 0xFE, 0x00, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xE0, + 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, + 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, + 0x3F, 0xFF, 0xFF, 0xE2, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, + 0x40, 0x7F, 0xFF, 0xFF, 0xF0, 0x02, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x02, 0xFF, + 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x02, 0xFF, 0xFF, 0xEA, 0xBF, 0xFF, 0xFF, 0x00, 0x00, + 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x02, 0xFF, 0xF4, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x80, 0x1F, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xFE, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFC, 0x02, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF9, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_18_bolditalicGlyphs[] = { @@ -8049,6 +8068,7 @@ static const EpdGlyph notosans_18_bolditalicGlyphs[] = { { 26, 31, 23, -1, 31, 202, 114866 }, // ₾ { 21, 35, 21, 0, 31, 184, 115068 }, // ₿ { 12, 6, 12, 0, 13, 18, 115252 }, // − + { 35, 35, 38, 1, 29, 307, 115270 }, // � }; static const EpdUnicodeInterval notosans_18_bolditalicIntervals[] = { @@ -8063,13 +8083,14 @@ static const EpdUnicodeInterval notosans_18_bolditalicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_18_bolditalic = { notosans_18_bolditalicBitmaps, notosans_18_bolditalicGlyphs, notosans_18_bolditalicIntervals, - 11, + 12, 51, 41, -11, diff --git a/lib/EpdFont/builtinFonts/notosans_18_italic.h b/lib/EpdFont/builtinFonts/notosans_18_italic.h index 6be5ad98..723fc7d4 100644 --- a/lib/EpdFont/builtinFonts/notosans_18_italic.h +++ b/lib/EpdFont/builtinFonts/notosans_18_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_18_italicBitmaps[105127] = { +static const uint8_t notosans_18_italicBitmaps[105434] = { 0x00, 0x0B, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0xFF, 0x00, 0x07, 0xF8, 0x00, 0x1F, 0xD0, 0x00, 0xBF, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xE0, 0x00, 0x3F, 0x40, 0x01, 0xFC, 0x00, 0x0B, 0xF0, 0x00, 0x2F, 0x80, 0x00, 0xFD, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x7E, 0x00, 0x02, 0xF4, 0x00, 0x0F, @@ -6578,7 +6578,26 @@ static const uint8_t notosans_18_italicBitmaps[105127] = { 0xC0, 0x00, 0x3F, 0xC0, 0x2F, 0x80, 0x02, 0xFF, 0x40, 0x3F, 0xFF, 0xFF, 0xFD, 0x00, 0x3F, 0xFF, 0xFF, 0xF4, 0x00, 0x7F, 0xFF, 0xFE, 0x40, 0x00, 0x01, 0xF0, 0xB8, 0x00, 0x00, 0x02, 0xE0, 0xF4, 0x00, 0x00, 0x03, 0xD0, 0xF4, 0x00, 0x00, 0x02, 0x80, 0xA0, 0x00, 0x00, 0x0A, 0xAA, 0xA0, 0xBF, - 0xFF, 0xD3, 0xFF, 0xFF, 0x05, 0x55, 0x54, + 0xFF, 0xD3, 0xFF, 0xFF, 0x05, 0x55, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, + 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFA, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, + 0xE0, 0x00, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x00, + 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xD0, 0x6A, 0x00, 0x3F, 0xE0, 0x00, + 0x00, 0x1F, 0xFF, 0xDF, 0xFE, 0x00, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, + 0xE0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x7F, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFE, + 0x00, 0x3F, 0xFF, 0xFF, 0xE2, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, + 0xFF, 0x40, 0x7F, 0xFF, 0xFF, 0xF0, 0x02, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x02, + 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x02, 0xFF, 0xFF, 0xEA, 0xBF, 0xFF, 0xFF, 0x00, + 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x02, 0xFF, 0xF4, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x80, 0x1F, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFE, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFC, + 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF9, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_18_italicGlyphs[] = { @@ -7415,6 +7434,7 @@ static const EpdGlyph notosans_18_italicGlyphs[] = { { 25, 31, 22, -1, 31, 194, 104747 }, // ₾ { 20, 35, 21, 1, 31, 175, 104941 }, // ₿ { 11, 4, 12, 0, 12, 11, 105116 }, // − + { 35, 35, 38, 1, 29, 307, 105127 }, // � }; static const EpdUnicodeInterval notosans_18_italicIntervals[] = { @@ -7429,13 +7449,14 @@ static const EpdUnicodeInterval notosans_18_italicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_18_italic = { notosans_18_italicBitmaps, notosans_18_italicGlyphs, notosans_18_italicIntervals, - 11, + 12, 51, 41, -11, diff --git a/lib/EpdFont/builtinFonts/notosans_18_regular.h b/lib/EpdFont/builtinFonts/notosans_18_regular.h index a934c691..5a5eedbe 100644 --- a/lib/EpdFont/builtinFonts/notosans_18_regular.h +++ b/lib/EpdFont/builtinFonts/notosans_18_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_18_regularBitmaps[98532] = { +static const uint8_t notosans_18_regularBitmaps[98839] = { 0x2F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0xC2, 0xFC, 0x2F, 0x82, 0xF8, 0x2F, 0x82, 0xF8, 0x1F, 0x81, 0xF4, 0x1F, 0x41, 0xF4, 0x1F, 0x40, 0xF4, 0x0F, 0x40, 0xF0, 0x0F, 0x00, 0x50, 0x00, 0x00, 0x00, 0x05, 0x03, 0xFC, 0x7F, 0xD3, 0xFD, 0x3F, 0xC0, 0x50, 0x7F, 0x02, 0xF9, 0xFC, 0x0B, 0xF7, @@ -6166,7 +6166,26 @@ static const uint8_t notosans_18_regularBitmaps[98532] = { 0xBC, 0x00, 0xFF, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFD, 0x3F, 0xFF, 0xFF, 0xFD, 0x2A, 0xAA, 0xAA, 0xA8, 0x2A, 0xAA, 0xAA, 0xAA, 0xA4, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xE0, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFA, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x2F, + 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xF0, 0x00, + 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xD0, 0x6A, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x1F, 0xFF, + 0xDF, 0xFE, 0x00, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xE0, 0x00, 0x1F, + 0xFF, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, + 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, + 0xFF, 0xE2, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0x40, 0x7F, + 0xFF, 0xFF, 0xF0, 0x02, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x02, 0xFF, 0xFF, 0xF0, + 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x02, 0xFF, 0xFF, 0xEA, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x02, 0xFF, 0xF4, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x80, 0x1F, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x02, 0xFE, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFC, 0x02, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xF9, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_18_regularGlyphs[] = { @@ -7004,6 +7023,7 @@ static const EpdGlyph notosans_18_regularGlyphs[] = { { 18, 35, 21, 3, 31, 158, 98247 }, // ₿ { 16, 27, 18, 1, 21, 108, 98405 }, // ⃀ { 19, 4, 21, 1, 15, 19, 98513 }, // − + { 35, 35, 38, 1, 29, 307, 98532 }, // � }; static const EpdUnicodeInterval notosans_18_regularIntervals[] = { @@ -7018,13 +7038,14 @@ static const EpdUnicodeInterval notosans_18_regularIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_18_regular = { notosans_18_regularBitmaps, notosans_18_regularGlyphs, notosans_18_regularIntervals, - 11, + 12, 51, 41, -11, diff --git a/lib/EpdFont/builtinFonts/notosans_8_regular.h b/lib/EpdFont/builtinFonts/notosans_8_regular.h index 9296ac53..b6c07922 100644 --- a/lib/EpdFont/builtinFonts/notosans_8_regular.h +++ b/lib/EpdFont/builtinFonts/notosans_8_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_8_regularBitmaps[10949] = { +static const uint8_t notosans_8_regularBitmaps[10981] = { 0xDB, 0x6D, 0xB6, 0xC3, 0xF4, 0xDE, 0xF7, 0xBD, 0x80, 0x0D, 0x83, 0x30, 0x66, 0x3F, 0xF7, 0xFE, 0x36, 0x04, 0xC7, 0xFE, 0xFF, 0xC6, 0x40, 0xD8, 0x1B, 0x00, 0x18, 0x18, 0xFE, 0xFE, 0xD8, 0xF8, 0xFC, 0x3E, 0x1F, 0x1B, 0xFF, 0xFE, 0x38, 0x18, 0x00, 0x01, 0xE1, 0x86, 0xCC, 0x13, 0x30, 0xCD, @@ -692,7 +692,9 @@ static const uint8_t notosans_8_regularBitmaps[10949] = { 0x07, 0x01, 0xC0, 0x1B, 0x03, 0xE1, 0xFF, 0x3D, 0xED, 0xBF, 0xB6, 0xF6, 0xDE, 0x53, 0xC0, 0x1C, 0x01, 0x80, 0x3F, 0xE7, 0xFC, 0x3C, 0x3C, 0xFE, 0xFF, 0xE3, 0xE3, 0xE7, 0xFE, 0xFF, 0xE3, 0xE3, 0xE3, 0xFF, 0xFE, 0x3C, 0x3C, 0x00, 0x3F, 0x7E, 0x60, 0x60, 0xE0, 0xE0, 0x60, 0x7E, 0x3F, 0x0C, - 0x7F, 0x7E, 0x7F, 0xFF, 0xC0, + 0x7F, 0x7E, 0x7F, 0xFF, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x03, 0xE0, 0x07, 0xF0, 0x0C, 0x38, 0x1F, + 0xDC, 0x3F, 0xDE, 0x7F, 0xBF, 0x7F, 0x7F, 0x3F, 0x7E, 0x1F, 0xFC, 0x0F, 0xF8, 0x06, 0x70, 0x03, + 0xE0, 0x01, 0xC0, 0x00, 0x80, }; static const EpdGlyph notosans_8_regularGlyphs[] = { @@ -1530,6 +1532,7 @@ static const EpdGlyph notosans_8_regularGlyphs[] = { { 8, 16, 10, 1, 14, 16, 10917 }, // ₿ { 8, 13, 8, 0, 10, 13, 10933 }, // ⃀ { 9, 2, 10, 0, 7, 3, 10946 }, // − + { 16, 16, 17, 0, 13, 32, 10949 }, // � }; static const EpdUnicodeInterval notosans_8_regularIntervals[] = { @@ -1544,13 +1547,14 @@ static const EpdUnicodeInterval notosans_8_regularIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_8_regular = { notosans_8_regularBitmaps, notosans_8_regularGlyphs, notosans_8_regularIntervals, - 11, + 12, 23, 18, -5, diff --git a/lib/EpdFont/scripts/fontconvert.py b/lib/EpdFont/scripts/fontconvert.py index ca923f90..7d4274ed 100755 --- a/lib/EpdFont/scripts/fontconvert.py +++ b/lib/EpdFont/scripts/fontconvert.py @@ -99,6 +99,9 @@ intervals = [ # (0xFE30, 0xFE4F), # # CJK Compatibility Ideographs # (0xF900, 0xFAFF), + ### Specials + # Replacement Character + (0xFFFD, 0xFFFD), ] add_ints = [] diff --git a/lib/Epub/Epub.cpp b/lib/Epub/Epub.cpp index 443efd95..78607573 100644 --- a/lib/Epub/Epub.cpp +++ b/lib/Epub/Epub.cpp @@ -619,14 +619,15 @@ int Epub::getSpineIndexForTextReference() const { return 0; } -// Calculate progress in book -uint8_t Epub::calculateProgress(const int currentSpineIndex, const float currentSpineRead) const { +// Calculate progress in book (returns 0.0-1.0) +float Epub::calculateProgress(const int currentSpineIndex, const float currentSpineRead) const { const size_t bookSize = getBookSize(); if (bookSize == 0) { - return 0; + return 0.0f; } const size_t prevChapterSize = (currentSpineIndex >= 1) ? getCumulativeSpineItemSize(currentSpineIndex - 1) : 0; const size_t curChapterSize = getCumulativeSpineItemSize(currentSpineIndex) - prevChapterSize; - const size_t sectionProgSize = currentSpineRead * curChapterSize; - return round(static_cast(prevChapterSize + sectionProgSize) / bookSize * 100.0); + const float sectionProgSize = currentSpineRead * static_cast(curChapterSize); + const float totalProgress = static_cast(prevChapterSize) + sectionProgSize; + return totalProgress / static_cast(bookSize); } diff --git a/lib/Epub/Epub.h b/lib/Epub/Epub.h index 334b4220..7a21efd5 100644 --- a/lib/Epub/Epub.h +++ b/lib/Epub/Epub.h @@ -63,5 +63,5 @@ class Epub { int getSpineIndexForTextReference() const; size_t getBookSize() const; - uint8_t calculateProgress(int currentSpineIndex, float currentSpineRead) const; + float calculateProgress(int currentSpineIndex, float currentSpineRead) const; }; diff --git a/lib/GfxRenderer/GfxRenderer.cpp b/lib/GfxRenderer/GfxRenderer.cpp index 7072fed8..e5b25bee 100644 --- a/lib/GfxRenderer/GfxRenderer.cpp +++ b/lib/GfxRenderer/GfxRenderer.cpp @@ -582,7 +582,7 @@ void GfxRenderer::drawTextRotated90CW(const int fontId, const int x, const int y while ((cp = utf8NextCodepoint(reinterpret_cast(&text)))) { const EpdGlyph* glyph = font.getGlyph(cp, style); if (!glyph) { - glyph = font.getGlyph('?', style); + glyph = font.getGlyph(REPLACEMENT_GLYPH, style); } if (!glyph) { continue; @@ -760,8 +760,7 @@ void GfxRenderer::renderChar(const EpdFontFamily& fontFamily, const uint32_t cp, const bool pixelState, const EpdFontFamily::Style style) const { const EpdGlyph* glyph = fontFamily.getGlyph(cp, style); if (!glyph) { - // TODO: Replace with fallback glyph property? - glyph = fontFamily.getGlyph('?', style); + glyph = fontFamily.getGlyph(REPLACEMENT_GLYPH, style); } // no glyph? diff --git a/lib/KOReaderSync/KOReaderCredentialStore.cpp b/lib/KOReaderSync/KOReaderCredentialStore.cpp new file mode 100644 index 00000000..c5737809 --- /dev/null +++ b/lib/KOReaderSync/KOReaderCredentialStore.cpp @@ -0,0 +1,168 @@ +#include "KOReaderCredentialStore.h" + +#include +#include +#include +#include + +// Initialize the static instance +KOReaderCredentialStore KOReaderCredentialStore::instance; + +namespace { +// File format version +constexpr uint8_t KOREADER_FILE_VERSION = 1; + +// KOReader credentials file path +constexpr char KOREADER_FILE[] = "/.crosspoint/koreader.bin"; + +// Default sync server URL +constexpr char DEFAULT_SERVER_URL[] = "https://sync.koreader.rocks:443"; + +// Obfuscation key - "KOReader" in ASCII +// This is NOT cryptographic security, just prevents casual file reading +constexpr uint8_t OBFUSCATION_KEY[] = {0x4B, 0x4F, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72}; +constexpr size_t KEY_LENGTH = sizeof(OBFUSCATION_KEY); +} // namespace + +void KOReaderCredentialStore::obfuscate(std::string& data) const { + for (size_t i = 0; i < data.size(); i++) { + data[i] ^= OBFUSCATION_KEY[i % KEY_LENGTH]; + } +} + +bool KOReaderCredentialStore::saveToFile() const { + // Make sure the directory exists + SdMan.mkdir("/.crosspoint"); + + FsFile file; + if (!SdMan.openFileForWrite("KRS", KOREADER_FILE, file)) { + return false; + } + + // Write header + serialization::writePod(file, KOREADER_FILE_VERSION); + + // Write username (plaintext - not particularly sensitive) + serialization::writeString(file, username); + Serial.printf("[%lu] [KRS] Saving username: %s\n", millis(), username.c_str()); + + // Write password (obfuscated) + std::string obfuscatedPwd = password; + obfuscate(obfuscatedPwd); + serialization::writeString(file, obfuscatedPwd); + + // Write server URL + serialization::writeString(file, serverUrl); + + // Write match method + serialization::writePod(file, static_cast(matchMethod)); + + file.close(); + Serial.printf("[%lu] [KRS] Saved KOReader credentials to file\n", millis()); + return true; +} + +bool KOReaderCredentialStore::loadFromFile() { + FsFile file; + if (!SdMan.openFileForRead("KRS", KOREADER_FILE, file)) { + Serial.printf("[%lu] [KRS] No credentials file found\n", millis()); + return false; + } + + // Read and verify version + uint8_t version; + serialization::readPod(file, version); + if (version != KOREADER_FILE_VERSION) { + Serial.printf("[%lu] [KRS] Unknown file version: %u\n", millis(), version); + file.close(); + return false; + } + + // Read username + if (file.available()) { + serialization::readString(file, username); + } else { + username.clear(); + } + + // Read and deobfuscate password + if (file.available()) { + serialization::readString(file, password); + obfuscate(password); // XOR is symmetric, so same function deobfuscates + } else { + password.clear(); + } + + // Read server URL + if (file.available()) { + serialization::readString(file, serverUrl); + } else { + serverUrl.clear(); + } + + // Read match method + if (file.available()) { + uint8_t method; + serialization::readPod(file, method); + matchMethod = static_cast(method); + } else { + matchMethod = DocumentMatchMethod::FILENAME; + } + + file.close(); + Serial.printf("[%lu] [KRS] Loaded KOReader credentials for user: %s\n", millis(), username.c_str()); + return true; +} + +void KOReaderCredentialStore::setCredentials(const std::string& user, const std::string& pass) { + username = user; + password = pass; + Serial.printf("[%lu] [KRS] Set credentials for user: %s\n", millis(), user.c_str()); +} + +std::string KOReaderCredentialStore::getMd5Password() const { + if (password.empty()) { + return ""; + } + + // Calculate MD5 hash of password using ESP32's MD5Builder + MD5Builder md5; + md5.begin(); + md5.add(password.c_str()); + md5.calculate(); + + return md5.toString().c_str(); +} + +bool KOReaderCredentialStore::hasCredentials() const { return !username.empty() && !password.empty(); } + +void KOReaderCredentialStore::clearCredentials() { + username.clear(); + password.clear(); + saveToFile(); + Serial.printf("[%lu] [KRS] Cleared KOReader credentials\n", millis()); +} + +void KOReaderCredentialStore::setServerUrl(const std::string& url) { + serverUrl = url; + Serial.printf("[%lu] [KRS] Set server URL: %s\n", millis(), url.empty() ? "(default)" : url.c_str()); +} + +std::string KOReaderCredentialStore::getBaseUrl() const { + if (serverUrl.empty()) { + return DEFAULT_SERVER_URL; + } + + // Normalize URL: add http:// if no protocol specified (local servers typically don't have SSL) + if (serverUrl.find("://") == std::string::npos) { + return "http://" + serverUrl; + } + + return serverUrl; +} + +void KOReaderCredentialStore::setMatchMethod(DocumentMatchMethod method) { + matchMethod = method; + Serial.printf("[%lu] [KRS] Set match method: %s\n", millis(), + method == DocumentMatchMethod::FILENAME ? "Filename" : "Binary"); +} diff --git a/lib/KOReaderSync/KOReaderCredentialStore.h b/lib/KOReaderSync/KOReaderCredentialStore.h new file mode 100644 index 00000000..998101a2 --- /dev/null +++ b/lib/KOReaderSync/KOReaderCredentialStore.h @@ -0,0 +1,69 @@ +#pragma once +#include +#include + +// Document matching method for KOReader sync +enum class DocumentMatchMethod : uint8_t { + FILENAME = 0, // Match by filename (simpler, works across different file sources) + BINARY = 1, // Match by partial MD5 of file content (more accurate, but files must be identical) +}; + +/** + * Singleton class for storing KOReader sync credentials on the SD card. + * Credentials are stored in /sd/.crosspoint/koreader.bin with basic + * XOR obfuscation to prevent casual reading (not cryptographically secure). + */ +class KOReaderCredentialStore { + private: + static KOReaderCredentialStore instance; + std::string username; + std::string password; + std::string serverUrl; // Custom sync server URL (empty = default) + DocumentMatchMethod matchMethod = DocumentMatchMethod::FILENAME; // Default to filename for compatibility + + // Private constructor for singleton + KOReaderCredentialStore() = default; + + // XOR obfuscation (symmetric - same for encode/decode) + void obfuscate(std::string& data) const; + + public: + // Delete copy constructor and assignment + KOReaderCredentialStore(const KOReaderCredentialStore&) = delete; + KOReaderCredentialStore& operator=(const KOReaderCredentialStore&) = delete; + + // Get singleton instance + static KOReaderCredentialStore& getInstance() { return instance; } + + // Save/load from SD card + bool saveToFile() const; + bool loadFromFile(); + + // Credential management + void setCredentials(const std::string& user, const std::string& pass); + const std::string& getUsername() const { return username; } + const std::string& getPassword() const { return password; } + + // Get MD5 hash of password for API authentication + std::string getMd5Password() const; + + // Check if credentials are set + bool hasCredentials() const; + + // Clear credentials + void clearCredentials(); + + // Server URL management + void setServerUrl(const std::string& url); + const std::string& getServerUrl() const { return serverUrl; } + + // Get base URL for API calls (with http:// normalization if no protocol, falls back to default) + std::string getBaseUrl() const; + + // Document matching method + void setMatchMethod(DocumentMatchMethod method); + DocumentMatchMethod getMatchMethod() const { return matchMethod; } +}; + +// Helper macro to access credential store +#define KOREADER_STORE KOReaderCredentialStore::getInstance() diff --git a/lib/KOReaderSync/KOReaderDocumentId.cpp b/lib/KOReaderSync/KOReaderDocumentId.cpp new file mode 100644 index 00000000..2c52464c --- /dev/null +++ b/lib/KOReaderSync/KOReaderDocumentId.cpp @@ -0,0 +1,96 @@ +#include "KOReaderDocumentId.h" + +#include +#include +#include + +namespace { +// Extract filename from path (everything after last '/') +std::string getFilename(const std::string& path) { + const size_t pos = path.rfind('/'); + if (pos == std::string::npos) { + return path; + } + return path.substr(pos + 1); +} +} // namespace + +std::string KOReaderDocumentId::calculateFromFilename(const std::string& filePath) { + const std::string filename = getFilename(filePath); + if (filename.empty()) { + return ""; + } + + MD5Builder md5; + md5.begin(); + md5.add(filename.c_str()); + md5.calculate(); + + std::string result = md5.toString().c_str(); + Serial.printf("[%lu] [KODoc] Filename hash: %s (from '%s')\n", millis(), result.c_str(), filename.c_str()); + return result; +} + +size_t KOReaderDocumentId::getOffset(int i) { + // Offset = 1024 << (2*i) + // For i = -1: 1024 >> 2 = 256 + // For i >= 0: 1024 << (2*i) + if (i < 0) { + return CHUNK_SIZE >> (-2 * i); + } + return CHUNK_SIZE << (2 * i); +} + +std::string KOReaderDocumentId::calculate(const std::string& filePath) { + FsFile file; + if (!SdMan.openFileForRead("KODoc", filePath, file)) { + Serial.printf("[%lu] [KODoc] Failed to open file: %s\n", millis(), filePath.c_str()); + return ""; + } + + const size_t fileSize = file.fileSize(); + Serial.printf("[%lu] [KODoc] Calculating hash for file: %s (size: %zu)\n", millis(), filePath.c_str(), fileSize); + + // Initialize MD5 builder + MD5Builder md5; + md5.begin(); + + // Buffer for reading chunks + uint8_t buffer[CHUNK_SIZE]; + size_t totalBytesRead = 0; + + // Read from each offset (i = -1 to 10) + for (int i = -1; i < OFFSET_COUNT - 1; i++) { + const size_t offset = getOffset(i); + + // Skip if offset is beyond file size + if (offset >= fileSize) { + continue; + } + + // Seek to offset + if (!file.seekSet(offset)) { + Serial.printf("[%lu] [KODoc] Failed to seek to offset %zu\n", millis(), offset); + continue; + } + + // Read up to CHUNK_SIZE bytes + const size_t bytesToRead = std::min(CHUNK_SIZE, fileSize - offset); + const size_t bytesRead = file.read(buffer, bytesToRead); + + if (bytesRead > 0) { + md5.add(buffer, bytesRead); + totalBytesRead += bytesRead; + } + } + + file.close(); + + // Calculate final hash + md5.calculate(); + std::string result = md5.toString().c_str(); + + Serial.printf("[%lu] [KODoc] Hash calculated: %s (from %zu bytes)\n", millis(), result.c_str(), totalBytesRead); + + return result; +} diff --git a/lib/KOReaderSync/KOReaderDocumentId.h b/lib/KOReaderSync/KOReaderDocumentId.h new file mode 100644 index 00000000..2b6189e2 --- /dev/null +++ b/lib/KOReaderSync/KOReaderDocumentId.h @@ -0,0 +1,45 @@ +#pragma once +#include + +/** + * Calculate KOReader document ID (partial MD5 hash). + * + * KOReader identifies documents using a partial MD5 hash of the file content. + * The algorithm reads 1024 bytes at specific offsets and computes the MD5 hash + * of the concatenated data. + * + * Offsets are calculated as: 1024 << (2*i) for i = -1 to 10 + * Producing: 256, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, + * 16777216, 67108864, 268435456, 1073741824 bytes + * + * If an offset is beyond the file size, it is skipped. + */ +class KOReaderDocumentId { + public: + /** + * Calculate the KOReader document hash for a file (binary/content-based). + * + * @param filePath Path to the file (typically an EPUB) + * @return 32-character lowercase hex string, or empty string on failure + */ + static std::string calculate(const std::string& filePath); + + /** + * Calculate document hash from filename only (filename-based sync mode). + * This is simpler and works when files have the same name across devices. + * + * @param filePath Path to the file (only the filename portion is used) + * @return 32-character lowercase hex MD5 of the filename + */ + static std::string calculateFromFilename(const std::string& filePath); + + private: + // Size of each chunk to read at each offset + static constexpr size_t CHUNK_SIZE = 1024; + + // Number of offsets to try (i = -1 to 10, so 12 offsets) + static constexpr int OFFSET_COUNT = 12; + + // Calculate offset for index i: 1024 << (2*i) + static size_t getOffset(int i); +}; diff --git a/lib/KOReaderSync/KOReaderSyncClient.cpp b/lib/KOReaderSync/KOReaderSyncClient.cpp new file mode 100644 index 00000000..c5053c64 --- /dev/null +++ b/lib/KOReaderSync/KOReaderSyncClient.cpp @@ -0,0 +1,198 @@ +#include "KOReaderSyncClient.h" + +#include +#include +#include +#include +#include + +#include + +#include "KOReaderCredentialStore.h" + +namespace { +// Device identifier for CrossPoint reader +constexpr char DEVICE_NAME[] = "CrossPoint"; +constexpr char DEVICE_ID[] = "crosspoint-reader"; + +void addAuthHeaders(HTTPClient& http) { + http.addHeader("Accept", "application/vnd.koreader.v1+json"); + http.addHeader("x-auth-user", KOREADER_STORE.getUsername().c_str()); + http.addHeader("x-auth-key", KOREADER_STORE.getMd5Password().c_str()); +} + +bool isHttpsUrl(const std::string& url) { return url.rfind("https://", 0) == 0; } +} // namespace + +KOReaderSyncClient::Error KOReaderSyncClient::authenticate() { + if (!KOREADER_STORE.hasCredentials()) { + Serial.printf("[%lu] [KOSync] No credentials configured\n", millis()); + return NO_CREDENTIALS; + } + + std::string url = KOREADER_STORE.getBaseUrl() + "/users/auth"; + Serial.printf("[%lu] [KOSync] Authenticating: %s\n", millis(), url.c_str()); + + HTTPClient http; + std::unique_ptr secureClient; + WiFiClient plainClient; + + if (isHttpsUrl(url)) { + secureClient.reset(new WiFiClientSecure); + secureClient->setInsecure(); + http.begin(*secureClient, url.c_str()); + } else { + http.begin(plainClient, url.c_str()); + } + addAuthHeaders(http); + + const int httpCode = http.GET(); + http.end(); + + Serial.printf("[%lu] [KOSync] Auth response: %d\n", millis(), httpCode); + + if (httpCode == 200) { + return OK; + } else if (httpCode == 401) { + return AUTH_FAILED; + } else if (httpCode < 0) { + return NETWORK_ERROR; + } + return SERVER_ERROR; +} + +KOReaderSyncClient::Error KOReaderSyncClient::getProgress(const std::string& documentHash, + KOReaderProgress& outProgress) { + if (!KOREADER_STORE.hasCredentials()) { + Serial.printf("[%lu] [KOSync] No credentials configured\n", millis()); + return NO_CREDENTIALS; + } + + std::string url = KOREADER_STORE.getBaseUrl() + "/syncs/progress/" + documentHash; + Serial.printf("[%lu] [KOSync] Getting progress: %s\n", millis(), url.c_str()); + + HTTPClient http; + std::unique_ptr secureClient; + WiFiClient plainClient; + + if (isHttpsUrl(url)) { + secureClient.reset(new WiFiClientSecure); + secureClient->setInsecure(); + http.begin(*secureClient, url.c_str()); + } else { + http.begin(plainClient, url.c_str()); + } + addAuthHeaders(http); + + const int httpCode = http.GET(); + + if (httpCode == 200) { + // Parse JSON response from response string + String responseBody = http.getString(); + http.end(); + + JsonDocument doc; + const DeserializationError error = deserializeJson(doc, responseBody); + + if (error) { + Serial.printf("[%lu] [KOSync] JSON parse failed: %s\n", millis(), error.c_str()); + return JSON_ERROR; + } + + outProgress.document = documentHash; + outProgress.progress = doc["progress"].as(); + outProgress.percentage = doc["percentage"].as(); + outProgress.device = doc["device"].as(); + outProgress.deviceId = doc["device_id"].as(); + outProgress.timestamp = doc["timestamp"].as(); + + Serial.printf("[%lu] [KOSync] Got progress: %.2f%% at %s\n", millis(), outProgress.percentage * 100, + outProgress.progress.c_str()); + return OK; + } + + http.end(); + + Serial.printf("[%lu] [KOSync] Get progress response: %d\n", millis(), httpCode); + + if (httpCode == 401) { + return AUTH_FAILED; + } else if (httpCode == 404) { + return NOT_FOUND; + } else if (httpCode < 0) { + return NETWORK_ERROR; + } + return SERVER_ERROR; +} + +KOReaderSyncClient::Error KOReaderSyncClient::updateProgress(const KOReaderProgress& progress) { + if (!KOREADER_STORE.hasCredentials()) { + Serial.printf("[%lu] [KOSync] No credentials configured\n", millis()); + return NO_CREDENTIALS; + } + + std::string url = KOREADER_STORE.getBaseUrl() + "/syncs/progress"; + Serial.printf("[%lu] [KOSync] Updating progress: %s\n", millis(), url.c_str()); + + HTTPClient http; + std::unique_ptr secureClient; + WiFiClient plainClient; + + if (isHttpsUrl(url)) { + secureClient.reset(new WiFiClientSecure); + secureClient->setInsecure(); + http.begin(*secureClient, url.c_str()); + } else { + http.begin(plainClient, url.c_str()); + } + addAuthHeaders(http); + http.addHeader("Content-Type", "application/json"); + + // Build JSON body (timestamp not required per API spec) + JsonDocument doc; + doc["document"] = progress.document; + doc["progress"] = progress.progress; + doc["percentage"] = progress.percentage; + doc["device"] = DEVICE_NAME; + doc["device_id"] = DEVICE_ID; + + std::string body; + serializeJson(doc, body); + + Serial.printf("[%lu] [KOSync] Request body: %s\n", millis(), body.c_str()); + + const int httpCode = http.PUT(body.c_str()); + http.end(); + + Serial.printf("[%lu] [KOSync] Update progress response: %d\n", millis(), httpCode); + + if (httpCode == 200 || httpCode == 202) { + return OK; + } else if (httpCode == 401) { + return AUTH_FAILED; + } else if (httpCode < 0) { + return NETWORK_ERROR; + } + return SERVER_ERROR; +} + +const char* KOReaderSyncClient::errorString(Error error) { + switch (error) { + case OK: + return "Success"; + case NO_CREDENTIALS: + return "No credentials configured"; + case NETWORK_ERROR: + return "Network error"; + case AUTH_FAILED: + return "Authentication failed"; + case SERVER_ERROR: + return "Server error (try again later)"; + case JSON_ERROR: + return "JSON parse error"; + case NOT_FOUND: + return "No progress found"; + default: + return "Unknown error"; + } +} diff --git a/lib/KOReaderSync/KOReaderSyncClient.h b/lib/KOReaderSync/KOReaderSyncClient.h new file mode 100644 index 00000000..a9bc5c09 --- /dev/null +++ b/lib/KOReaderSync/KOReaderSyncClient.h @@ -0,0 +1,59 @@ +#pragma once +#include + +/** + * Progress data from KOReader sync server. + */ +struct KOReaderProgress { + std::string document; // Document hash + std::string progress; // XPath-like progress string + float percentage; // Progress percentage (0.0 to 1.0) + std::string device; // Device name + std::string deviceId; // Device ID + int64_t timestamp; // Unix timestamp of last update +}; + +/** + * HTTP client for KOReader sync API. + * + * Base URL: https://sync.koreader.rocks:443/ + * + * API Endpoints: + * GET /users/auth - Authenticate (validate credentials) + * GET /syncs/progress/:document - Get progress for a document + * PUT /syncs/progress - Update progress for a document + * + * Authentication: + * x-auth-user: username + * x-auth-key: MD5 hash of password + */ +class KOReaderSyncClient { + public: + enum Error { OK = 0, NO_CREDENTIALS, NETWORK_ERROR, AUTH_FAILED, SERVER_ERROR, JSON_ERROR, NOT_FOUND }; + + /** + * Authenticate with the sync server (validate credentials). + * @return OK on success, error code on failure + */ + static Error authenticate(); + + /** + * Get reading progress for a document. + * @param documentHash The document hash (from KOReaderDocumentId) + * @param outProgress Output: the progress data + * @return OK on success, NOT_FOUND if no progress exists, error code on failure + */ + static Error getProgress(const std::string& documentHash, KOReaderProgress& outProgress); + + /** + * Update reading progress for a document. + * @param progress The progress data to upload + * @return OK on success, error code on failure + */ + static Error updateProgress(const KOReaderProgress& progress); + + /** + * Get human-readable error message. + */ + static const char* errorString(Error error); +}; diff --git a/lib/KOReaderSync/ProgressMapper.cpp b/lib/KOReaderSync/ProgressMapper.cpp new file mode 100644 index 00000000..2c15ab71 --- /dev/null +++ b/lib/KOReaderSync/ProgressMapper.cpp @@ -0,0 +1,112 @@ +#include "ProgressMapper.h" + +#include + +#include + +KOReaderPosition ProgressMapper::toKOReader(const std::shared_ptr& epub, const CrossPointPosition& pos) { + KOReaderPosition result; + + // Calculate page progress within current spine item + float intraSpineProgress = 0.0f; + if (pos.totalPages > 0) { + intraSpineProgress = static_cast(pos.pageNumber) / static_cast(pos.totalPages); + } + + // Calculate overall book progress (0.0-1.0) + result.percentage = epub->calculateProgress(pos.spineIndex, intraSpineProgress); + + // Generate XPath with estimated paragraph position based on page + result.xpath = generateXPath(pos.spineIndex, pos.pageNumber, pos.totalPages); + + // Get chapter info for logging + const int tocIndex = epub->getTocIndexForSpineIndex(pos.spineIndex); + const std::string chapterName = (tocIndex >= 0) ? epub->getTocItem(tocIndex).title : "unknown"; + + Serial.printf("[%lu] [ProgressMapper] CrossPoint -> KOReader: chapter='%s', page=%d/%d -> %.2f%% at %s\n", millis(), + chapterName.c_str(), pos.pageNumber, pos.totalPages, result.percentage * 100, result.xpath.c_str()); + + return result; +} + +CrossPointPosition ProgressMapper::toCrossPoint(const std::shared_ptr& epub, const KOReaderPosition& koPos, + int totalPagesInSpine) { + CrossPointPosition result; + result.spineIndex = 0; + result.pageNumber = 0; + result.totalPages = totalPagesInSpine; + + const size_t bookSize = epub->getBookSize(); + if (bookSize == 0) { + return result; + } + + // First, try to get spine index from XPath (DocFragment) + int xpathSpineIndex = parseDocFragmentIndex(koPos.xpath); + if (xpathSpineIndex >= 0 && xpathSpineIndex < epub->getSpineItemsCount()) { + result.spineIndex = xpathSpineIndex; + // When we have XPath, go to page 0 of the spine - byte-based page calculation is unreliable + result.pageNumber = 0; + } else { + // Fall back to percentage-based lookup for both spine and page + const size_t targetBytes = static_cast(bookSize * koPos.percentage); + + // Find the spine item that contains this byte position + for (int i = 0; i < epub->getSpineItemsCount(); i++) { + const size_t cumulativeSize = epub->getCumulativeSpineItemSize(i); + if (cumulativeSize >= targetBytes) { + result.spineIndex = i; + break; + } + } + + // Estimate page number within the spine item using percentage (only when no XPath) + if (totalPagesInSpine > 0 && result.spineIndex < epub->getSpineItemsCount()) { + const size_t prevCumSize = (result.spineIndex > 0) ? epub->getCumulativeSpineItemSize(result.spineIndex - 1) : 0; + const size_t currentCumSize = epub->getCumulativeSpineItemSize(result.spineIndex); + const size_t spineSize = currentCumSize - prevCumSize; + + if (spineSize > 0) { + const size_t bytesIntoSpine = (targetBytes > prevCumSize) ? (targetBytes - prevCumSize) : 0; + const float intraSpineProgress = static_cast(bytesIntoSpine) / static_cast(spineSize); + const float clampedProgress = std::max(0.0f, std::min(1.0f, intraSpineProgress)); + result.pageNumber = static_cast(clampedProgress * totalPagesInSpine); + result.pageNumber = std::max(0, std::min(result.pageNumber, totalPagesInSpine - 1)); + } + } + } + + Serial.printf("[%lu] [ProgressMapper] KOReader -> CrossPoint: %.2f%% at %s -> spine=%d, page=%d\n", millis(), + koPos.percentage * 100, koPos.xpath.c_str(), result.spineIndex, result.pageNumber); + + return result; +} + +std::string ProgressMapper::generateXPath(int spineIndex, int pageNumber, int totalPages) { + // KOReader uses 1-based DocFragment indices + // Use a simple xpath pointing to the DocFragment - KOReader will use the percentage for fine positioning + // Avoid specifying paragraph numbers as they may not exist in the target document + return "/body/DocFragment[" + std::to_string(spineIndex + 1) + "]/body"; +} + +int ProgressMapper::parseDocFragmentIndex(const std::string& xpath) { + // Look for DocFragment[N] pattern + const size_t start = xpath.find("DocFragment["); + if (start == std::string::npos) { + return -1; + } + + const size_t numStart = start + 12; // Length of "DocFragment[" + const size_t numEnd = xpath.find(']', numStart); + if (numEnd == std::string::npos) { + return -1; + } + + try { + const int docFragmentIndex = std::stoi(xpath.substr(numStart, numEnd - numStart)); + // KOReader uses 1-based indices, we use 0-based + return docFragmentIndex - 1; + } catch (...) { + return -1; + } +} diff --git a/lib/KOReaderSync/ProgressMapper.h b/lib/KOReaderSync/ProgressMapper.h new file mode 100644 index 00000000..694549da --- /dev/null +++ b/lib/KOReaderSync/ProgressMapper.h @@ -0,0 +1,72 @@ +#pragma once +#include + +#include +#include + +/** + * CrossPoint position representation. + */ +struct CrossPointPosition { + int spineIndex; // Current spine item (chapter) index + int pageNumber; // Current page within the spine item + int totalPages; // Total pages in the current spine item +}; + +/** + * KOReader position representation. + */ +struct KOReaderPosition { + std::string xpath; // XPath-like progress string + float percentage; // Progress percentage (0.0 to 1.0) +}; + +/** + * Maps between CrossPoint and KOReader position formats. + * + * CrossPoint tracks position as (spineIndex, pageNumber). + * KOReader uses XPath-like strings + percentage. + * + * Since CrossPoint discards HTML structure during parsing, we generate + * synthetic XPath strings based on spine index, using percentage as the + * primary sync mechanism. + */ +class ProgressMapper { + public: + /** + * Convert CrossPoint position to KOReader format. + * + * @param epub The EPUB book + * @param pos CrossPoint position + * @return KOReader position + */ + static KOReaderPosition toKOReader(const std::shared_ptr& epub, const CrossPointPosition& pos); + + /** + * Convert KOReader position to CrossPoint format. + * + * Note: The returned pageNumber may be approximate since different + * rendering settings produce different page counts. + * + * @param epub The EPUB book + * @param koPos KOReader position + * @param totalPagesInSpine Total pages in the target spine item (for page estimation) + * @return CrossPoint position + */ + static CrossPointPosition toCrossPoint(const std::shared_ptr& epub, const KOReaderPosition& koPos, + int totalPagesInSpine = 0); + + private: + /** + * Generate XPath for KOReader compatibility. + * Format: /body/DocFragment[spineIndex+1]/body/p[estimatedParagraph] + * Paragraph is estimated based on page position within the chapter. + */ + static std::string generateXPath(int spineIndex, int pageNumber, int totalPages); + + /** + * Parse DocFragment index from XPath string. + * Returns -1 if not found. + */ + static int parseDocFragmentIndex(const std::string& xpath); +}; diff --git a/lib/Utf8/Utf8.h b/lib/Utf8/Utf8.h index 0209bc25..095c1584 100644 --- a/lib/Utf8/Utf8.h +++ b/lib/Utf8/Utf8.h @@ -2,4 +2,6 @@ #include +#define REPLACEMENT_GLYPH 0xFFFD + uint32_t utf8NextCodepoint(const unsigned char** string); diff --git a/lib/Xtc/Xtc.cpp b/lib/Xtc/Xtc.cpp index 7205ffb9..c79421d7 100644 --- a/lib/Xtc/Xtc.cpp +++ b/lib/Xtc/Xtc.cpp @@ -203,7 +203,7 @@ bool Xtc::generateCoverBmp() const { coverBmp.write(reinterpret_cast(&colorsImportant), 4); // Color palette (2 colors for 1-bit) - // XTC uses inverted polarity: 0 = black, 1 = white + // XTC 1-bit polarity: 0 = black, 1 = white (standard BMP palette order) // Color 0: Black (text/foreground in XTC) uint8_t black[4] = {0x00, 0x00, 0x00, 0x00}; coverBmp.write(black, 4); @@ -506,8 +506,8 @@ bool Xtc::generateThumbBmp() const { // Bounds check for buffer access if (byteIdx < bitmapSize) { const uint8_t pixelBit = (pageBuffer[byteIdx] >> bitIdx) & 1; - // XTC polarity: 1=black, 0=white - grayValue = pixelBit ? 0 : 255; + // XTC 1-bit polarity: 0=black, 1=white (same as BMP palette) + grayValue = pixelBit ? 255 : 0; } } diff --git a/src/activities/home/HomeActivity.cpp b/src/activities/home/HomeActivity.cpp index 3a97e132..6f27e39c 100644 --- a/src/activities/home/HomeActivity.cpp +++ b/src/activities/home/HomeActivity.cpp @@ -325,6 +325,10 @@ void HomeActivity::render() { } if (hasContinueReading) { + // Invert text colors based on selection state: + // - With cover: selected = white text on black box, unselected = black text on white box + // - Without cover: selected = white text on black card, unselected = black text on white card + // Split into words (avoid stringstream to keep this light on the MCU) std::vector words; words.reserve(8); @@ -407,7 +411,7 @@ void HomeActivity::render() { // Vertically center the title block within the card int titleYStart = bookY + (bookHeight - totalTextHeight) / 2; - // If cover image was rendered, draw white box behind title and author + // If cover image was rendered, draw box behind title and author if (coverRendered) { constexpr int boxPadding = 8; // Calculate the max text width for the box @@ -438,14 +442,14 @@ void HomeActivity::render() { const int boxX = (pageWidth - boxWidth) / 2; const int boxY = titleYStart - boxPadding; - // Draw white filled box - renderer.fillRect(boxX, boxY, boxWidth, boxHeight, false); - // Draw black border around the box - renderer.drawRect(boxX, boxY, boxWidth, boxHeight, true); + // Draw box (inverted when selected: black box instead of white) + renderer.fillRect(boxX, boxY, boxWidth, boxHeight, bookSelected); + // Draw border around the box (inverted when selected: white border instead of black) + renderer.drawRect(boxX, boxY, boxWidth, boxHeight, !bookSelected); } for (const auto& line : lines) { - renderer.drawCenteredText(UI_12_FONT_ID, titleYStart, line.c_str(), !bookSelected || coverRendered); + renderer.drawCenteredText(UI_12_FONT_ID, titleYStart, line.c_str(), !bookSelected); titleYStart += renderer.getLineHeight(UI_12_FONT_ID); } @@ -466,13 +470,13 @@ void HomeActivity::render() { } trimmedAuthor.append("..."); } - renderer.drawCenteredText(UI_10_FONT_ID, titleYStart, trimmedAuthor.c_str(), !bookSelected || coverRendered); + renderer.drawCenteredText(UI_10_FONT_ID, titleYStart, trimmedAuthor.c_str(), !bookSelected); } // "Continue Reading" label at the bottom const int continueY = bookY + bookHeight - renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2; if (coverRendered) { - // Draw white box behind "Continue Reading" text + // Draw box behind "Continue Reading" text (inverted when selected: black box instead of white) const char* continueText = "Continue Reading"; const int continueTextWidth = renderer.getTextWidth(UI_10_FONT_ID, continueText); constexpr int continuePadding = 6; @@ -480,9 +484,9 @@ void HomeActivity::render() { const int continueBoxHeight = renderer.getLineHeight(UI_10_FONT_ID) + continuePadding; const int continueBoxX = (pageWidth - continueBoxWidth) / 2; const int continueBoxY = continueY - continuePadding / 2; - renderer.fillRect(continueBoxX, continueBoxY, continueBoxWidth, continueBoxHeight, false); - renderer.drawRect(continueBoxX, continueBoxY, continueBoxWidth, continueBoxHeight, true); - renderer.drawCenteredText(UI_10_FONT_ID, continueY, continueText, true); + renderer.fillRect(continueBoxX, continueBoxY, continueBoxWidth, continueBoxHeight, bookSelected); + renderer.drawRect(continueBoxX, continueBoxY, continueBoxWidth, continueBoxHeight, !bookSelected); + renderer.drawCenteredText(UI_10_FONT_ID, continueY, continueText, !bookSelected); } else { renderer.drawCenteredText(UI_10_FONT_ID, continueY, "Continue Reading", !bookSelected); } diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index b748fd28..d70a15c4 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -118,9 +118,11 @@ void EpubReaderActivity::loop() { if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { // Don't start activity transition while rendering xSemaphoreTake(renderingMutex, portMAX_DELAY); + const int currentPage = section ? section->currentPage : 0; + const int totalPages = section ? section->pageCount : 0; exitActivity(); enterNewActivity(new EpubReaderChapterSelectionActivity( - this->renderer, this->mappedInput, epub, currentSpineIndex, + this->renderer, this->mappedInput, epub, epub->getPath(), currentSpineIndex, currentPage, totalPages, [this] { exitActivity(); updateRequired = true; @@ -133,6 +135,16 @@ void EpubReaderActivity::loop() { } exitActivity(); updateRequired = true; + }, + [this](const int newSpineIndex, const int newPage) { + // Handle sync position + if (currentSpineIndex != newSpineIndex || (section && section->currentPage != newPage)) { + currentSpineIndex = newSpineIndex; + nextPageNumber = newPage; + section.reset(); + } + exitActivity(); + updateRequired = true; })); xSemaphoreGive(renderingMutex); } @@ -430,11 +442,13 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in if (showProgress) { // Calculate progress in book const float sectionChapterProg = static_cast(section->currentPage) / section->pageCount; - const uint8_t bookProgress = epub->calculateProgress(currentSpineIndex, sectionChapterProg); + const float bookProgress = epub->calculateProgress(currentSpineIndex, sectionChapterProg) * 100; // Right aligned text for progress counter - const std::string progress = std::to_string(section->currentPage + 1) + "/" + std::to_string(section->pageCount) + - " " + std::to_string(bookProgress) + "%"; + char progressStr[32]; + snprintf(progressStr, sizeof(progressStr), "%d/%d %.1f%%", section->currentPage + 1, section->pageCount, + bookProgress); + const std::string progress = progressStr; progressTextWidth = renderer.getTextWidth(SMALL_FONT_ID, progress.c_str()); renderer.drawText(SMALL_FONT_ID, renderer.getScreenWidth() - orientedMarginRight - progressTextWidth, textY, progress.c_str()); diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp index 8f3ecb80..f9a1aa69 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp @@ -2,6 +2,8 @@ #include +#include "KOReaderCredentialStore.h" +#include "KOReaderSyncActivity.h" #include "MappedInputManager.h" #include "fontIds.h" @@ -10,6 +12,26 @@ namespace { constexpr int SKIP_PAGE_MS = 700; } // namespace +bool EpubReaderChapterSelectionActivity::hasSyncOption() const { return KOREADER_STORE.hasCredentials(); } + +int EpubReaderChapterSelectionActivity::getTotalItems() const { + // Add 2 for sync options (top and bottom) if credentials are configured + const int syncCount = hasSyncOption() ? 2 : 0; + return epub->getTocItemsCount() + syncCount; +} + +bool EpubReaderChapterSelectionActivity::isSyncItem(int index) const { + if (!hasSyncOption()) return false; + // First item and last item are sync options + return index == 0 || index == getTotalItems() - 1; +} + +int EpubReaderChapterSelectionActivity::tocIndexFromItemIndex(int itemIndex) const { + // Account for the sync option at the top + const int offset = hasSyncOption() ? 1 : 0; + return itemIndex - offset; +} + int EpubReaderChapterSelectionActivity::getPageItems() const { // Layout constants used in renderScreen constexpr int startY = 60; @@ -34,17 +56,21 @@ void EpubReaderChapterSelectionActivity::taskTrampoline(void* param) { } void EpubReaderChapterSelectionActivity::onEnter() { - Activity::onEnter(); + ActivityWithSubactivity::onEnter(); if (!epub) { return; } renderingMutex = xSemaphoreCreateMutex(); + + // Account for sync option offset when finding current TOC index + const int syncOffset = hasSyncOption() ? 1 : 0; selectorIndex = epub->getTocIndexForSpineIndex(currentSpineIndex); if (selectorIndex == -1) { selectorIndex = 0; } + selectorIndex += syncOffset; // Offset for top sync option // Trigger first update updateRequired = true; @@ -57,7 +83,7 @@ void EpubReaderChapterSelectionActivity::onEnter() { } void EpubReaderChapterSelectionActivity::onExit() { - Activity::onExit(); + ActivityWithSubactivity::onExit(); // Wait until not rendering to delete task to avoid killing mid-instruction to EPD xSemaphoreTake(renderingMutex, portMAX_DELAY); @@ -69,7 +95,30 @@ void EpubReaderChapterSelectionActivity::onExit() { renderingMutex = nullptr; } +void EpubReaderChapterSelectionActivity::launchSyncActivity() { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + exitActivity(); + enterNewActivity(new KOReaderSyncActivity( + renderer, mappedInput, epub, epubPath, currentSpineIndex, currentPage, totalPagesInSpine, + [this]() { + // On cancel + exitActivity(); + updateRequired = true; + }, + [this](int newSpineIndex, int newPage) { + // On sync complete + exitActivity(); + onSyncPosition(newSpineIndex, newPage); + })); + xSemaphoreGive(renderingMutex); +} + void EpubReaderChapterSelectionActivity::loop() { + if (subActivity) { + subActivity->loop(); + return; + } + const bool prevReleased = mappedInput.wasReleased(MappedInputManager::Button::Up) || mappedInput.wasReleased(MappedInputManager::Button::Left); const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::Down) || @@ -77,9 +126,18 @@ void EpubReaderChapterSelectionActivity::loop() { const bool skipPage = mappedInput.getHeldTime() > SKIP_PAGE_MS; const int pageItems = getPageItems(); + const int totalItems = getTotalItems(); if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { - const auto newSpineIndex = epub->getSpineIndexForTocIndex(selectorIndex); + // Check if sync option is selected (first or last item) + if (isSyncItem(selectorIndex)) { + launchSyncActivity(); + return; + } + + // Get TOC index (account for top sync offset) + const int tocIndex = tocIndexFromItemIndex(selectorIndex); + const auto newSpineIndex = epub->getSpineIndexForTocIndex(tocIndex); if (newSpineIndex == -1) { onGoBack(); } else { @@ -89,17 +147,16 @@ void EpubReaderChapterSelectionActivity::loop() { onGoBack(); } else if (prevReleased) { if (skipPage) { - selectorIndex = - ((selectorIndex / pageItems - 1) * pageItems + epub->getTocItemsCount()) % epub->getTocItemsCount(); + selectorIndex = ((selectorIndex / pageItems - 1) * pageItems + totalItems) % totalItems; } else { - selectorIndex = (selectorIndex + epub->getTocItemsCount() - 1) % epub->getTocItemsCount(); + selectorIndex = (selectorIndex + totalItems - 1) % totalItems; } updateRequired = true; } else if (nextReleased) { if (skipPage) { - selectorIndex = ((selectorIndex / pageItems + 1) * pageItems) % epub->getTocItemsCount(); + selectorIndex = ((selectorIndex / pageItems + 1) * pageItems) % totalItems; } else { - selectorIndex = (selectorIndex + 1) % epub->getTocItemsCount(); + selectorIndex = (selectorIndex + 1) % totalItems; } updateRequired = true; } @@ -107,7 +164,7 @@ void EpubReaderChapterSelectionActivity::loop() { void EpubReaderChapterSelectionActivity::displayTaskLoop() { while (true) { - if (updateRequired) { + if (updateRequired && !subActivity) { updateRequired = false; xSemaphoreTake(renderingMutex, portMAX_DELAY); renderScreen(); @@ -122,6 +179,7 @@ void EpubReaderChapterSelectionActivity::renderScreen() { const auto pageWidth = renderer.getScreenWidth(); const int pageItems = getPageItems(); + const int totalItems = getTotalItems(); const std::string title = renderer.truncatedText(UI_12_FONT_ID, epub->getTitle().c_str(), pageWidth - 40, EpdFontFamily::BOLD); @@ -129,11 +187,20 @@ void EpubReaderChapterSelectionActivity::renderScreen() { const auto pageStartIndex = selectorIndex / pageItems * pageItems; renderer.fillRect(0, 60 + (selectorIndex % pageItems) * 30 - 2, pageWidth - 1, 30); - for (int tocIndex = pageStartIndex; tocIndex < epub->getTocItemsCount() && tocIndex < pageStartIndex + pageItems; - tocIndex++) { - auto item = epub->getTocItem(tocIndex); - renderer.drawText(UI_10_FONT_ID, 20 + (item.level - 1) * 15, 60 + (tocIndex % pageItems) * 30, item.title.c_str(), - tocIndex != selectorIndex); + + for (int itemIndex = pageStartIndex; itemIndex < totalItems && itemIndex < pageStartIndex + pageItems; itemIndex++) { + const int displayY = 60 + (itemIndex % pageItems) * 30; + const bool isSelected = (itemIndex == selectorIndex); + + if (isSyncItem(itemIndex)) { + // Draw sync option (at top or bottom) + renderer.drawText(UI_10_FONT_ID, 20, displayY, ">> Sync Progress", !isSelected); + } else { + // Draw TOC item (account for top sync offset) + const int tocIndex = tocIndexFromItemIndex(itemIndex); + auto item = epub->getTocItem(tocIndex); + renderer.drawText(UI_10_FONT_ID, 20 + (item.level - 1) * 15, displayY, item.title.c_str(), !isSelected); + } } const auto labels = mappedInput.mapLabels("« Back", "Select", "Up", "Down"); diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.h b/src/activities/reader/EpubReaderChapterSelectionActivity.h index cf3f1905..255f0cea 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.h +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.h @@ -6,36 +6,59 @@ #include -#include "../Activity.h" +#include "../ActivityWithSubactivity.h" -class EpubReaderChapterSelectionActivity final : public Activity { +class EpubReaderChapterSelectionActivity final : public ActivityWithSubactivity { std::shared_ptr epub; + std::string epubPath; TaskHandle_t displayTaskHandle = nullptr; SemaphoreHandle_t renderingMutex = nullptr; int currentSpineIndex = 0; + int currentPage = 0; + int totalPagesInSpine = 0; int selectorIndex = 0; bool updateRequired = false; const std::function onGoBack; const std::function onSelectSpineIndex; + const std::function onSyncPosition; // Number of items that fit on a page, derived from logical screen height. // This adapts automatically when switching between portrait and landscape. int getPageItems() const; + // Total items including sync options (top and bottom) + int getTotalItems() const; + + // Check if sync option is available (credentials configured) + bool hasSyncOption() const; + + // Check if given item index is a sync option (first or last) + bool isSyncItem(int index) const; + + // Convert item index to TOC index (accounting for top sync option offset) + int tocIndexFromItemIndex(int itemIndex) const; + static void taskTrampoline(void* param); [[noreturn]] void displayTaskLoop(); void renderScreen(); + void launchSyncActivity(); public: explicit EpubReaderChapterSelectionActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, - const std::shared_ptr& epub, const int currentSpineIndex, - const std::function& onGoBack, - const std::function& onSelectSpineIndex) - : Activity("EpubReaderChapterSelection", renderer, mappedInput), + const std::shared_ptr& epub, const std::string& epubPath, + const int currentSpineIndex, const int currentPage, + const int totalPagesInSpine, const std::function& onGoBack, + const std::function& onSelectSpineIndex, + const std::function& onSyncPosition) + : ActivityWithSubactivity("EpubReaderChapterSelection", renderer, mappedInput), epub(epub), + epubPath(epubPath), currentSpineIndex(currentSpineIndex), + currentPage(currentPage), + totalPagesInSpine(totalPagesInSpine), onGoBack(onGoBack), - onSelectSpineIndex(onSelectSpineIndex) {} + onSelectSpineIndex(onSelectSpineIndex), + onSyncPosition(onSyncPosition) {} void onEnter() override; void onExit() override; void loop() override; diff --git a/src/activities/reader/KOReaderSyncActivity.cpp b/src/activities/reader/KOReaderSyncActivity.cpp new file mode 100644 index 00000000..4a85f23d --- /dev/null +++ b/src/activities/reader/KOReaderSyncActivity.cpp @@ -0,0 +1,439 @@ +#include "KOReaderSyncActivity.h" + +#include +#include +#include + +#include "KOReaderCredentialStore.h" +#include "KOReaderDocumentId.h" +#include "MappedInputManager.h" +#include "activities/network/WifiSelectionActivity.h" +#include "fontIds.h" + +namespace { +void syncTimeWithNTP() { + // Stop SNTP if already running (can't reconfigure while running) + if (esp_sntp_enabled()) { + esp_sntp_stop(); + } + + // Configure SNTP + esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL); + esp_sntp_setservername(0, "pool.ntp.org"); + esp_sntp_init(); + + // Wait for time to sync (with timeout) + int retry = 0; + const int maxRetries = 50; // 5 seconds max + while (sntp_get_sync_status() != SNTP_SYNC_STATUS_COMPLETED && retry < maxRetries) { + vTaskDelay(100 / portTICK_PERIOD_MS); + retry++; + } + + if (retry < maxRetries) { + Serial.printf("[%lu] [KOSync] NTP time synced\n", millis()); + } else { + Serial.printf("[%lu] [KOSync] NTP sync timeout, using fallback\n", millis()); + } +} +} // namespace + +void KOReaderSyncActivity::taskTrampoline(void* param) { + auto* self = static_cast(param); + self->displayTaskLoop(); +} + +void KOReaderSyncActivity::onWifiSelectionComplete(const bool success) { + exitActivity(); + + if (!success) { + Serial.printf("[%lu] [KOSync] WiFi connection failed, exiting\n", millis()); + onCancel(); + return; + } + + Serial.printf("[%lu] [KOSync] WiFi connected, starting sync\n", millis()); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = SYNCING; + statusMessage = "Syncing time..."; + xSemaphoreGive(renderingMutex); + updateRequired = true; + + // Sync time with NTP before making API requests + syncTimeWithNTP(); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + statusMessage = "Calculating document hash..."; + xSemaphoreGive(renderingMutex); + updateRequired = true; + + performSync(); +} + +void KOReaderSyncActivity::performSync() { + // Calculate document hash based on user's preferred method + if (KOREADER_STORE.getMatchMethod() == DocumentMatchMethod::FILENAME) { + documentHash = KOReaderDocumentId::calculateFromFilename(epubPath); + } else { + documentHash = KOReaderDocumentId::calculate(epubPath); + } + if (documentHash.empty()) { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = SYNC_FAILED; + statusMessage = "Failed to calculate document hash"; + xSemaphoreGive(renderingMutex); + updateRequired = true; + return; + } + + Serial.printf("[%lu] [KOSync] Document hash: %s\n", millis(), documentHash.c_str()); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + statusMessage = "Fetching remote progress..."; + xSemaphoreGive(renderingMutex); + updateRequired = true; + vTaskDelay(10 / portTICK_PERIOD_MS); + + // Fetch remote progress + const auto result = KOReaderSyncClient::getProgress(documentHash, remoteProgress); + + if (result == KOReaderSyncClient::NOT_FOUND) { + // No remote progress - offer to upload + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = NO_REMOTE_PROGRESS; + hasRemoteProgress = false; + xSemaphoreGive(renderingMutex); + updateRequired = true; + return; + } + + if (result != KOReaderSyncClient::OK) { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = SYNC_FAILED; + statusMessage = KOReaderSyncClient::errorString(result); + xSemaphoreGive(renderingMutex); + updateRequired = true; + return; + } + + // Convert remote progress to CrossPoint position + hasRemoteProgress = true; + KOReaderPosition koPos = {remoteProgress.progress, remoteProgress.percentage}; + remotePosition = ProgressMapper::toCrossPoint(epub, koPos, totalPagesInSpine); + + // Calculate local progress in KOReader format (for display) + CrossPointPosition localPos = {currentSpineIndex, currentPage, totalPagesInSpine}; + localProgress = ProgressMapper::toKOReader(epub, localPos); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = SHOWING_RESULT; + selectedOption = 0; // Default to "Apply" + xSemaphoreGive(renderingMutex); + updateRequired = true; +} + +void KOReaderSyncActivity::performUpload() { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = UPLOADING; + statusMessage = "Uploading progress..."; + xSemaphoreGive(renderingMutex); + updateRequired = true; + vTaskDelay(10 / portTICK_PERIOD_MS); + + // Convert current position to KOReader format + CrossPointPosition localPos = {currentSpineIndex, currentPage, totalPagesInSpine}; + KOReaderPosition koPos = ProgressMapper::toKOReader(epub, localPos); + + KOReaderProgress progress; + progress.document = documentHash; + progress.progress = koPos.xpath; + progress.percentage = koPos.percentage; + + const auto result = KOReaderSyncClient::updateProgress(progress); + + if (result != KOReaderSyncClient::OK) { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = SYNC_FAILED; + statusMessage = KOReaderSyncClient::errorString(result); + xSemaphoreGive(renderingMutex); + updateRequired = true; + return; + } + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = UPLOAD_COMPLETE; + xSemaphoreGive(renderingMutex); + updateRequired = true; +} + +void KOReaderSyncActivity::onEnter() { + ActivityWithSubactivity::onEnter(); + + renderingMutex = xSemaphoreCreateMutex(); + + xTaskCreate(&KOReaderSyncActivity::taskTrampoline, "KOSyncTask", + 4096, // Stack size (larger for network operations) + this, // Parameters + 1, // Priority + &displayTaskHandle // Task handle + ); + + // Check for credentials first + if (!KOREADER_STORE.hasCredentials()) { + state = NO_CREDENTIALS; + updateRequired = true; + return; + } + + // Turn on WiFi + Serial.printf("[%lu] [KOSync] Turning on WiFi...\n", millis()); + WiFi.mode(WIFI_STA); + + // Check if already connected + if (WiFi.status() == WL_CONNECTED) { + Serial.printf("[%lu] [KOSync] Already connected to WiFi\n", millis()); + state = SYNCING; + statusMessage = "Syncing time..."; + updateRequired = true; + + // Perform sync directly (will be handled in loop) + xTaskCreate( + [](void* param) { + auto* self = static_cast(param); + // Sync time first + syncTimeWithNTP(); + xSemaphoreTake(self->renderingMutex, portMAX_DELAY); + self->statusMessage = "Calculating document hash..."; + xSemaphoreGive(self->renderingMutex); + self->updateRequired = true; + self->performSync(); + vTaskDelete(nullptr); + }, + "SyncTask", 4096, this, 1, nullptr); + return; + } + + // Launch WiFi selection subactivity + Serial.printf("[%lu] [KOSync] Launching WifiSelectionActivity...\n", millis()); + enterNewActivity(new WifiSelectionActivity(renderer, mappedInput, + [this](const bool connected) { onWifiSelectionComplete(connected); })); +} + +void KOReaderSyncActivity::onExit() { + ActivityWithSubactivity::onExit(); + + // Turn off wifi + WiFi.disconnect(false); + delay(100); + WiFi.mode(WIFI_OFF); + delay(100); + + // Wait until not rendering to delete task + xSemaphoreTake(renderingMutex, portMAX_DELAY); + if (displayTaskHandle) { + vTaskDelete(displayTaskHandle); + displayTaskHandle = nullptr; + } + vSemaphoreDelete(renderingMutex); + renderingMutex = nullptr; +} + +void KOReaderSyncActivity::displayTaskLoop() { + while (true) { + if (updateRequired) { + updateRequired = false; + xSemaphoreTake(renderingMutex, portMAX_DELAY); + render(); + xSemaphoreGive(renderingMutex); + } + vTaskDelay(10 / portTICK_PERIOD_MS); + } +} + +void KOReaderSyncActivity::render() { + if (subActivity) { + return; + } + + const auto pageWidth = renderer.getScreenWidth(); + + renderer.clearScreen(); + renderer.drawCenteredText(UI_12_FONT_ID, 15, "KOReader Sync", true, EpdFontFamily::BOLD); + + if (state == NO_CREDENTIALS) { + renderer.drawCenteredText(UI_10_FONT_ID, 280, "No credentials configured", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, 320, "Set up KOReader account in Settings"); + + const auto labels = mappedInput.mapLabels("Back", "", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } + + if (state == SYNCING || state == UPLOADING) { + renderer.drawCenteredText(UI_10_FONT_ID, 300, statusMessage.c_str(), true, EpdFontFamily::BOLD); + renderer.displayBuffer(); + return; + } + + if (state == SHOWING_RESULT) { + // Show comparison + renderer.drawCenteredText(UI_10_FONT_ID, 120, "Progress found!", true, EpdFontFamily::BOLD); + + // Get chapter names from TOC + const int remoteTocIndex = epub->getTocIndexForSpineIndex(remotePosition.spineIndex); + const int localTocIndex = epub->getTocIndexForSpineIndex(currentSpineIndex); + const std::string remoteChapter = (remoteTocIndex >= 0) + ? epub->getTocItem(remoteTocIndex).title + : ("Section " + std::to_string(remotePosition.spineIndex + 1)); + const std::string localChapter = (localTocIndex >= 0) ? epub->getTocItem(localTocIndex).title + : ("Section " + std::to_string(currentSpineIndex + 1)); + + // Remote progress - chapter and page + renderer.drawText(UI_10_FONT_ID, 20, 160, "Remote:", true); + char remoteChapterStr[128]; + snprintf(remoteChapterStr, sizeof(remoteChapterStr), " %s", remoteChapter.c_str()); + renderer.drawText(UI_10_FONT_ID, 20, 185, remoteChapterStr); + char remotePageStr[64]; + snprintf(remotePageStr, sizeof(remotePageStr), " Page %d, %.2f%% overall", remotePosition.pageNumber + 1, + remoteProgress.percentage * 100); + renderer.drawText(UI_10_FONT_ID, 20, 210, remotePageStr); + + if (!remoteProgress.device.empty()) { + char deviceStr[64]; + snprintf(deviceStr, sizeof(deviceStr), " From: %s", remoteProgress.device.c_str()); + renderer.drawText(UI_10_FONT_ID, 20, 235, deviceStr); + } + + // Local progress - chapter and page + renderer.drawText(UI_10_FONT_ID, 20, 270, "Local:", true); + char localChapterStr[128]; + snprintf(localChapterStr, sizeof(localChapterStr), " %s", localChapter.c_str()); + renderer.drawText(UI_10_FONT_ID, 20, 295, localChapterStr); + char localPageStr[64]; + snprintf(localPageStr, sizeof(localPageStr), " Page %d/%d, %.2f%% overall", currentPage + 1, totalPagesInSpine, + localProgress.percentage * 100); + renderer.drawText(UI_10_FONT_ID, 20, 320, localPageStr); + + // Options + const int optionY = 350; + const int optionHeight = 30; + + // Apply option + if (selectedOption == 0) { + renderer.fillRect(0, optionY - 2, pageWidth - 1, optionHeight); + } + renderer.drawText(UI_10_FONT_ID, 20, optionY, "Apply remote progress", selectedOption != 0); + + // Upload option + if (selectedOption == 1) { + renderer.fillRect(0, optionY + optionHeight - 2, pageWidth - 1, optionHeight); + } + renderer.drawText(UI_10_FONT_ID, 20, optionY + optionHeight, "Upload local progress", selectedOption != 1); + + // Cancel option + if (selectedOption == 2) { + renderer.fillRect(0, optionY + optionHeight * 2 - 2, pageWidth - 1, optionHeight); + } + renderer.drawText(UI_10_FONT_ID, 20, optionY + optionHeight * 2, "Cancel", selectedOption != 2); + + const auto labels = mappedInput.mapLabels("", "Select", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } + + if (state == NO_REMOTE_PROGRESS) { + renderer.drawCenteredText(UI_10_FONT_ID, 280, "No remote progress found", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, 320, "Upload current position?"); + + const auto labels = mappedInput.mapLabels("Cancel", "Upload", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } + + if (state == UPLOAD_COMPLETE) { + renderer.drawCenteredText(UI_10_FONT_ID, 300, "Progress uploaded!", true, EpdFontFamily::BOLD); + + const auto labels = mappedInput.mapLabels("Back", "", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } + + if (state == SYNC_FAILED) { + renderer.drawCenteredText(UI_10_FONT_ID, 280, "Sync failed", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, 320, statusMessage.c_str()); + + const auto labels = mappedInput.mapLabels("Back", "", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } +} + +void KOReaderSyncActivity::loop() { + if (subActivity) { + subActivity->loop(); + return; + } + + if (state == NO_CREDENTIALS || state == SYNC_FAILED || state == UPLOAD_COMPLETE) { + if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + onCancel(); + } + return; + } + + if (state == SHOWING_RESULT) { + // Navigate options + if (mappedInput.wasPressed(MappedInputManager::Button::Up) || + mappedInput.wasPressed(MappedInputManager::Button::Left)) { + selectedOption = (selectedOption + 2) % 3; // Wrap around + updateRequired = true; + } else if (mappedInput.wasPressed(MappedInputManager::Button::Down) || + mappedInput.wasPressed(MappedInputManager::Button::Right)) { + selectedOption = (selectedOption + 1) % 3; + updateRequired = true; + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + if (selectedOption == 0) { + // Apply remote progress + onSyncComplete(remotePosition.spineIndex, remotePosition.pageNumber); + } else if (selectedOption == 1) { + // Upload local progress + performUpload(); + } else { + // Cancel + onCancel(); + } + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + onCancel(); + } + return; + } + + if (state == NO_REMOTE_PROGRESS) { + if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + // Calculate hash if not done yet + if (documentHash.empty()) { + if (KOREADER_STORE.getMatchMethod() == DocumentMatchMethod::FILENAME) { + documentHash = KOReaderDocumentId::calculateFromFilename(epubPath); + } else { + documentHash = KOReaderDocumentId::calculate(epubPath); + } + } + performUpload(); + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + onCancel(); + } + return; + } +} diff --git a/src/activities/reader/KOReaderSyncActivity.h b/src/activities/reader/KOReaderSyncActivity.h new file mode 100644 index 00000000..dd61ffa5 --- /dev/null +++ b/src/activities/reader/KOReaderSyncActivity.h @@ -0,0 +1,98 @@ +#pragma once +#include +#include +#include +#include + +#include +#include + +#include "KOReaderSyncClient.h" +#include "ProgressMapper.h" +#include "activities/ActivityWithSubactivity.h" + +/** + * Activity for syncing reading progress with KOReader sync server. + * + * Flow: + * 1. Connect to WiFi (if not connected) + * 2. Calculate document hash + * 3. Fetch remote progress + * 4. Show comparison and options (Apply/Upload/Cancel) + * 5. Apply or upload progress + */ +class KOReaderSyncActivity final : public ActivityWithSubactivity { + public: + using OnCancelCallback = std::function; + using OnSyncCompleteCallback = std::function; + + explicit KOReaderSyncActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, + const std::shared_ptr& epub, const std::string& epubPath, int currentSpineIndex, + int currentPage, int totalPagesInSpine, OnCancelCallback onCancel, + OnSyncCompleteCallback onSyncComplete) + : ActivityWithSubactivity("KOReaderSync", renderer, mappedInput), + epub(epub), + epubPath(epubPath), + currentSpineIndex(currentSpineIndex), + currentPage(currentPage), + totalPagesInSpine(totalPagesInSpine), + remoteProgress{}, + remotePosition{}, + localProgress{}, + onCancel(std::move(onCancel)), + onSyncComplete(std::move(onSyncComplete)) {} + + void onEnter() override; + void onExit() override; + void loop() override; + bool preventAutoSleep() override { return state == CONNECTING || state == SYNCING; } + + private: + enum State { + WIFI_SELECTION, + CONNECTING, + SYNCING, + SHOWING_RESULT, + UPLOADING, + UPLOAD_COMPLETE, + NO_REMOTE_PROGRESS, + SYNC_FAILED, + NO_CREDENTIALS + }; + + std::shared_ptr epub; + std::string epubPath; + int currentSpineIndex; + int currentPage; + int totalPagesInSpine; + + TaskHandle_t displayTaskHandle = nullptr; + SemaphoreHandle_t renderingMutex = nullptr; + bool updateRequired = false; + + State state = WIFI_SELECTION; + std::string statusMessage; + std::string documentHash; + + // Remote progress data + bool hasRemoteProgress = false; + KOReaderProgress remoteProgress; + CrossPointPosition remotePosition; + + // Local progress as KOReader format (for display) + KOReaderPosition localProgress; + + // Selection in result screen (0=Apply, 1=Upload, 2=Cancel) + int selectedOption = 0; + + OnCancelCallback onCancel; + OnSyncCompleteCallback onSyncComplete; + + void onWifiSelectionComplete(bool success); + void performSync(); + void performUpload(); + + static void taskTrampoline(void* param); + [[noreturn]] void displayTaskLoop(); + void render(); +}; diff --git a/src/activities/settings/KOReaderAuthActivity.cpp b/src/activities/settings/KOReaderAuthActivity.cpp new file mode 100644 index 00000000..8681812f --- /dev/null +++ b/src/activities/settings/KOReaderAuthActivity.cpp @@ -0,0 +1,167 @@ +#include "KOReaderAuthActivity.h" + +#include +#include + +#include "KOReaderCredentialStore.h" +#include "KOReaderSyncClient.h" +#include "MappedInputManager.h" +#include "activities/network/WifiSelectionActivity.h" +#include "fontIds.h" + +void KOReaderAuthActivity::taskTrampoline(void* param) { + auto* self = static_cast(param); + self->displayTaskLoop(); +} + +void KOReaderAuthActivity::onWifiSelectionComplete(const bool success) { + exitActivity(); + + if (!success) { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = FAILED; + errorMessage = "WiFi connection failed"; + xSemaphoreGive(renderingMutex); + updateRequired = true; + return; + } + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = AUTHENTICATING; + statusMessage = "Authenticating..."; + xSemaphoreGive(renderingMutex); + updateRequired = true; + + performAuthentication(); +} + +void KOReaderAuthActivity::performAuthentication() { + const auto result = KOReaderSyncClient::authenticate(); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + if (result == KOReaderSyncClient::OK) { + state = SUCCESS; + statusMessage = "Successfully authenticated!"; + } else { + state = FAILED; + errorMessage = KOReaderSyncClient::errorString(result); + } + xSemaphoreGive(renderingMutex); + updateRequired = true; +} + +void KOReaderAuthActivity::onEnter() { + ActivityWithSubactivity::onEnter(); + + renderingMutex = xSemaphoreCreateMutex(); + + xTaskCreate(&KOReaderAuthActivity::taskTrampoline, "KOAuthTask", + 4096, // Stack size + this, // Parameters + 1, // Priority + &displayTaskHandle // Task handle + ); + + // Turn on WiFi + WiFi.mode(WIFI_STA); + + // Check if already connected + if (WiFi.status() == WL_CONNECTED) { + state = AUTHENTICATING; + statusMessage = "Authenticating..."; + updateRequired = true; + + // Perform authentication in a separate task + xTaskCreate( + [](void* param) { + auto* self = static_cast(param); + self->performAuthentication(); + vTaskDelete(nullptr); + }, + "AuthTask", 4096, this, 1, nullptr); + return; + } + + // Launch WiFi selection + enterNewActivity(new WifiSelectionActivity(renderer, mappedInput, + [this](const bool connected) { onWifiSelectionComplete(connected); })); +} + +void KOReaderAuthActivity::onExit() { + ActivityWithSubactivity::onExit(); + + // Turn off wifi + WiFi.disconnect(false); + delay(100); + WiFi.mode(WIFI_OFF); + delay(100); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + if (displayTaskHandle) { + vTaskDelete(displayTaskHandle); + displayTaskHandle = nullptr; + } + vSemaphoreDelete(renderingMutex); + renderingMutex = nullptr; +} + +void KOReaderAuthActivity::displayTaskLoop() { + while (true) { + if (updateRequired && !subActivity) { + updateRequired = false; + xSemaphoreTake(renderingMutex, portMAX_DELAY); + render(); + xSemaphoreGive(renderingMutex); + } + vTaskDelay(10 / portTICK_PERIOD_MS); + } +} + +void KOReaderAuthActivity::render() { + if (subActivity) { + return; + } + + renderer.clearScreen(); + renderer.drawCenteredText(UI_12_FONT_ID, 15, "KOReader Auth", true, EpdFontFamily::BOLD); + + if (state == AUTHENTICATING) { + renderer.drawCenteredText(UI_10_FONT_ID, 300, statusMessage.c_str(), true, EpdFontFamily::BOLD); + renderer.displayBuffer(); + return; + } + + if (state == SUCCESS) { + renderer.drawCenteredText(UI_10_FONT_ID, 280, "Success!", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, 320, "KOReader sync is ready to use"); + + const auto labels = mappedInput.mapLabels("Done", "", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } + + if (state == FAILED) { + renderer.drawCenteredText(UI_10_FONT_ID, 280, "Authentication Failed", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, 320, errorMessage.c_str()); + + const auto labels = mappedInput.mapLabels("Back", "", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } +} + +void KOReaderAuthActivity::loop() { + if (subActivity) { + subActivity->loop(); + return; + } + + if (state == SUCCESS || state == FAILED) { + if (mappedInput.wasPressed(MappedInputManager::Button::Back) || + mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + onComplete(); + } + } +} diff --git a/src/activities/settings/KOReaderAuthActivity.h b/src/activities/settings/KOReaderAuthActivity.h new file mode 100644 index 00000000..a6ed0d3e --- /dev/null +++ b/src/activities/settings/KOReaderAuthActivity.h @@ -0,0 +1,44 @@ +#pragma once +#include +#include +#include + +#include + +#include "activities/ActivityWithSubactivity.h" + +/** + * Activity for testing KOReader credentials. + * Connects to WiFi and authenticates with the KOReader sync server. + */ +class KOReaderAuthActivity final : public ActivityWithSubactivity { + public: + explicit KOReaderAuthActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, + const std::function& onComplete) + : ActivityWithSubactivity("KOReaderAuth", renderer, mappedInput), onComplete(onComplete) {} + + void onEnter() override; + void onExit() override; + void loop() override; + bool preventAutoSleep() override { return state == CONNECTING || state == AUTHENTICATING; } + + private: + enum State { WIFI_SELECTION, CONNECTING, AUTHENTICATING, SUCCESS, FAILED }; + + TaskHandle_t displayTaskHandle = nullptr; + SemaphoreHandle_t renderingMutex = nullptr; + bool updateRequired = false; + + State state = WIFI_SELECTION; + std::string statusMessage; + std::string errorMessage; + + const std::function onComplete; + + void onWifiSelectionComplete(bool success); + void performAuthentication(); + + static void taskTrampoline(void* param); + [[noreturn]] void displayTaskLoop(); + void render(); +}; diff --git a/src/activities/settings/KOReaderSettingsActivity.cpp b/src/activities/settings/KOReaderSettingsActivity.cpp new file mode 100644 index 00000000..6eb22c8e --- /dev/null +++ b/src/activities/settings/KOReaderSettingsActivity.cpp @@ -0,0 +1,213 @@ +#include "KOReaderSettingsActivity.h" + +#include + +#include + +#include "KOReaderAuthActivity.h" +#include "KOReaderCredentialStore.h" +#include "MappedInputManager.h" +#include "activities/util/KeyboardEntryActivity.h" +#include "fontIds.h" + +namespace { +constexpr int MENU_ITEMS = 5; +const char* menuNames[MENU_ITEMS] = {"Username", "Password", "Sync Server URL", "Document Matching", "Authenticate"}; +} // namespace + +void KOReaderSettingsActivity::taskTrampoline(void* param) { + auto* self = static_cast(param); + self->displayTaskLoop(); +} + +void KOReaderSettingsActivity::onEnter() { + ActivityWithSubactivity::onEnter(); + + renderingMutex = xSemaphoreCreateMutex(); + selectedIndex = 0; + updateRequired = true; + + xTaskCreate(&KOReaderSettingsActivity::taskTrampoline, "KOReaderSettingsTask", + 4096, // Stack size + this, // Parameters + 1, // Priority + &displayTaskHandle // Task handle + ); +} + +void KOReaderSettingsActivity::onExit() { + ActivityWithSubactivity::onExit(); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + if (displayTaskHandle) { + vTaskDelete(displayTaskHandle); + displayTaskHandle = nullptr; + } + vSemaphoreDelete(renderingMutex); + renderingMutex = nullptr; +} + +void KOReaderSettingsActivity::loop() { + if (subActivity) { + subActivity->loop(); + return; + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + onBack(); + return; + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + handleSelection(); + return; + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Up) || + mappedInput.wasPressed(MappedInputManager::Button::Left)) { + selectedIndex = (selectedIndex + MENU_ITEMS - 1) % MENU_ITEMS; + updateRequired = true; + } else if (mappedInput.wasPressed(MappedInputManager::Button::Down) || + mappedInput.wasPressed(MappedInputManager::Button::Right)) { + selectedIndex = (selectedIndex + 1) % MENU_ITEMS; + updateRequired = true; + } +} + +void KOReaderSettingsActivity::handleSelection() { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + + if (selectedIndex == 0) { + // Username + exitActivity(); + enterNewActivity(new KeyboardEntryActivity( + renderer, mappedInput, "KOReader Username", KOREADER_STORE.getUsername(), 10, + 64, // maxLength + false, // not password + [this](const std::string& username) { + KOREADER_STORE.setCredentials(username, KOREADER_STORE.getPassword()); + KOREADER_STORE.saveToFile(); + exitActivity(); + updateRequired = true; + }, + [this]() { + exitActivity(); + updateRequired = true; + })); + } else if (selectedIndex == 1) { + // Password + exitActivity(); + enterNewActivity(new KeyboardEntryActivity( + renderer, mappedInput, "KOReader Password", KOREADER_STORE.getPassword(), 10, + 64, // maxLength + false, // show characters + [this](const std::string& password) { + KOREADER_STORE.setCredentials(KOREADER_STORE.getUsername(), password); + KOREADER_STORE.saveToFile(); + exitActivity(); + updateRequired = true; + }, + [this]() { + exitActivity(); + updateRequired = true; + })); + } else if (selectedIndex == 2) { + // Sync Server URL - prefill with https:// if empty to save typing + const std::string currentUrl = KOREADER_STORE.getServerUrl(); + const std::string prefillUrl = currentUrl.empty() ? "https://" : currentUrl; + exitActivity(); + enterNewActivity(new KeyboardEntryActivity( + renderer, mappedInput, "Sync Server URL", prefillUrl, 10, + 128, // maxLength - URLs can be long + false, // not password + [this](const std::string& url) { + // Clear if user just left the prefilled https:// + const std::string urlToSave = (url == "https://" || url == "http://") ? "" : url; + KOREADER_STORE.setServerUrl(urlToSave); + KOREADER_STORE.saveToFile(); + exitActivity(); + updateRequired = true; + }, + [this]() { + exitActivity(); + updateRequired = true; + })); + } else if (selectedIndex == 3) { + // Document Matching - toggle between Filename and Binary + const auto current = KOREADER_STORE.getMatchMethod(); + const auto newMethod = + (current == DocumentMatchMethod::FILENAME) ? DocumentMatchMethod::BINARY : DocumentMatchMethod::FILENAME; + KOREADER_STORE.setMatchMethod(newMethod); + KOREADER_STORE.saveToFile(); + updateRequired = true; + } else if (selectedIndex == 4) { + // Authenticate + if (!KOREADER_STORE.hasCredentials()) { + // Can't authenticate without credentials - just show message briefly + xSemaphoreGive(renderingMutex); + return; + } + exitActivity(); + enterNewActivity(new KOReaderAuthActivity(renderer, mappedInput, [this] { + exitActivity(); + updateRequired = true; + })); + } + + xSemaphoreGive(renderingMutex); +} + +void KOReaderSettingsActivity::displayTaskLoop() { + while (true) { + if (updateRequired && !subActivity) { + updateRequired = false; + xSemaphoreTake(renderingMutex, portMAX_DELAY); + render(); + xSemaphoreGive(renderingMutex); + } + vTaskDelay(10 / portTICK_PERIOD_MS); + } +} + +void KOReaderSettingsActivity::render() { + renderer.clearScreen(); + + const auto pageWidth = renderer.getScreenWidth(); + + // Draw header + renderer.drawCenteredText(UI_12_FONT_ID, 15, "KOReader Sync", true, EpdFontFamily::BOLD); + + // Draw selection highlight + renderer.fillRect(0, 60 + selectedIndex * 30 - 2, pageWidth - 1, 30); + + // Draw menu items + for (int i = 0; i < MENU_ITEMS; i++) { + const int settingY = 60 + i * 30; + const bool isSelected = (i == selectedIndex); + + renderer.drawText(UI_10_FONT_ID, 20, settingY, menuNames[i], !isSelected); + + // Draw status for each item + const char* status = ""; + if (i == 0) { + status = KOREADER_STORE.getUsername().empty() ? "[Not Set]" : "[Set]"; + } else if (i == 1) { + status = KOREADER_STORE.getPassword().empty() ? "[Not Set]" : "[Set]"; + } else if (i == 2) { + status = KOREADER_STORE.getServerUrl().empty() ? "[Not Set]" : "[Set]"; + } else if (i == 3) { + status = KOREADER_STORE.getMatchMethod() == DocumentMatchMethod::FILENAME ? "[Filename]" : "[Binary]"; + } else if (i == 4) { + status = KOREADER_STORE.hasCredentials() ? "" : "[Set credentials first]"; + } + + const auto width = renderer.getTextWidth(UI_10_FONT_ID, status); + renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, settingY, status, !isSelected); + } + + // Draw button hints + const auto labels = mappedInput.mapLabels("« Back", "Select", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + + renderer.displayBuffer(); +} diff --git a/src/activities/settings/KOReaderSettingsActivity.h b/src/activities/settings/KOReaderSettingsActivity.h new file mode 100644 index 00000000..2bedf034 --- /dev/null +++ b/src/activities/settings/KOReaderSettingsActivity.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include + +#include + +#include "activities/ActivityWithSubactivity.h" + +/** + * Submenu for KOReader Sync settings. + * Shows username, password, and authenticate options. + */ +class KOReaderSettingsActivity final : public ActivityWithSubactivity { + public: + explicit KOReaderSettingsActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, + const std::function& onBack) + : ActivityWithSubactivity("KOReaderSettings", renderer, mappedInput), onBack(onBack) {} + + void onEnter() override; + void onExit() override; + void loop() override; + + private: + TaskHandle_t displayTaskHandle = nullptr; + SemaphoreHandle_t renderingMutex = nullptr; + bool updateRequired = false; + + int selectedIndex = 0; + const std::function onBack; + + static void taskTrampoline(void* param); + [[noreturn]] void displayTaskLoop(); + void render(); + void handleSelection(); +}; diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index d11e9cd3..259ca336 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -7,6 +7,7 @@ #include "CalibreSettingsActivity.h" #include "CrossPointSettings.h" +#include "KOReaderSettingsActivity.h" #include "MappedInputManager.h" #include "OtaUpdateActivity.h" #include "fontIds.h" @@ -42,6 +43,7 @@ const SettingInfo settingsList[settingsCount] = { {"1 min", "5 min", "10 min", "15 min", "30 min"}), SettingInfo::Enum("Refresh Frequency", &CrossPointSettings::refreshFrequency, {"1 page", "5 pages", "10 pages", "15 pages", "30 pages"}), + SettingInfo::Action("KOReader Sync"), SettingInfo::Action("Calibre Settings"), SettingInfo::Action("Check for updates")}; } // namespace @@ -116,7 +118,6 @@ void SettingsActivity::loop() { } void SettingsActivity::toggleCurrentSetting() { - // Validate index if (selectedSettingIndex < 0 || selectedSettingIndex >= settingsCount) { return; } @@ -140,7 +141,15 @@ void SettingsActivity::toggleCurrentSetting() { SETTINGS.*(setting.valuePtr) = currentValue + setting.valueRange.step; } } else if (setting.type == SettingType::ACTION) { - if (strcmp(setting.name, "Calibre Settings") == 0) { + if (strcmp(setting.name, "KOReader Sync") == 0) { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + exitActivity(); + enterNewActivity(new KOReaderSettingsActivity(renderer, mappedInput, [this] { + exitActivity(); + updateRequired = true; + })); + xSemaphoreGive(renderingMutex); + } else if (strcmp(setting.name, "Calibre Settings") == 0) { xSemaphoreTake(renderingMutex, portMAX_DELAY); exitActivity(); enterNewActivity(new CalibreSettingsActivity(renderer, mappedInput, [this] { @@ -187,18 +196,19 @@ void SettingsActivity::render() const { // Draw header renderer.drawCenteredText(UI_12_FONT_ID, 15, "Settings", true, EpdFontFamily::BOLD); - // Draw selection + // Draw selection highlight renderer.fillRect(0, 60 + selectedSettingIndex * 30 - 2, pageWidth - 1, 30); // Draw all settings for (int i = 0; i < settingsCount; i++) { const int settingY = 60 + i * 30; // 30 pixels between settings + const bool isSelected = (i == selectedSettingIndex); // Draw setting name - renderer.drawText(UI_10_FONT_ID, 20, settingY, settingsList[i].name, i != selectedSettingIndex); + renderer.drawText(UI_10_FONT_ID, 20, settingY, settingsList[i].name, !isSelected); // Draw value based on setting type - std::string valueText = ""; + std::string valueText; if (settingsList[i].type == SettingType::TOGGLE && settingsList[i].valuePtr != nullptr) { const bool value = SETTINGS.*(settingsList[i].valuePtr); valueText = value ? "ON" : "OFF"; @@ -208,8 +218,10 @@ void SettingsActivity::render() const { } else if (settingsList[i].type == SettingType::VALUE && settingsList[i].valuePtr != nullptr) { valueText = std::to_string(SETTINGS.*(settingsList[i].valuePtr)); } - const auto width = renderer.getTextWidth(UI_10_FONT_ID, valueText.c_str()); - renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, settingY, valueText.c_str(), i != selectedSettingIndex); + if (!valueText.empty()) { + const auto width = renderer.getTextWidth(UI_10_FONT_ID, valueText.c_str()); + renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, settingY, valueText.c_str(), !isSelected); + } } // Draw version text above button hints diff --git a/src/activities/util/KeyboardEntryActivity.cpp b/src/activities/util/KeyboardEntryActivity.cpp index aa4ffc20..8c36ac33 100644 --- a/src/activities/util/KeyboardEntryActivity.cpp +++ b/src/activities/util/KeyboardEntryActivity.cpp @@ -73,7 +73,7 @@ int KeyboardEntryActivity::getRowLength(const int row) const { case 3: return 10; // zxcvbnm,./ case 4: - return 10; // caps (2 wide), space (5 wide), backspace (2 wide), OK + return 10; // shift (2 wide), space (5 wide), backspace (2 wide), OK default: return 0; } @@ -145,6 +145,11 @@ void KeyboardEntryActivity::loop() { // Clamp column to valid range for new row const int maxCol = getRowLength(selectedRow) - 1; if (selectedCol > maxCol) selectedCol = maxCol; + } else { + // Wrap to bottom row + selectedRow = NUM_ROWS - 1; + const int maxCol = getRowLength(selectedRow) - 1; + if (selectedCol > maxCol) selectedCol = maxCol; } updateRequired = true; } @@ -154,16 +159,24 @@ void KeyboardEntryActivity::loop() { selectedRow++; const int maxCol = getRowLength(selectedRow) - 1; if (selectedCol > maxCol) selectedCol = maxCol; + } else { + // Wrap to top row + selectedRow = 0; + const int maxCol = getRowLength(selectedRow) - 1; + if (selectedCol > maxCol) selectedCol = maxCol; } updateRequired = true; } if (mappedInput.wasPressed(MappedInputManager::Button::Left)) { + const int maxCol = getRowLength(selectedRow) - 1; + // Special bottom row case if (selectedRow == SPECIAL_ROW) { // Bottom row has special key widths if (selectedCol >= SHIFT_COL && selectedCol < SPACE_COL) { - // In shift key, do nothing + // In shift key, wrap to end of row + selectedCol = maxCol; } else if (selectedCol >= SPACE_COL && selectedCol < BACKSPACE_COL) { // In space bar, move to shift selectedCol = SHIFT_COL; @@ -180,10 +193,9 @@ void KeyboardEntryActivity::loop() { if (selectedCol > 0) { selectedCol--; - } else if (selectedRow > 0) { - // Wrap to previous row - selectedRow--; - selectedCol = getRowLength(selectedRow) - 1; + } else { + // Wrap to end of current row + selectedCol = maxCol; } updateRequired = true; } @@ -204,7 +216,8 @@ void KeyboardEntryActivity::loop() { // In backspace, move to done selectedCol = DONE_COL; } else if (selectedCol >= DONE_COL) { - // At done button, do nothing + // At done button, wrap to beginning of row + selectedCol = SHIFT_COL; } updateRequired = true; return; @@ -212,9 +225,8 @@ void KeyboardEntryActivity::loop() { if (selectedCol < maxCol) { selectedCol++; - } else if (selectedRow < NUM_ROWS - 1) { - // Wrap to next row - selectedRow++; + } else { + // Wrap to beginning of current row selectedCol = 0; } updateRequired = true; @@ -288,14 +300,14 @@ void KeyboardEntryActivity::render() const { // Handle bottom row (row 4) specially with proper multi-column keys if (row == 4) { - // Bottom row layout: CAPS (2 cols) | SPACE (5 cols) | <- (2 cols) | OK (2 cols) + // Bottom row layout: SHIFT (2 cols) | SPACE (5 cols) | <- (2 cols) | OK (2 cols) // Total: 11 visual columns, but we use logical positions for selection int currentX = startX; - // CAPS key (logical col 0, spans 2 key widths) - const bool capsSelected = (selectedRow == 4 && selectedCol >= SHIFT_COL && selectedCol < SPACE_COL); - renderItemWithSelector(currentX + 2, rowY, shiftActive ? "CAPS" : "caps", capsSelected); + // SHIFT key (logical col 0, spans 2 key widths) + const bool shiftSelected = (selectedRow == 4 && selectedCol >= SHIFT_COL && selectedCol < SPACE_COL); + renderItemWithSelector(currentX + 2, rowY, shiftActive ? "SHIFT" : "shift", shiftSelected); currentX += 2 * (keyWidth + keySpacing); // Space bar (logical cols 2-6, spans 5 key widths) diff --git a/src/main.cpp b/src/main.cpp index 8a7c3b91..e0ad316a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,7 @@ #include "Battery.h" #include "CrossPointSettings.h" #include "CrossPointState.h" +#include "KOReaderCredentialStore.h" #include "MappedInputManager.h" #include "activities/boot_sleep/BootActivity.h" #include "activities/boot_sleep/SleepActivity.h" @@ -289,6 +290,7 @@ void setup() { } SETTINGS.loadFromFile(); + KOREADER_STORE.loadFromFile(); // verify power button press duration after we've read settings. verifyWakeupLongPress();