mirror of
https://libwebsockets.org/repo/libwebsockets
synced 2024-11-22 00:57:52 +00:00
e3dca87f23
This adds optional display list support to lws_display, using DLOs (Display List Objects). DLOs for rectangle / rounded rectangle (with circle as the degenerate case), PNGs, JPEG and compressed, antialiased bitmapped fonts and text primitives are provided. Logical DLOs are instantiated on heap and listed into an lws_display_list owner, DLOs handle attributes like position, bounding box, colour + opacity, and local error diffusion backing buffer. When the display list is complete, it can be rasterized a line at a time, with scoped error diffusion resolved, such that no allocation for the framebuffer is required at any point. DLOs are freed as the rasterization moves beyond their bounding box. Adds a platform registry binding names and other metadata to lws_display fonts / PNGs / JPEGs. Provides registration, destruction and best match selection apis.
175 lines
5.4 KiB
C++
175 lines
5.4 KiB
C++
// Class to store the data of a font while it is being processed.
|
|
// This class can be safely cloned using the default copy constructor.
|
|
|
|
#pragma once
|
|
#include <cstdint>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <fstream>
|
|
#include <memory>
|
|
#include <map>
|
|
|
|
namespace mcufont
|
|
{
|
|
|
|
class DataFile
|
|
{
|
|
public:
|
|
typedef std::vector<uint8_t> pixels_t;
|
|
|
|
struct dictentry_t
|
|
{
|
|
pixels_t replacement; // The expanded version of this block.
|
|
int score; // Number of bytes that having this entry saves.
|
|
bool ref_encode; // Encode using references to other dictionary entries.
|
|
|
|
dictentry_t(): score(0), ref_encode(false) {}
|
|
};
|
|
|
|
struct glyphentry_t
|
|
{
|
|
pixels_t data; // The full data of the glyph.
|
|
std::vector<int> chars; // Characters that this glyph represents.
|
|
int width; // Tracking width of the character.
|
|
};
|
|
|
|
struct fontinfo_t
|
|
{
|
|
std::string name; // Name of the typeface
|
|
int max_width; // Width of the character bounding box.
|
|
int max_height; // Height of the character bounding box.
|
|
int baseline_x; // X coordinate (from left) of the baseline.
|
|
int baseline_y; // Y coordinate (from top) of the baseline.
|
|
int line_height; // Line height (vertical advance).
|
|
int flags;
|
|
};
|
|
|
|
static const int FLAG_MONOSPACE = 0x01;
|
|
static const int FLAG_BW = 0x02;
|
|
|
|
// Construct from data in memory.
|
|
DataFile(const std::vector<dictentry_t> &dictionary,
|
|
const std::vector<glyphentry_t> &glyphs,
|
|
const fontinfo_t &fontinfo);
|
|
|
|
// Save to a file (custom format)
|
|
void Save(std::ostream &file) const;
|
|
|
|
// Load from a file (custom format)
|
|
// Returns nullptr if load fails.
|
|
static std::unique_ptr<DataFile> Load(std::istream &file);
|
|
|
|
// Get or set an entry in the dictionary. The size of the dictionary
|
|
// is constant. Entries 0 to 23 are reserved for special purposes.
|
|
static const size_t dictionarysize = 256 - 24;
|
|
const dictentry_t &GetDictionaryEntry(size_t index) const
|
|
{ return m_dictionary.at(index); }
|
|
void SetDictionaryEntry(size_t index, const dictentry_t &value);
|
|
const std::vector<dictentry_t> &GetDictionary() const
|
|
{ return m_dictionary; }
|
|
|
|
// Get the index of the dictionary entry with the lowest score.
|
|
size_t GetLowScoreIndex() const
|
|
{ return m_lowscoreindex; }
|
|
|
|
// Get an entry in the glyph table.
|
|
size_t GetGlyphCount() const
|
|
{ return m_glyphtable.size(); }
|
|
const glyphentry_t &GetGlyphEntry(size_t index) const
|
|
{ return m_glyphtable.at(index); }
|
|
const std::vector<glyphentry_t> &GetGlyphTable() const
|
|
{ return m_glyphtable; }
|
|
|
|
// Create a map of char indices to glyph indices
|
|
std::map<size_t, size_t> GetCharToGlyphMap() const;
|
|
|
|
// Get the information that applies to all glyphs.
|
|
const fontinfo_t &GetFontInfo() const
|
|
{ return m_fontinfo; }
|
|
|
|
// Show a glyph as text.
|
|
std::string GlyphToText(size_t index) const;
|
|
|
|
// Get the random generator seed
|
|
// The seed is stored in the datafile to get deterministic behaviour
|
|
// for debugging.
|
|
uint32_t GetSeed() const { return m_seed; }
|
|
void SetSeed(uint32_t seed) { m_seed = seed; }
|
|
|
|
private:
|
|
std::vector<dictentry_t> m_dictionary;
|
|
std::vector<glyphentry_t> m_glyphtable;
|
|
fontinfo_t m_fontinfo;
|
|
uint32_t m_seed;
|
|
|
|
size_t m_lowscoreindex;
|
|
|
|
void UpdateLowScoreIndex();
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream& os, const DataFile::pixels_t& str);
|
|
std::istream& operator>>(std::istream& is, DataFile::pixels_t& str);
|
|
|
|
}
|
|
|
|
#ifdef CXXTEST_RUNNING
|
|
#include <cxxtest/TestSuite.h>
|
|
|
|
using namespace mcufont;
|
|
|
|
class DataFileTests: public CxxTest::TestSuite
|
|
{
|
|
public:
|
|
void testFileLoad()
|
|
{
|
|
std::istringstream s(testfile);
|
|
std::unique_ptr<DataFile> f = DataFile::Load(s);
|
|
|
|
TS_ASSERT_EQUALS(f->GetFontInfo().name, "Sans Serif");
|
|
TS_ASSERT_EQUALS(f->GetFontInfo().max_width, 4);
|
|
TS_ASSERT_EQUALS(f->GetFontInfo().max_height, 6);
|
|
TS_ASSERT_EQUALS(f->GetDictionaryEntry(0).score, 5);
|
|
TS_ASSERT_EQUALS(f->GetDictionaryEntry(1).score, 13);
|
|
TS_ASSERT_EQUALS(f->GetGlyphCount(), 3);
|
|
|
|
DataFile::pixels_t expected = {
|
|
0,15,0,15, 0,15,0,15, 0,15,0,15, 0,15,0,15, 0,15,0,15, 0,15,0,15
|
|
};
|
|
TS_ASSERT_EQUALS(f->GetGlyphEntry(0).data.size(), 24);
|
|
TS_ASSERT(f->GetGlyphEntry(0).data == expected);
|
|
}
|
|
|
|
void testFileSave()
|
|
{
|
|
std::istringstream is1(testfile);
|
|
std::unique_ptr<DataFile> f1 = DataFile::Load(is1);
|
|
|
|
std::ostringstream os;
|
|
f1->Save(os);
|
|
|
|
std::string text = os.str();
|
|
std::istringstream is2(text);
|
|
std::unique_ptr<DataFile> f2 = DataFile::Load(is2);
|
|
|
|
TS_ASSERT_EQUALS(f1->GetFontInfo().name, f2->GetFontInfo().name);
|
|
TS_ASSERT(f1->GetGlyphEntry(0).data == f2->GetGlyphEntry(0).data);
|
|
}
|
|
|
|
private:
|
|
static constexpr const char *testfile =
|
|
"Version 1\n"
|
|
"FontName Sans Serif\n"
|
|
"MaxWidth 4\n"
|
|
"MaxHeight 6\n"
|
|
"BaselineX 1\n"
|
|
"BaselineY 1\n"
|
|
"DictEntry 5 0 0F0F0\n"
|
|
"DictEntry 13 0 F0F0F0\n"
|
|
"DictEntry 1 0 F0F0F0\n"
|
|
"Glyph 1,2,3 4 0F0F0F0F0F0F0F0F0F0F0F0F\n"
|
|
"Glyph 4 4 0F0F0F0F0F0F0F0F0F0F0F0F\n"
|
|
"Glyph 5 4 0F0F0F0F0F0F0F0F0F0F0F0F\n";
|
|
};
|
|
|
|
#endif
|