Files
Upsilon/kandinsky/src/context_text.cpp
ArtichautCosmique 0906dc919b [mpy/kandinsky] Fix draw_string() on new line + good colors (#47)
* [mpy/kandinsky] Use good colors

* [kandinsky/context_text] Avoid returning to pos x=0 on new line, use arg's x coordinate instead
2021-10-11 20:25:03 +02:00

80 lines
3.5 KiB
C++

#include <assert.h>
#include <kandinsky/context.h>
#include <kandinsky/font.h>
#include <ion/unicode/utf8_decoder.h>
#include <ion/display.h>
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);
}
int KDContext::checkDrawnString(const char * text, KDPoint p, const KDFont * font, KDColor textColor, KDColor backgroundColor, int maxLength) {
int numberOfFailedPixels = 0;
pushOrPullString(text, p, font, textColor, backgroundColor, maxLength, false, &numberOfFailedPixels);
return numberOfFailedPixels;
}
KDPoint KDContext::pushOrPullString(const char * text, KDPoint p, const KDFont * font, KDColor textColor, KDColor backgroundColor, int maxByteLength, bool push, int * result) {
KDPoint position = p;
KDSize glyphSize = font->glyphSize();
KDFont::RenderPalette palette = font->renderPalette(textColor, backgroundColor);
KDFont::GlyphBuffer glyphBuffer;
UTF8Decoder decoder(text);
const char * codePointPointer = decoder.stringPosition();
CodePoint codePoint = decoder.nextCodePoint();
while (codePoint != UCodePointNull && (maxByteLength < 0 || codePointPointer < text + maxByteLength)) {
codePointPointer = decoder.stringPosition();
if (codePoint == UCodePointLineFeed) {
assert(position.y() < KDCOORDINATE_MAX - glyphSize.height());
position = KDPoint(p.x(), position.y() + glyphSize.height());
codePoint = decoder.nextCodePoint();
} else if (codePoint == UCodePointTabulation) {
position = position.translatedBy(KDPoint(k_tabCharacterWidth * glyphSize.width(), 0));
codePoint = decoder.nextCodePoint();
} else {
assert(!codePoint.isCombining());
font->setGlyphGrayscalesForCodePoint(codePoint, &glyphBuffer);
codePoint = decoder.nextCodePoint();
while (codePoint.isCombining()) {
font->accumulateGlyphGrayscalesForCodePoint(codePoint, &glyphBuffer);
codePointPointer = decoder.stringPosition();
codePoint = decoder.nextCodePoint();
}
font->colorizeGlyphBuffer(&palette, &glyphBuffer);
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 = 0;
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 = (*result)+1;
break;
}
}
}
position = position.translatedBy(KDPoint(glyphSize.width(), 0));
}
}
return position;
}