Proper refresh on exit
This commit is contained in:
@@ -751,11 +751,12 @@ void GfxRenderer::drawCenteredText(const int fontId, const int y, const char* te
|
|||||||
void GfxRenderer::drawText(const int fontId, const int x, const int y, const char* text, const bool black,
|
void GfxRenderer::drawText(const int fontId, const int x, const int y, const char* text, const bool black,
|
||||||
const EpdFontFamily::Style style) const {
|
const EpdFontFamily::Style style) const {
|
||||||
const int yPos = y + getFontAscenderSize(fontId);
|
const int yPos = y + getFontAscenderSize(fontId);
|
||||||
int32_t xPosFP = fp4::fromPixel(x); // 12.4 fixed-point accumulator
|
|
||||||
int lastBaseX = x;
|
int lastBaseX = x;
|
||||||
int lastBaseLeft = 0;
|
int lastBaseLeft = 0;
|
||||||
int lastBaseWidth = 0;
|
int lastBaseWidth = 0;
|
||||||
int lastBaseTop = 0;
|
int lastBaseTop = 0;
|
||||||
|
int lastBaseAdvanceFP = 0; // 12.4 fixed-point
|
||||||
|
int32_t prevAdvanceFP = 0; // 12.4 fixed-point: prev glyph's advance + next kern for snap
|
||||||
|
|
||||||
// cannot draw a NULL / empty string
|
// cannot draw a NULL / empty string
|
||||||
if (text == nullptr || *text == '\0') {
|
if (text == nullptr || *text == '\0') {
|
||||||
@@ -788,20 +789,24 @@ void GfxRenderer::drawText(const int fontId, const int x, const int y, const cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
cp = font.applyLigatures(cp, text, style);
|
cp = font.applyLigatures(cp, text, style);
|
||||||
const int kernFP = (prevCp != 0) ? font.getKerning(prevCp, cp, style) : 0; // 4.4 fixed-point kern
|
|
||||||
xPosFP += kernFP;
|
|
||||||
|
|
||||||
lastBaseX = fp4::toPixel(xPosFP); // snap 12.4 fixed-point to nearest pixel
|
// Differential rounding: snap (previous advance + current kern) as one unit so
|
||||||
|
// identical character pairs always produce the same pixel step regardless of
|
||||||
|
// where they fall on the line.
|
||||||
|
if (prevCp != 0) {
|
||||||
|
const auto kernFP = font.getKerning(prevCp, cp, style); // 4.4 fixed-point kern
|
||||||
|
lastBaseX += fp4::toPixel(prevAdvanceFP + kernFP); // snap 12.4 fixed-point to nearest pixel
|
||||||
|
}
|
||||||
|
|
||||||
const EpdGlyph* glyph = font.getGlyph(cp, style);
|
const EpdGlyph* glyph = font.getGlyph(cp, style);
|
||||||
|
|
||||||
lastBaseLeft = glyph ? glyph->left : 0;
|
lastBaseLeft = glyph ? glyph->left : 0;
|
||||||
lastBaseWidth = glyph ? glyph->width : 0;
|
lastBaseWidth = glyph ? glyph->width : 0;
|
||||||
lastBaseTop = glyph ? glyph->top : 0;
|
lastBaseTop = glyph ? glyph->top : 0;
|
||||||
|
lastBaseAdvanceFP = glyph ? glyph->advanceX : 0;
|
||||||
|
prevAdvanceFP = lastBaseAdvanceFP;
|
||||||
|
|
||||||
renderCharImpl<TextRotation::None>(*this, renderMode, font, cp, lastBaseX, yPos, black, style);
|
renderCharImpl<TextRotation::None>(*this, renderMode, font, cp, lastBaseX, yPos, black, style);
|
||||||
if (glyph) {
|
|
||||||
xPosFP += glyph->advanceX; // 12.4 fixed-point advance
|
|
||||||
}
|
|
||||||
prevCp = cp;
|
prevCp = cp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1583,10 +1588,17 @@ void GfxRenderer::invertScreen() const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GfxRenderer::setNextDisplayRefreshMode(const HalDisplay::RefreshMode refreshMode) const {
|
||||||
|
useNextRefreshOverride = true;
|
||||||
|
nextRefreshOverride = refreshMode;
|
||||||
|
}
|
||||||
|
|
||||||
void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const {
|
void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const {
|
||||||
|
const auto effectiveMode = useNextRefreshOverride ? nextRefreshOverride : refreshMode;
|
||||||
|
useNextRefreshOverride = false;
|
||||||
auto elapsed = millis() - start_ms;
|
auto elapsed = millis() - start_ms;
|
||||||
LOG_DBG("GFX", "Time = %lu ms from clearScreen to displayBuffer", elapsed);
|
LOG_DBG("GFX", "Time = %lu ms from clearScreen to displayBuffer", elapsed);
|
||||||
display.displayBuffer(refreshMode, fadingFix);
|
display.displayBuffer(effectiveMode, fadingFix);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GfxRenderer::truncatedText(const int fontId, const char* text, const int maxWidth,
|
std::string GfxRenderer::truncatedText(const int fontId, const char* text, const int maxWidth,
|
||||||
@@ -1744,21 +1756,28 @@ int GfxRenderer::getTextAdvanceX(const int fontId, const char* text, EpdFontFami
|
|||||||
|
|
||||||
uint32_t cp;
|
uint32_t cp;
|
||||||
uint32_t prevCp = 0;
|
uint32_t prevCp = 0;
|
||||||
int32_t widthFP = 0; // 12.4 fixed-point accumulator
|
int widthPx = 0;
|
||||||
|
int32_t prevAdvanceFP = 0; // 12.4 fixed-point: prev glyph's advance + next kern for snap
|
||||||
const auto& font = fontIt->second;
|
const auto& font = fontIt->second;
|
||||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
||||||
if (utf8IsCombiningMark(cp)) {
|
if (utf8IsCombiningMark(cp)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
cp = font.applyLigatures(cp, text, style);
|
cp = font.applyLigatures(cp, text, style);
|
||||||
|
|
||||||
|
// Differential rounding: snap (previous advance + current kern) together,
|
||||||
|
// matching drawText so measurement and rendering agree exactly.
|
||||||
if (prevCp != 0) {
|
if (prevCp != 0) {
|
||||||
widthFP += font.getKerning(prevCp, cp, style); // 4.4 fixed-point kern
|
const auto kernFP = font.getKerning(prevCp, cp, style); // 4.4 fixed-point kern
|
||||||
|
widthPx += fp4::toPixel(prevAdvanceFP + kernFP); // snap 12.4 fixed-point to nearest pixel
|
||||||
}
|
}
|
||||||
|
|
||||||
const EpdGlyph* glyph = font.getGlyph(cp, style);
|
const EpdGlyph* glyph = font.getGlyph(cp, style);
|
||||||
if (glyph) widthFP += glyph->advanceX; // 12.4 fixed-point advance
|
prevAdvanceFP = glyph ? glyph->advanceX : 0;
|
||||||
prevCp = cp;
|
prevCp = cp;
|
||||||
}
|
}
|
||||||
return fp4::toPixel(widthFP); // snap 12.4 fixed-point to nearest pixel
|
widthPx += fp4::toPixel(prevAdvanceFP); // final glyph's advance
|
||||||
|
return widthPx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GfxRenderer::getFontAscenderSize(const int fontId) const {
|
int GfxRenderer::getFontAscenderSize(const int fontId) const {
|
||||||
@@ -1805,11 +1824,12 @@ void GfxRenderer::drawTextRotated90CW(const int fontId, const int x, const int y
|
|||||||
|
|
||||||
const auto& font = fontIt->second;
|
const auto& font = fontIt->second;
|
||||||
|
|
||||||
int32_t yPosFP = fp4::fromPixel(y); // 12.4 fixed-point accumulator
|
|
||||||
int lastBaseY = y;
|
int lastBaseY = y;
|
||||||
int lastBaseLeft = 0;
|
int lastBaseLeft = 0;
|
||||||
int lastBaseWidth = 0;
|
int lastBaseWidth = 0;
|
||||||
int lastBaseTop = 0;
|
int lastBaseTop = 0;
|
||||||
|
int lastBaseAdvanceFP = 0; // 12.4 fixed-point
|
||||||
|
int32_t prevAdvanceFP = 0; // 12.4 fixed-point: prev glyph's advance + next kern for snap
|
||||||
|
|
||||||
uint32_t cp;
|
uint32_t cp;
|
||||||
uint32_t prevCp = 0;
|
uint32_t prevCp = 0;
|
||||||
@@ -1826,21 +1846,23 @@ void GfxRenderer::drawTextRotated90CW(const int fontId, const int x, const int y
|
|||||||
}
|
}
|
||||||
|
|
||||||
cp = font.applyLigatures(cp, text, style);
|
cp = font.applyLigatures(cp, text, style);
|
||||||
|
|
||||||
|
// Differential rounding: snap (previous advance + current kern) as one unit,
|
||||||
|
// subtracting for the rotated coordinate direction.
|
||||||
if (prevCp != 0) {
|
if (prevCp != 0) {
|
||||||
yPosFP -= font.getKerning(prevCp, cp, style); // 4.4 fixed-point kern (subtract for rotated)
|
const auto kernFP = font.getKerning(prevCp, cp, style); // 4.4 fixed-point kern
|
||||||
|
lastBaseY -= fp4::toPixel(prevAdvanceFP + kernFP); // snap 12.4 fixed-point to nearest pixel
|
||||||
}
|
}
|
||||||
|
|
||||||
lastBaseY = fp4::toPixel(yPosFP); // snap 12.4 fixed-point to nearest pixel
|
|
||||||
const EpdGlyph* glyph = font.getGlyph(cp, style);
|
const EpdGlyph* glyph = font.getGlyph(cp, style);
|
||||||
|
|
||||||
lastBaseLeft = glyph ? glyph->left : 0;
|
lastBaseLeft = glyph ? glyph->left : 0;
|
||||||
lastBaseWidth = glyph ? glyph->width : 0;
|
lastBaseWidth = glyph ? glyph->width : 0;
|
||||||
lastBaseTop = glyph ? glyph->top : 0;
|
lastBaseTop = glyph ? glyph->top : 0;
|
||||||
|
lastBaseAdvanceFP = glyph ? glyph->advanceX : 0;
|
||||||
|
prevAdvanceFP = lastBaseAdvanceFP;
|
||||||
|
|
||||||
renderCharImpl<TextRotation::Rotated90CW>(*this, renderMode, font, cp, x, lastBaseY, black, style);
|
renderCharImpl<TextRotation::Rotated90CW>(*this, renderMode, font, cp, x, lastBaseY, black, style);
|
||||||
if (glyph) {
|
|
||||||
yPosFP -= glyph->advanceX; // 12.4 fixed-point advance (subtract for rotated)
|
|
||||||
}
|
|
||||||
prevCp = cp;
|
prevCp = cp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ class GfxRenderer {
|
|||||||
// recording to the (non-const) FontCacheManager. Same pragmatic compromise
|
// recording to the (non-const) FontCacheManager. Same pragmatic compromise
|
||||||
// as before, concentrated in a single pointer instead of four fields.
|
// as before, concentrated in a single pointer instead of four fields.
|
||||||
mutable FontCacheManager* fontCacheManager_ = nullptr;
|
mutable FontCacheManager* fontCacheManager_ = nullptr;
|
||||||
|
mutable bool useNextRefreshOverride = false;
|
||||||
|
mutable HalDisplay::RefreshMode nextRefreshOverride = HalDisplay::FAST_REFRESH;
|
||||||
|
|
||||||
void renderChar(const EpdFontFamily& fontFamily, uint32_t cp, int* x, int* y, bool pixelState,
|
void renderChar(const EpdFontFamily& fontFamily, uint32_t cp, int* x, int* y, bool pixelState,
|
||||||
EpdFontFamily::Style style) const;
|
EpdFontFamily::Style style) const;
|
||||||
@@ -92,6 +94,7 @@ class GfxRenderer {
|
|||||||
int getScreenWidth() const;
|
int getScreenWidth() const;
|
||||||
int getScreenHeight() const;
|
int getScreenHeight() const;
|
||||||
void displayBuffer(HalDisplay::RefreshMode refreshMode = HalDisplay::FAST_REFRESH) const;
|
void displayBuffer(HalDisplay::RefreshMode refreshMode = HalDisplay::FAST_REFRESH) const;
|
||||||
|
void setNextDisplayRefreshMode(HalDisplay::RefreshMode refreshMode) const;
|
||||||
// EXPERIMENTAL: Windowed update - display only a rectangular region
|
// EXPERIMENTAL: Windowed update - display only a rectangular region
|
||||||
// void displayWindow(int x, int y, int width, int height) const;
|
// void displayWindow(int x, int y, int width, int height) const;
|
||||||
void invertScreen() const;
|
void invertScreen() const;
|
||||||
|
|||||||
@@ -88,8 +88,9 @@ inline void displayWithRefreshCycle(const GfxRenderer& renderer, int& pagesUntil
|
|||||||
|
|
||||||
inline void enforceExitFullRefresh(const GfxRenderer& renderer) {
|
inline void enforceExitFullRefresh(const GfxRenderer& renderer) {
|
||||||
// Reader exits can leave visible ghosting when the next screen is rendered with a fast LUT.
|
// Reader exits can leave visible ghosting when the next screen is rendered with a fast LUT.
|
||||||
// Force one full waveform pass before leaving the reader stack.
|
// Schedule the next displayed screen to use a full refresh, rather than refreshing
|
||||||
renderer.displayBuffer(HalDisplay::FULL_REFRESH);
|
// the current reader screen as it closes.
|
||||||
|
renderer.setNextDisplayRefreshMode(HalDisplay::FULL_REFRESH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grayscale anti-aliasing pass. Renders content twice (LSB + MSB) to build
|
// Grayscale anti-aliasing pass. Renders content twice (LSB + MSB) to build
|
||||||
|
|||||||
@@ -123,8 +123,7 @@ void BmpViewerActivity::onExit() {
|
|||||||
saveDitherSettingsIfNeeded();
|
saveDitherSettingsIfNeeded();
|
||||||
#endif
|
#endif
|
||||||
Activity::onExit();
|
Activity::onExit();
|
||||||
renderer.clearScreen();
|
ReaderUtils::enforceExitFullRefresh(renderer);
|
||||||
renderer.displayBuffer(HalDisplay::FULL_REFRESH);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BmpViewerActivity::renderBmpImage(const bool showControls) {
|
bool BmpViewerActivity::renderBmpImage(const bool showControls) {
|
||||||
|
|||||||
Reference in New Issue
Block a user