fix: various bug fixes in desktop components
This commit is contained in:
@@ -177,6 +177,9 @@ struct DesktopState {
|
||||
Rect temp_icon_rect;
|
||||
|
||||
int screen_w, screen_h;
|
||||
uint32_t* background_cache;
|
||||
int background_cache_pitch;
|
||||
bool background_cache_dirty;
|
||||
|
||||
// IDs of external windows we've sent a close event to but that haven't
|
||||
// been destroyed yet by their owning process. Prevents the poll loop
|
||||
|
||||
@@ -12,16 +12,17 @@ namespace gui {
|
||||
|
||||
// Fast horizontal line
|
||||
inline void draw_hline(Framebuffer& fb, int x, int y, int w, Color c) {
|
||||
for (int i = 0; i < w; i++) fb.put_pixel(x + i, y, c);
|
||||
fb.fill_rect(x, y, w, 1, c);
|
||||
}
|
||||
|
||||
// Fast vertical line
|
||||
inline void draw_vline(Framebuffer& fb, int x, int y, int h, Color c) {
|
||||
for (int i = 0; i < h; i++) fb.put_pixel(x, y + i, c);
|
||||
fb.fill_rect(x, y, 1, h, c);
|
||||
}
|
||||
|
||||
// Rectangle outline
|
||||
inline void draw_rect(Framebuffer& fb, int x, int y, int w, int h, Color c) {
|
||||
if (w <= 0 || h <= 0) return;
|
||||
draw_hline(fb, x, y, w, c);
|
||||
draw_hline(fb, x, y + h - 1, w, c);
|
||||
draw_vline(fb, x, y, h, c);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <montauk/syscall.h>
|
||||
#include <montauk/string.h>
|
||||
#include "gui/gui.hpp"
|
||||
|
||||
namespace gui {
|
||||
@@ -18,6 +19,46 @@ class Framebuffer {
|
||||
int fb_height;
|
||||
int fb_pitch; // in bytes
|
||||
|
||||
static inline void fill_pixels(uint32_t* dst, int count, uint32_t pixel) {
|
||||
if (!dst || count <= 0) return;
|
||||
|
||||
uint64_t pixel64 = ((uint64_t)pixel << 32) | pixel;
|
||||
if (((uint64_t)dst & 4) && count > 0) {
|
||||
*dst++ = pixel;
|
||||
count--;
|
||||
}
|
||||
|
||||
uint64_t* dst64 = (uint64_t*)dst;
|
||||
int pairs = count / 2;
|
||||
for (int i = 0; i < pairs; i++) {
|
||||
dst64[i] = pixel64;
|
||||
}
|
||||
|
||||
if (count & 1) {
|
||||
((uint32_t*)(dst64 + pairs))[0] = pixel;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t blend_pixel(uint32_t dst, uint32_t src, uint32_t alpha) {
|
||||
uint32_t inv_a = 255 - alpha;
|
||||
uint32_t sr = (src >> 16) & 0xFF;
|
||||
uint32_t sg = (src >> 8) & 0xFF;
|
||||
uint32_t sb = src & 0xFF;
|
||||
uint32_t dr = (dst >> 16) & 0xFF;
|
||||
uint32_t dg = (dst >> 8) & 0xFF;
|
||||
uint32_t db = dst & 0xFF;
|
||||
|
||||
uint32_t rr = alpha * sr + inv_a * dr;
|
||||
uint32_t gg = alpha * sg + inv_a * dg;
|
||||
uint32_t bb = alpha * sb + inv_a * db;
|
||||
|
||||
rr = (rr + 1 + (rr >> 8)) >> 8;
|
||||
gg = (gg + 1 + (gg >> 8)) >> 8;
|
||||
bb = (bb + 1 + (bb >> 8)) >> 8;
|
||||
|
||||
return 0xFF000000 | (rr << 16) | (gg << 8) | bb;
|
||||
}
|
||||
|
||||
public:
|
||||
Framebuffer() : hw_fb(nullptr), back_buf(nullptr), fb_width(0), fb_height(0), fb_pitch(0) {
|
||||
Montauk::FbInfo info;
|
||||
@@ -75,6 +116,8 @@ public:
|
||||
}
|
||||
|
||||
inline void fill_rect(int x, int y, int w, int h, Color c) {
|
||||
if (!back_buf) return;
|
||||
|
||||
// Clip to screen bounds
|
||||
int x0 = x < 0 ? 0 : x;
|
||||
int y0 = y < 0 ? 0 : y;
|
||||
@@ -88,9 +131,7 @@ public:
|
||||
|
||||
for (int row = y0; row < y1; row++) {
|
||||
uint32_t* dst = (uint32_t*)((uint8_t*)back_buf + row * fb_pitch) + x0;
|
||||
for (int col = 0; col < clipped_w; col++) {
|
||||
dst[col] = pixel;
|
||||
}
|
||||
fill_pixels(dst, clipped_w, pixel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,59 +177,85 @@ public:
|
||||
}
|
||||
|
||||
inline void blit(int x, int y, int w, int h, const uint32_t* pixels) {
|
||||
for (int row = 0; row < h; row++) {
|
||||
int dy = y + row;
|
||||
if (dy < 0 || dy >= fb_height) continue;
|
||||
for (int col = 0; col < w; col++) {
|
||||
int dx = x + col;
|
||||
if (dx < 0 || dx >= fb_width) continue;
|
||||
uint32_t* dst_row = (uint32_t*)((uint8_t*)back_buf + dy * fb_pitch);
|
||||
dst_row[dx] = pixels[row * w + col];
|
||||
}
|
||||
if (!back_buf || !pixels || w <= 0 || h <= 0) return;
|
||||
|
||||
int src_x = 0;
|
||||
int src_y = 0;
|
||||
int dst_x = x;
|
||||
int dst_y = y;
|
||||
int copy_w = w;
|
||||
int copy_h = h;
|
||||
|
||||
if (dst_x < 0) { src_x = -dst_x; copy_w += dst_x; dst_x = 0; }
|
||||
if (dst_y < 0) { src_y = -dst_y; copy_h += dst_y; dst_y = 0; }
|
||||
if (dst_x + copy_w > fb_width) copy_w = fb_width - dst_x;
|
||||
if (dst_y + copy_h > fb_height) copy_h = fb_height - dst_y;
|
||||
if (copy_w <= 0 || copy_h <= 0) return;
|
||||
|
||||
uint64_t row_bytes = (uint64_t)copy_w * sizeof(uint32_t);
|
||||
for (int row = 0; row < copy_h; row++) {
|
||||
uint32_t* dst = (uint32_t*)((uint8_t*)back_buf + (dst_y + row) * fb_pitch) + dst_x;
|
||||
const uint32_t* src = pixels + (src_y + row) * w + src_x;
|
||||
montauk::memcpy(dst, src, row_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
inline void blit_alpha(int x, int y, int w, int h, const uint32_t* pixels) {
|
||||
for (int row = 0; row < h; row++) {
|
||||
int dy = y + row;
|
||||
if (dy < 0 || dy >= fb_height) continue;
|
||||
for (int col = 0; col < w; col++) {
|
||||
int dx = x + col;
|
||||
if (dx < 0 || dx >= fb_width) continue;
|
||||
if (!back_buf || !pixels || w <= 0 || h <= 0) return;
|
||||
|
||||
uint32_t src = pixels[row * w + col];
|
||||
uint8_t sa = (src >> 24) & 0xFF;
|
||||
int src_x = 0;
|
||||
int src_y = 0;
|
||||
int dst_x = x;
|
||||
int dst_y = y;
|
||||
int copy_w = w;
|
||||
int copy_h = h;
|
||||
|
||||
if (dst_x < 0) { src_x = -dst_x; copy_w += dst_x; dst_x = 0; }
|
||||
if (dst_y < 0) { src_y = -dst_y; copy_h += dst_y; dst_y = 0; }
|
||||
if (dst_x + copy_w > fb_width) copy_w = fb_width - dst_x;
|
||||
if (dst_y + copy_h > fb_height) copy_h = fb_height - dst_y;
|
||||
if (copy_w <= 0 || copy_h <= 0) return;
|
||||
|
||||
for (int row = 0; row < copy_h; row++) {
|
||||
uint32_t* dst = (uint32_t*)((uint8_t*)back_buf + (dst_y + row) * fb_pitch) + dst_x;
|
||||
const uint32_t* src = pixels + (src_y + row) * w + src_x;
|
||||
for (int col = 0; col < copy_w; col++) {
|
||||
uint32_t s = src[col];
|
||||
uint8_t sa = (s >> 24) & 0xFF;
|
||||
if (sa == 0) continue;
|
||||
|
||||
uint8_t sr = (src >> 16) & 0xFF;
|
||||
uint8_t sg = (src >> 8) & 0xFF;
|
||||
uint8_t sb = src & 0xFF;
|
||||
|
||||
if (sa == 255) {
|
||||
uint32_t* dst_row = (uint32_t*)((uint8_t*)back_buf + dy * fb_pitch);
|
||||
dst_row[dx] = src;
|
||||
dst[col] = s;
|
||||
continue;
|
||||
}
|
||||
|
||||
Color sc = {sr, sg, sb, sa};
|
||||
put_pixel_alpha(dx, dy, sc);
|
||||
dst[col] = blend_pixel(dst[col], s, sa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void copy_from(const uint32_t* pixels, int src_pitch_bytes) {
|
||||
if (!back_buf || !pixels || src_pitch_bytes <= 0) return;
|
||||
uint64_t row_bytes = (uint64_t)fb_width * sizeof(uint32_t);
|
||||
for (int row = 0; row < fb_height; row++) {
|
||||
uint32_t* dst = (uint32_t*)((uint8_t*)back_buf + row * fb_pitch);
|
||||
const uint32_t* src = (const uint32_t*)((const uint8_t*)pixels + row * src_pitch_bytes);
|
||||
montauk::memcpy(dst, src, row_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
inline void clear(Color c) {
|
||||
fill_rect(0, 0, fb_width, fb_height, c);
|
||||
}
|
||||
|
||||
inline void flip() {
|
||||
if (!hw_fb || !back_buf) return;
|
||||
|
||||
// Copy back buffer to hardware framebuffer, row by row (pitch may differ)
|
||||
int row_pixels = fb_width;
|
||||
uint64_t row_bytes = (uint64_t)fb_width * sizeof(uint32_t);
|
||||
for (int y = 0; y < fb_height; y++) {
|
||||
uint32_t* src = (uint32_t*)((uint8_t*)back_buf + y * fb_pitch);
|
||||
uint32_t* dst = (uint32_t*)((uint8_t*)hw_fb + y * fb_pitch);
|
||||
for (int x = 0; x < row_pixels; x++) {
|
||||
dst[x] = src[x];
|
||||
}
|
||||
montauk::memcpy(dst, src, row_bytes);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -237,6 +237,13 @@ struct TrueTypeFont {
|
||||
GlyphCache* gc = get_cache(pixel_size);
|
||||
int cx = x;
|
||||
int baseline = y + gc->ascent;
|
||||
int fb_w = fb.width();
|
||||
int fb_h = fb.height();
|
||||
int fb_pitch = fb.pitch();
|
||||
uint32_t* fb_pixels = fb.buffer();
|
||||
if (!fb_pixels) return;
|
||||
uint32_t src_rgb = 0xFF000000 | ((uint32_t)color.r << 16) |
|
||||
((uint32_t)color.g << 8) | color.b;
|
||||
|
||||
for (int i = 0; text[i]; i++) {
|
||||
CachedGlyph* g = get_glyph(gc, (unsigned char)text[i]);
|
||||
@@ -245,12 +252,41 @@ struct TrueTypeFont {
|
||||
if (g->bitmap) {
|
||||
int gx = cx + g->xoff;
|
||||
int gy = baseline + g->yoff;
|
||||
for (int row = 0; row < g->height; row++) {
|
||||
for (int col = 0; col < g->width; col++) {
|
||||
uint8_t alpha = g->bitmap[row * g->width + col];
|
||||
if (alpha > 0) {
|
||||
Color c = {color.r, color.g, color.b, alpha};
|
||||
fb.put_pixel_alpha(gx + col, gy + row, c);
|
||||
|
||||
int row0 = gy < 0 ? -gy : 0;
|
||||
int col0 = gx < 0 ? -gx : 0;
|
||||
int row1 = gy + g->height > fb_h ? fb_h - gy : g->height;
|
||||
int col1 = gx + g->width > fb_w ? fb_w - gx : g->width;
|
||||
|
||||
if (row0 < row1 && col0 < col1) {
|
||||
for (int row = row0; row < row1; row++) {
|
||||
uint8_t* alpha_row = g->bitmap + row * g->width + col0;
|
||||
uint32_t* dst = (uint32_t*)((uint8_t*)fb_pixels + (gy + row) * fb_pitch) + gx + col0;
|
||||
|
||||
for (int col = col0; col < col1; col++) {
|
||||
uint8_t alpha = *alpha_row++;
|
||||
if (alpha == 0) {
|
||||
dst++;
|
||||
continue;
|
||||
}
|
||||
if (alpha == 255) {
|
||||
*dst++ = src_rgb;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t d = *dst;
|
||||
uint32_t inv_a = 255 - alpha;
|
||||
uint32_t dr = (d >> 16) & 0xFF;
|
||||
uint32_t dg = (d >> 8) & 0xFF;
|
||||
uint32_t db = d & 0xFF;
|
||||
uint32_t rr = alpha * color.r + inv_a * dr;
|
||||
uint32_t gg = alpha * color.g + inv_a * dg;
|
||||
uint32_t bb = alpha * color.b + inv_a * db;
|
||||
|
||||
rr = (rr + 1 + (rr >> 8)) >> 8;
|
||||
gg = (gg + 1 + (gg >> 8)) >> 8;
|
||||
bb = (bb + 1 + (bb >> 8)) >> 8;
|
||||
*dst++ = 0xFF000000 | (rr << 16) | (gg << 8) | bb;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -427,6 +463,7 @@ namespace fonts {
|
||||
inline bool init() {
|
||||
auto load = [](const char* path) -> TrueTypeFont* {
|
||||
TrueTypeFont* f = (TrueTypeFont*)montauk::malloc(sizeof(TrueTypeFont));
|
||||
if (!f) return nullptr;
|
||||
montauk::memset(f, 0, sizeof(TrueTypeFont));
|
||||
if (!f->init(path)) {
|
||||
montauk::mfree(f);
|
||||
|
||||
Reference in New Issue
Block a user