@@ 1,78 1,75 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "RawFont.hpp"
-#include "Common.hpp" // for Status, Status::GUI_SUCCESS, Status::GU...
-#include "Context.hpp" // for Context
-#include "DrawCommand.hpp" // for DrawRectangle, DrawCommand (ptr only)
-#include "FontKerning.hpp" // for FontKerning
-#include "Renderer.hpp" // for Renderer
-#include "TextConstants.hpp" // for newline
-#include <log/log.hpp> // for LOG_ERROR
-#include "utf8/UTF8.hpp" // for UTF8
-#include <cstring> // for memcpy
-#include <utility> // for pair
+#include "Common.hpp"
+#include "Context.hpp"
+#include "renderers/LineRenderer.hpp"
+#include "renderers/RectangleRenderer.hpp"
+#include "TextConstants.hpp"
+#include <log/log.hpp>
+#include "utf8/UTF8.hpp"
+#include <cstring>
+#include <utility>
namespace gui
{
-
RawFont::~RawFont()
{
- if (fallback_font != nullptr) {
- fallback_font = nullptr;
- }
+ fallback_font = nullptr;
}
gui::Status RawFont::load(uint8_t *data)
{
- uint32_t offset = 0;
+ std::uint32_t offset = 0;
- if (info.load(data, offset) != gui::Status::GUI_SUCCESS)
+ if (info.load(data, offset) != gui::Status::GUI_SUCCESS) {
return gui::Status::GUI_FAILURE;
+ }
// number of glyphs in the font
- memcpy(&glyph_count, data + offset, sizeof(uint32_t));
- offset += sizeof(uint32_t);
+ memcpy(&glyph_count, data + offset, sizeof(std::uint32_t));
+ offset += sizeof(std::uint32_t);
// offset to the beginning of the glyph data
- memcpy(&glyph_data_offset, data + offset, sizeof(uint32_t));
- offset += sizeof(uint32_t);
+ memcpy(&glyph_data_offset, data + offset, sizeof(std::uint32_t));
+ offset += sizeof(std::uint32_t);
// number of kerning pairs
- memcpy(&kern_count, data + offset, sizeof(uint32_t));
- offset += sizeof(uint32_t);
+ memcpy(&kern_count, data + offset, sizeof(std::uint32_t));
+ offset += sizeof(std::uint32_t);
// array of glyphs structures
- memcpy(&kern_data_offset, data + offset, sizeof(uint32_t));
- offset += sizeof(uint32_t);
+ memcpy(&kern_data_offset, data + offset, sizeof(std::uint32_t));
+ offset += sizeof(std::uint32_t);
// offset to the beginning of the image data
- memcpy(&image_data_offset, data + offset, sizeof(uint32_t));
- offset += sizeof(uint32_t);
+ memcpy(&image_data_offset, data + offset, sizeof(std::uint32_t));
+ offset += sizeof(std::uint32_t);
// id of the font assigned by the font manager
id = 1;
// load glyphs
- uint32_t glyphOffset = glyph_data_offset;
- for (unsigned int i = 0; i < glyph_count; i++) {
+ std::uint32_t glyphOffset = glyph_data_offset;
+ for (std::uint32_t i = 0; i < glyph_count; i++) {
auto glyph = std::make_unique<FontGlyph>();
glyph->load(data, glyphOffset);
glyph->loadImage(data, glyph->glyph_offset);
- glyphs.insert(std::pair<uint32_t, std::unique_ptr<FontGlyph>>(glyph->id, std::move(glyph)));
+ glyphs.insert(std::pair<std::uint32_t, std::unique_ptr<FontGlyph>>(glyph->id, std::move(glyph)));
}
// load kerning
// first map contains index of the character and the map that holds values for kerning between
- // first and second character character. In second map key is the value of the second character
+ // first and second character. In second map key is the value of the second character
// and value is the kerning between first and second element.
- uint32_t kernOffset = kern_data_offset;
- for (unsigned int i = 0; i < kern_count; i++) {
+ std::uint32_t kernOffset = kern_data_offset;
+ for (std::uint32_t i = 0; i < kern_count; i++) {
auto kern = std::make_unique<FontKerning>();
kern->load(data, kernOffset);
// find map using first element of kerning as a key
- auto it = kerning.find(kern->first);
+ const auto it = kerning.find(kern->first);
// element wasn't found
if (it == kerning.end()) {
- std::map<uint32_t, std::unique_ptr<FontKerning>> kernMap;
- auto kern_first = kern->first;
+ std::map<std::uint32_t, std::unique_ptr<FontKerning>> kernMap;
+ const auto kern_first = kern->first;
kernMap.emplace(std::make_pair(kern->second, std::move(kern)));
// insert element to the first map
@@ 89,40 86,41 @@ namespace gui
return gui::Status::GUI_SUCCESS;
}
- int32_t RawFont::getKerning(uint32_t id1, uint32_t id2) const
+ int32_t RawFont::getKerning(std::uint32_t id1, std::uint32_t id2) const
{
if (id2 == none_char_id) {
return 0;
}
// search for a map with kerning for given character (id1)
- auto it1 = kerning.find(id1);
+ const auto it1 = kerning.find(id1);
// if there is no map with kerning for id1 return 0;
- if (it1 == kerning.end())
+ if (it1 == kerning.end()) {
return 0;
+ }
- auto &kernMap = it1->second;
+ const auto &kernMap = it1->second;
// otherwise search for id2 in kernMap and return value or 0 if it's not found
- auto it2 = kernMap.find(id2);
+ const auto it2 = kernMap.find(id2);
if (it2 == kernMap.end()) {
return 0;
}
- const std::unique_ptr<FontKerning> &kern = it2->second;
+ const auto &kern = it2->second;
return kern->amount;
}
- uint32_t RawFont::getCharCountInSpace(const UTF8 &str, const uint32_t space) const
+ std::uint32_t RawFont::getCharCountInSpace(const UTF8 &str, const std::uint32_t space) const
{
- uint32_t availableSpace = space;
- uint32_t count = 0;
- uint32_t current = 0;
- uint32_t previous = none_char_id;
+ std::uint32_t availableSpace = space;
+ std::uint32_t count = 0;
+ std::uint32_t current = 0;
+ std::uint32_t previous = none_char_id;
- for (uint32_t i = 0; i < str.length(); ++i, ++count) {
+ for (std::uint32_t i = 0; i < str.length(); ++i, ++count) {
current = str[i];
- auto char_pixel_width = getCharPixelWidth(current, previous);
+ const auto char_pixel_width = getCharPixelWidth(current, previous);
if (availableSpace < char_pixel_width) {
return count;
}
@@ 132,7 130,7 @@ namespace gui
return count;
}
- FontGlyph *RawFont::getGlyph(uint32_t glyph_id) const
+ FontGlyph *RawFont::getGlyph(std::uint32_t glyph_id) const
{
auto glyph = this->findGlyph(glyph_id);
if (glyph != nullptr) {
@@ 147,16 145,16 @@ namespace gui
return unsupported.get();
}
- FontGlyph *RawFont::findGlyph(uint32_t glyph_id) const
+ FontGlyph *RawFont::findGlyph(std::uint32_t glyph_id) const
{
- auto glyph_found = glyphs.find(glyph_id);
+ const auto glyph_found = glyphs.find(glyph_id);
if (glyph_found != glyphs.end()) {
return glyph_found->second.get();
}
return nullptr;
}
- FontGlyph *RawFont::findGlyphFallback(uint32_t glyph_id) const
+ FontGlyph *RawFont::findGlyphFallback(std::uint32_t glyph_id) const
{
if (fallback_font == nullptr) {
return nullptr;
@@ 164,7 162,7 @@ namespace gui
return fallback_font->findGlyph(glyph_id);
}
- uint32_t RawFont::getPixelWidth(const UTF8 &str, const uint32_t start, const uint32_t count) const
+ std::uint32_t RawFont::getPixelWidth(const UTF8 &str, const std::uint32_t start, const std::uint32_t count) const
{
if (count == 0) {
return 0;
@@ 180,11 178,11 @@ namespace gui
}
// width of text in pixels
- uint32_t width = 0;
- uint32_t idCurrent = 0;
- uint32_t idLast = none_char_id;
+ std::uint32_t width = 0;
+ std::uint32_t idCurrent = 0;
+ std::uint32_t idLast = none_char_id;
- for (uint32_t i = 0; i < count; ++i) {
+ for (std::uint32_t i = 0; i < count; ++i) {
idCurrent = str[start + i];
width += getCharPixelWidth(idCurrent, idLast);
idLast = idCurrent;
@@ 193,70 191,93 @@ namespace gui
return width;
}
- uint32_t RawFont::getPixelWidth(const UTF8 &str) const
+ std::uint32_t RawFont::getPixelWidth(const UTF8 &str) const
{
return getPixelWidth(str, 0, str.length());
}
- uint32_t RawFont::getCharPixelWidth(uint32_t charCode, uint32_t previousChar) const
+ std::uint32_t RawFont::getCharPixelWidth(std::uint32_t charCode, std::uint32_t previousChar) const
{
if (charCode == text::newline) { // newline doesn't have width
return 0;
}
- auto glyph = getGlyph(charCode);
+ const auto glyph = getGlyph(charCode);
return glyph->xadvance + getKerning(charCode, previousChar);
}
- uint32_t RawFont::getCharPixelHeight(uint32_t charCode)
+ std::uint32_t RawFont::getCharPixelHeight(std::uint32_t charCode)
{
- FontGlyph *glyph = getGlyph(charCode);
+ const auto glyph = getGlyph(charCode);
return glyph->height;
}
void RawFont::createGlyphUnsupported()
{
+ constexpr auto ptToPx = 0.75f;
+ constexpr auto diagonalSpacingToRectangleEdgeRatio = 0.6f; // To the center of the line
+ constexpr auto fallbackLineWidth = 1;
+ constexpr auto modelChar = 'h'; // Just get any char, it is needed only to obtain line width
+
unsupported = std::make_unique<FontGlyph>();
- const float pt_to_px = 0.75;
- unsupported->height = this->info.size * pt_to_px;
- const float typical_width_as_percent_of_height = 0.62;
- unsupported->width = unsupported->height * typical_width_as_percent_of_height;
+ unsupported->height = info.size * ptToPx;
+ unsupported->width = unsupported->height;
unsupported->xoffset = 0;
- unsupported->yoffset = 0;
-
- // generate a rectangle based on an existing letter. otherwise use some magic numbers ↑ to approximate the size
- // for the rectangle
- char baseChar = 'h'; // arbitrary choice. h as a representative character to get an idea of glyph size. if not
- // found, then use magic numbers above
- auto baseCharFound = this->glyphs.find(baseChar);
- if (baseCharFound != this->glyphs.end()) {
- FontGlyph *baseGlyph = baseCharFound->second.get();
- unsupported->width = baseGlyph->width;
- unsupported->height = baseGlyph->height;
- unsupported->xoffset = (baseGlyph->xadvance - baseGlyph->width) / 2;
+ unsupported->yoffset = unsupported->height;
+
+ const auto modelGlyph = glyphs.find(modelChar);
+ if (modelGlyph != glyphs.end()) {
+ const auto modelGlyphData = modelGlyph->second.get();
+ unsupported->xoffset = (modelGlyphData->xadvance - modelGlyphData->width) / 2;
}
+
if (unsupported->xoffset == 0) {
- unsupported->xoffset = 1; // fallback margin.
+ unsupported->xoffset = fallbackLineWidth;
}
- unsupported->yoffset += unsupported->height;
+
unsupported->xadvance =
unsupported->width + (2 * unsupported->xoffset); // use xoffset as margins on the left/right of the glyph
- // populate with a bitmap (glyph)
- DrawRectangle commandRect;
- commandRect.origin = {0, 0};
- commandRect.width = unsupported->width;
- commandRect.height = unsupported->height;
- commandRect.areaX = 0;
- commandRect.areaY = 0;
- commandRect.areaW = unsupported->width;
- commandRect.areaH = unsupported->height;
- commandRect.penWidth = unsupported->xoffset;
+ const auto diagonalHorizontalDistance =
+ static_cast<Position>((unsupported->width / 2) * diagonalSpacingToRectangleEdgeRatio);
+ const auto diagonalVerticalDistance =
+ static_cast<Position>((unsupported->height / 2) * diagonalSpacingToRectangleEdgeRatio);
+
+ /* Correction required to place the diagonals in the center of the rectangle
+ * regardless of line width. Drawing line with width > 1 is done
+ * by drawing multiple 1px lines in certain direction, so correction has to
+ * be applied to compensate that. */
+ const auto horizontalOffset = static_cast<Position>(std::ceil(unsupported->xoffset / 2.0));
+
+ const Point rectangleOrigin = {0, 0};
+ const Point firstDiagonalOrigin = {diagonalHorizontalDistance - horizontalOffset, diagonalVerticalDistance};
+ const Point secondDiagonalOrigin = {unsupported->width - diagonalHorizontalDistance - horizontalOffset,
+ diagonalVerticalDistance};
+
+ /* The "length" in draw45deg() is not an actual length, it's length of the projection
+ * of the line on one of the axes (no matter which one, as it is 45 degrees angle), i.e.
+ * real length divided by square root of 2.
+ * Both diagonals have the same length, so compute only one of them, based on height.
+ * Computation based on width will yield the same result - we're in square. */
+ const auto diagonalLength = unsupported->height - (2 * diagonalVerticalDistance) + 1;
+
+ const gui::renderer::RectangleRenderer::DrawableStyle rectangleStyle = {
+ .borderWidth = static_cast<Length>(unsupported->xoffset)};
+ const gui::renderer::LineRenderer::DrawableStyle diagonalStyle = {
+ .penWidth = static_cast<Length>(unsupported->xoffset),
+ .direction = renderer::LineExpansionDirection::Right};
+
+ /* Render items */
Context renderCtx(unsupported->width, unsupported->height);
- Renderer().render(renderCtx, commandRect);
-
- auto size = unsupported->width * unsupported->height;
- unsupported->data = new uint8_t[size];
- std::memcpy(unsupported->data, renderCtx.getData(), size);
+ gui::renderer::RectangleRenderer::drawFlat(
+ &renderCtx, rectangleOrigin, unsupported->width, unsupported->height, rectangleStyle);
+ gui::renderer::LineRenderer::draw45deg(
+ &renderCtx, firstDiagonalOrigin, diagonalLength, diagonalStyle, true); // Draw to the right
+ gui::renderer::LineRenderer::draw45deg(
+ &renderCtx, secondDiagonalOrigin, diagonalLength, diagonalStyle, false); // Draw to the left
+
+ const auto glyphDataSize = unsupported->width * unsupported->height;
+ unsupported->data = new uint8_t[glyphDataSize];
+ std::memcpy(unsupported->data, renderCtx.getData(), glyphDataSize);
}
void RawFont::setFallbackFont(RawFont *fallback)
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 11,8 11,8 @@
#include <map>
#include <memory>
#include <string>
-#include "FontGlyph.hpp" // for FontGlyph
-#include "FontKerning.hpp" // for FontKerning
+#include "FontGlyph.hpp"
+#include "FontKerning.hpp"
namespace gui
{
@@ 27,25 27,25 @@ namespace gui
gui::Status load(uint8_t *data);
- static const uint32_t none_char_id = std::numeric_limits<const uint32_t>().max();
+ static const std::uint32_t none_char_id = std::numeric_limits<const std::uint32_t>().max();
// structure holding detailed information about font
FontInfo info;
- // number of glyphs in the fontno
- uint32_t glyph_count;
+ // number of glyphs in the font
+ std::uint32_t glyph_count;
// offset to the beginning of the glyph data
- uint32_t glyph_data_offset;
+ std::uint32_t glyph_data_offset;
// number of kerning pairs
- uint32_t kern_count;
+ std::uint32_t kern_count;
// array of glyphs structures
- uint32_t kern_data_offset;
+ std::uint32_t kern_data_offset;
// offset to the beginning of the image data
- uint32_t image_data_offset;
- // id of the font asigned by the font manager
- uint32_t id;
+ std::uint32_t image_data_offset;
+ // id of the font assigned by the font manager
+ std::uint32_t id;
/// return glyph for selected code
/// if code is not found in font, it is searched in the fallback font, if not found - unsupportedGlyph returned
- FontGlyph *getGlyph(uint32_t id) const;
+ FontGlyph *getGlyph(std::uint32_t id) const;
/**
* @brief Returns kerning value for pair of the two characters.
@@ 53,14 53,14 @@ namespace gui
* @param id2 Code of the second character - if none_char_id then return 0
* @return Value of the kerning or 0 if pair was not found.
*/
- int32_t getKerning(uint32_t id1, uint32_t id2) const;
+ int32_t getKerning(std::uint32_t id1, std::uint32_t id2) const;
/**
* @brief Method calculates how many chars will fit specified width using current font.
* @param str UTF8 string that will be used to calculate how many chars can fit provided space.
* @param space Number of pixels in width availabale to calculate how many chars will fit.
* @return number of chars that can fit provided space;
*/
- uint32_t getCharCountInSpace(const UTF8 &str, const uint32_t space) const;
+ std::uint32_t getCharCountInSpace(const UTF8 &str, const std::uint32_t space) const;
/**
* @brief Calculates how many pixels will occupy selected part of the string.
* @param str String used as a source of text.
@@ 68,23 68,23 @@ namespace gui
* @param count Number of characters that should be used during calculating pixels width.
* @return Number of pixels in width occupied by selected part of the text.
*/
- uint32_t getPixelWidth(const UTF8 &str, const uint32_t start, const uint32_t count) const;
+ std::uint32_t getPixelWidth(const UTF8 &str, const std::uint32_t start, const std::uint32_t count) const;
/**
* @brief Calculates how many pixels will occupy string.
* @param str String used as a source of text.
* @return Number of pixels in width occupied by string.
*/
- uint32_t getPixelWidth(const UTF8 &str) const;
+ std::uint32_t getPixelWidth(const UTF8 &str) const;
/**
* @brief returns number of pixels occupied by character horizontally.
*
* if previous char is set - then tries to append kerning
*/
- uint32_t getCharPixelWidth(uint32_t charCode, uint32_t previousChar = none_char_id) const;
+ std::uint32_t getCharPixelWidth(std::uint32_t charCode, std::uint32_t previousChar = none_char_id) const;
/**
* @brief Returns number of pixels occupied by the character vertically.
*/
- uint32_t getCharPixelHeight(uint32_t charCode);
+ std::uint32_t getCharPixelHeight(std::uint32_t charCode);
const std::string getName()
{
return info.face;
@@ 92,8 92,8 @@ namespace gui
void setFallbackFont(RawFont *font);
private:
- std::map<uint32_t, std::unique_ptr<FontGlyph>> glyphs;
- std::map<uint32_t, std::map<uint32_t, std::unique_ptr<FontKerning>>> kerning;
+ std::map<std::uint32_t, std::unique_ptr<FontGlyph>> glyphs;
+ std::map<std::uint32_t, std::map<std::uint32_t, std::unique_ptr<FontKerning>>> kerning;
/// if the fallback font is set it is used in case of a glyph being unsupported in the primary font
RawFont *fallback_font = nullptr;
/// the glyph used when requested glyph is unsupported in the font (and the fallback font if one is set)
@@ 103,9 103,9 @@ namespace gui
/// return glyph for selected code
/// if code is not found - nullptr is returned
- FontGlyph *findGlyph(uint32_t id) const;
+ FontGlyph *findGlyph(std::uint32_t id) const;
/// return glyph for selected code
/// if code is not found - nullptr is returned
- FontGlyph *findGlyphFallback(uint32_t id) const;
+ FontGlyph *findGlyphFallback(std::uint32_t id) const;
};
} /* namespace gui */