diff --git a/apps/shared/post_and_hardware_tests.cpp b/apps/shared/post_and_hardware_tests.cpp index 4eaea2323..28890ef44 100644 --- a/apps/shared/post_and_hardware_tests.cpp +++ b/apps/shared/post_and_hardware_tests.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include namespace Shared { @@ -54,7 +56,7 @@ bool POSTAndHardwareTests::WhiteTilingLCDTestOK() { } bool POSTAndHardwareTests::LCDDataOK(int numberOfIterations) { - if (!WhiteTilingLCDTestOK()) { + if (!TextLCDTestOK() || !WhiteTilingLCDTestOK()) { return false; } for (int iteration = 0; iteration < numberOfIterations; iteration++) { @@ -81,4 +83,24 @@ bool POSTAndHardwareTests::LCDDataOK(int numberOfIterations) { return true; } +bool POSTAndHardwareTests::TextLCDTestOK() { + const char * text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + const KDFont * font = KDFont::SmallFont; + KDCoordinate glyphHeight = font->glyphSize().height(); + + // Fill the screen + for (int i = 0; i < Ion::Display::Height / glyphHeight; i++) { + KDIonContext::sharedContext()->drawString(text, KDPoint(0, i * glyphHeight), font); + } + + // Check the drawing + for (int i = 0; i < Ion::Display::Height / glyphHeight; i++) { + if (!KDIonContext::sharedContext()->checkDrawnString(text, KDPoint(0, i * glyphHeight), font)) { + return false; + } + } + return true; +} + + } diff --git a/apps/shared/post_and_hardware_tests.h b/apps/shared/post_and_hardware_tests.h index b9059a94d..951f3d8e2 100644 --- a/apps/shared/post_and_hardware_tests.h +++ b/apps/shared/post_and_hardware_tests.h @@ -15,6 +15,7 @@ private: constexpr static int k_stampSize = 8; constexpr static int k_invalidPixelsLimit = 2; static bool WhiteTilingLCDTestOK(); + static bool TextLCDTestOK(); static_assert(Ion::Display::Width % k_stampSize == 0, "Stamps must tesselate the display"); static_assert(Ion::Display::Height % k_stampSize == 0, "Stamps must tesselate the display"); static_assert(k_stampSize % 2 == 0, "Even number of XOR needed."); diff --git a/kandinsky/include/kandinsky/context.h b/kandinsky/include/kandinsky/context.h index c41ad63b1..b18a19e75 100644 --- a/kandinsky/include/kandinsky/context.h +++ b/kandinsky/include/kandinsky/context.h @@ -17,6 +17,8 @@ public: // Text KDPoint drawString(const char * text, KDPoint p, const KDFont * font = KDFont::LargeFont, KDColor textColor = KDColorBlack, KDColor backgroundColor = KDColorWhite, int maxLength = -1); + // Check that a string is drawn. + bool checkDrawnString(const char * text, KDPoint p, const KDFont * font = KDFont::LargeFont, KDColor textColor = KDColorBlack, KDColor backgroundColor = KDColorWhite, int maxLength = -1); // Line. Not anti-aliased. void drawLine(KDPoint p1, KDPoint p2, KDColor c); @@ -33,6 +35,7 @@ protected: virtual void pullRect(KDRect rect, KDColor * pixels) = 0; private: KDRect absoluteFillRect(KDRect rect); + KDPoint pushOrPullString(const char * text, KDPoint p, const KDFont * font, KDColor textColor, KDColor backgroundColor, int maxByteLength, bool push, bool * result = nullptr); KDPoint m_origin; KDRect m_clippingRect; }; diff --git a/kandinsky/src/context_text.cpp b/kandinsky/src/context_text.cpp index 49de92fe7..22050b3a6 100644 --- a/kandinsky/src/context_text.cpp +++ b/kandinsky/src/context_text.cpp @@ -2,14 +2,24 @@ #include #include #include +#include constexpr static int k_tabCharacterWidth = 4; KDPoint KDContext::drawString(const char * text, KDPoint p, const KDFont * font, KDColor textColor, KDColor backgroundColor, int maxByteLength) { + return pushOrPullString(text, p, font, textColor, backgroundColor, maxByteLength, true); +} + +bool KDContext::checkDrawnString(const char * text, KDPoint p, const KDFont * font, KDColor textColor, KDColor backgroundColor, int maxLength) { + bool result = true; + pushOrPullString(text, p, font, textColor, backgroundColor, maxLength, false, &result); + return result; +} + +KDPoint KDContext::pushOrPullString(const char * text, KDPoint p, const KDFont * font, KDColor textColor, KDColor backgroundColor, int maxByteLength, bool push, bool * result) { KDPoint position = p; KDSize glyphSize = font->glyphSize(); KDFont::RenderPalette palette = font->renderPalette(textColor, backgroundColor); - KDFont::GlyphBuffer glyphBuffer; UTF8Decoder decoder(text); @@ -33,12 +43,33 @@ KDPoint KDContext::drawString(const char * text, KDPoint p, const KDFont * font, codePoint = decoder.nextCodePoint(); } font->colorizeGlyphBuffer(&palette, &glyphBuffer); - // Flush accumulated content - fillRectWithPixels( - KDRect(position, glyphSize), - glyphBuffer.colorBuffer(), - glyphBuffer.colorBuffer() // It's OK to trash the content of the color buffer since we'll re-fetch it for the next char anyway - ); + if (push) { + // Push the character on the screen + fillRectWithPixels( + KDRect(position, glyphSize), + glyphBuffer.colorBuffer(), + glyphBuffer.colorBuffer() // It's OK to trash the content of the color buffer since we'll re-fetch it for the next char anyway + ); + } else { + // Pull and compare the character from the screen + assert(result != nullptr); + *result = true; + KDFont::GlyphBuffer workingGlyphBuffer; + KDColor * workingColorBuffer = workingGlyphBuffer.colorBuffer(); + KDColor * colorBuffer = glyphBuffer.colorBuffer(); + for (int i = 0; i < glyphSize.height() * glyphSize.width(); i++) { + workingColorBuffer[i] = KDColorRed; + } + /* Caution: Unlike fillRectWithPixels, pullRect accesses outside (0, 0, + * Ion::Display::Width, Ion::Display::Height) might give weird data. */ + Ion::Display::pullRect(KDRect(position, glyphSize), workingColorBuffer); + for (int k = 0; k < glyphSize.height() * glyphSize.width(); k++) { + if (colorBuffer[k] != workingColorBuffer[k]) { + *result = false; + return position; + } + } + } position = position.translatedBy(KDPoint(glyphSize.width(), 0)); } }