Compare commits
8 Commits
50a3533322
...
e4982a1a5c
Author | SHA1 | Date |
---|---|---|
Bananymous | e4982a1a5c | |
Bananymous | cea6dedccc | |
Bananymous | e6ed5a388d | |
Bananymous | b89fc3fe87 | |
Bananymous | 57ae74f908 | |
Bananymous | 1a6804b4b4 | |
Bananymous | 82e6a3582d | |
Bananymous | 11a4e4faa2 |
|
@ -0,0 +1,13 @@
|
|||
Diagnostics:
|
||||
Suppress: target_unsupported_type
|
||||
|
||||
CompileFlags:
|
||||
Remove: [
|
||||
-fstrict-volatile-bitfields,
|
||||
-fno-tree-loop-distribute-patterns
|
||||
]
|
||||
Add: [
|
||||
-D__banan_os__,
|
||||
-D__arch__=x86_64,
|
||||
-D__x86_64__
|
||||
]
|
|
@ -2,5 +2,9 @@
|
|||
"cmake.configureOnOpen": false,
|
||||
"editor.tabSize": 4,
|
||||
"editor.insertSpaces": false,
|
||||
"editor.detectIndentation": false
|
||||
"editor.detectIndentation": false,
|
||||
"clangd.arguments": [
|
||||
"--compile-commands-dir=${workspaceFolder}/build",
|
||||
"-header-insertion=never"
|
||||
]
|
||||
}
|
|
@ -29,6 +29,8 @@ set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
|||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
set(BUILD_SHARED_LIBS True)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
|
||||
|
|
|
@ -121,6 +121,10 @@ namespace Kernel
|
|||
m_background = TerminalColor::BLACK;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
BAN::swap(m_foreground, m_background);
|
||||
break;
|
||||
|
||||
case 30: m_foreground = TerminalColor::BLACK; break;
|
||||
case 31: m_foreground = TerminalColor::RED; break;
|
||||
case 32: m_foreground = TerminalColor::GREEN; break;
|
||||
|
|
|
@ -20,7 +20,7 @@ foreach(library ${USERSPACE_LIBRARIES})
|
|||
# This is to allow cmake to link when libc updates
|
||||
target_link_options(${library_lower} PRIVATE -nolibc)
|
||||
# Default compile options
|
||||
target_compile_options(${library_lower} PRIVATE -g -O2)
|
||||
target_compile_options(${library_lower} PRIVATE -g -O2 -Wall -Wextra -Werror)
|
||||
|
||||
target_compile_definitions(${library_lower} PRIVATE __enable_sse=${BANAN_ENABLE_SSE})
|
||||
if (NOT BANAN_ENABLE_SSE)
|
||||
|
|
|
@ -50,6 +50,16 @@ static void integer_to_string(char* buffer, T value, int base, bool upper, forma
|
|||
options.zero_padded = false;
|
||||
}
|
||||
|
||||
if (value == 0 && options.alternate_form)
|
||||
{
|
||||
if (digits == 0 && base == 8)
|
||||
digits = 1;
|
||||
for (int i = 0; i < digits; i++)
|
||||
buffer[i] = '0';
|
||||
buffer[digits] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
auto digit_char = [](int digit, bool upper)
|
||||
{
|
||||
if (digit < 10)
|
||||
|
@ -83,6 +93,7 @@ static void integer_to_string(char* buffer, T value, int base, bool upper, forma
|
|||
{
|
||||
prefix_length = 1;
|
||||
prefix[0] = '0';
|
||||
digits--;
|
||||
}
|
||||
else if (options.alternate_form && base == 16)
|
||||
{
|
||||
|
@ -361,7 +372,9 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun
|
|||
format--;
|
||||
format++;
|
||||
|
||||
char conversion[128];
|
||||
// FIXME: this should be thread-local to keep
|
||||
// satisfy multithreaded requirement
|
||||
static char conversion[4096];
|
||||
const char* string = nullptr;
|
||||
|
||||
int length = -1;
|
||||
|
|
|
@ -135,14 +135,53 @@ namespace LibGUI
|
|||
draw_character(text[i], font, tl_x + (int32_t)(i * font.width()), tl_y, color);
|
||||
}
|
||||
|
||||
void Window::shift_vertical(int32_t amount)
|
||||
void Window::shift_vertical(int32_t amount, uint32_t fill_color)
|
||||
{
|
||||
uint32_t amount_abs = BAN::Math::abs(amount);
|
||||
const uint32_t amount_abs = BAN::Math::abs(amount);
|
||||
if (amount_abs == 0 || amount_abs >= height())
|
||||
return;
|
||||
|
||||
uint32_t* dst = (amount > 0) ? m_framebuffer.data() + width() * amount_abs : m_framebuffer.data();
|
||||
uint32_t* src = (amount < 0) ? m_framebuffer.data() + width() * amount_abs : m_framebuffer.data();
|
||||
memmove(dst, src, width() * (height() - amount_abs) * 4);
|
||||
|
||||
const uint32_t y_lo = (amount < 0) ? height() - amount_abs : 0;
|
||||
const uint32_t y_hi = (amount < 0) ? height() : amount_abs;
|
||||
for (uint32_t y = y_lo; y < y_hi; y++)
|
||||
for (uint32_t x = 0; x < width(); x++)
|
||||
set_pixel(x, y, fill_color);
|
||||
}
|
||||
|
||||
void Window::copy_horizontal_slice(int32_t dst_y, int32_t src_y, uint32_t uamount, uint32_t fill_color)
|
||||
{
|
||||
int32_t amount = uamount;
|
||||
if (dst_y < 0)
|
||||
{
|
||||
amount -= -dst_y;
|
||||
src_y += -dst_y;
|
||||
dst_y = 0;
|
||||
}
|
||||
|
||||
amount = BAN::Math::min<int32_t>(amount, height() - dst_y);
|
||||
if (amount <= 0)
|
||||
return;
|
||||
|
||||
const int32_t copy_src_y = BAN::Math::clamp<int32_t>(src_y, 0, height());
|
||||
const int32_t copy_amount = BAN::Math::clamp<int32_t>(src_y + amount, 0, height()) - copy_src_y;
|
||||
if (copy_amount > 0)
|
||||
{
|
||||
memmove(
|
||||
&m_framebuffer[width() * (dst_y + (copy_src_y - src_y))],
|
||||
&m_framebuffer[width() * copy_src_y],
|
||||
copy_amount * width() * 4
|
||||
);
|
||||
}
|
||||
|
||||
const uint32_t fill_y_off = (src_y < copy_src_y) ? 0 : copy_amount;
|
||||
const uint32_t fill_amount = amount - copy_amount;
|
||||
for (uint32_t i = 0; i < fill_amount; i++)
|
||||
for (uint32_t x = 0; x < width(); x++)
|
||||
set_pixel(x, dst_y + fill_y_off + i, fill_color);
|
||||
}
|
||||
|
||||
bool Window::clamp_to_framebuffer(int32_t& signed_x, int32_t& signed_y, uint32_t& width, uint32_t& height) const
|
||||
|
|
|
@ -125,7 +125,13 @@ namespace LibGUI
|
|||
void draw_character(uint32_t codepoint, const LibFont::Font& font, int32_t x, int32_t y, uint32_t color);
|
||||
void draw_text(BAN::StringView text, const LibFont::Font& font, int32_t x, int32_t y, uint32_t color);
|
||||
|
||||
void shift_vertical(int32_t amount);
|
||||
// shift whole vertically by amount pixels, sign determines the direction
|
||||
// fill_color is used to fill "new" data
|
||||
void shift_vertical(int32_t amount, uint32_t fill_color);
|
||||
|
||||
// copy horizontal slice [src_y, src_y + amount[ to [dst_y, dst_y + amount[
|
||||
// fill_color is used when copying data outside of window bounds
|
||||
void copy_horizontal_slice(int32_t dst_y, int32_t src_y, uint32_t amount, uint32_t fill_color);
|
||||
|
||||
bool invalidate(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||
bool invalidate() { return invalidate(0, 0, width(), height()); }
|
||||
|
|
|
@ -522,6 +522,159 @@ namespace LibImage
|
|||
}
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<uint64_t> parse_pixel_data(BAN::Vector<Image::Color>& color_bitmap, uint64_t image_width, uint64_t image_height, const IHDR& ihdr, const BAN::Vector<Image::Color>& palette, BAN::ByteSpan encoded_data)
|
||||
{
|
||||
ASSERT(color_bitmap.size() >= image_height * image_width);
|
||||
|
||||
const uint8_t bits_per_channel = ihdr.bit_depth;
|
||||
const uint8_t channels =
|
||||
[&]() -> uint8_t
|
||||
{
|
||||
switch (ihdr.colour_type)
|
||||
{
|
||||
case ColourType::Greyscale: return 1;
|
||||
case ColourType::Truecolour: return 3;
|
||||
case ColourType::IndexedColour: return 1;
|
||||
case ColourType::GreyscaleAlpha: return 2;
|
||||
case ColourType::TruecolourAlpha: return 4;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}();
|
||||
|
||||
const auto extract_channel =
|
||||
[&](auto& bit_buffer) -> uint8_t
|
||||
{
|
||||
uint16_t tmp = MUST(bit_buffer.get_bits(bits_per_channel));
|
||||
switch (bits_per_channel)
|
||||
{
|
||||
case 1: return tmp * 0xFF;
|
||||
case 2: return tmp * 0xFF / 3;
|
||||
case 4: return tmp * 0xFF / 15;
|
||||
case 8: return tmp;
|
||||
case 16: return tmp & 0xFF; // NOTE: stored in big endian
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
};
|
||||
|
||||
const auto extract_color =
|
||||
[&](auto& bit_buffer) -> Image::Color
|
||||
{
|
||||
uint8_t tmp;
|
||||
switch (ihdr.colour_type)
|
||||
{
|
||||
case ColourType::Greyscale:
|
||||
tmp = extract_channel(bit_buffer);
|
||||
return Image::Color {
|
||||
.r = tmp,
|
||||
.g = tmp,
|
||||
.b = tmp,
|
||||
.a = 0xFF
|
||||
};
|
||||
case ColourType::Truecolour:
|
||||
return Image::Color {
|
||||
.r = extract_channel(bit_buffer),
|
||||
.g = extract_channel(bit_buffer),
|
||||
.b = extract_channel(bit_buffer),
|
||||
.a = 0xFF
|
||||
};
|
||||
case ColourType::IndexedColour:
|
||||
return palette[MUST(bit_buffer.get_bits(bits_per_channel))];
|
||||
case ColourType::GreyscaleAlpha:
|
||||
tmp = extract_channel(bit_buffer);
|
||||
return Image::Color {
|
||||
.r = tmp,
|
||||
.g = tmp,
|
||||
.b = tmp,
|
||||
.a = extract_channel(bit_buffer)
|
||||
};
|
||||
case ColourType::TruecolourAlpha:
|
||||
return Image::Color {
|
||||
.r = extract_channel(bit_buffer),
|
||||
.g = extract_channel(bit_buffer),
|
||||
.b = extract_channel(bit_buffer),
|
||||
.a = extract_channel(bit_buffer)
|
||||
};
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
};
|
||||
|
||||
constexpr auto paeth_predictor =
|
||||
[](int16_t a, int16_t b, int16_t c) -> uint8_t
|
||||
{
|
||||
int16_t p = a + b - c;
|
||||
int16_t pa = BAN::Math::abs(p - a);
|
||||
int16_t pb = BAN::Math::abs(p - b);
|
||||
int16_t pc = BAN::Math::abs(p - c);
|
||||
if (pa <= pb && pa <= pc)
|
||||
return a;
|
||||
if (pb <= pc)
|
||||
return b;
|
||||
return c;
|
||||
};
|
||||
|
||||
const uint64_t bytes_per_scanline = BAN::Math::div_round_up<uint64_t>(image_width * channels * bits_per_channel, 8);
|
||||
const uint64_t pitch = bytes_per_scanline + 1;
|
||||
|
||||
if (encoded_data.size() < pitch * image_height)
|
||||
{
|
||||
dwarnln_if(DEBUG_PNG, "PNG does not contain enough image data");
|
||||
return BAN::Error::from_errno(ENODATA);
|
||||
}
|
||||
|
||||
BAN::Vector<uint8_t> zero_scanline;
|
||||
TRY(zero_scanline.resize(bytes_per_scanline, 0));
|
||||
|
||||
BAN::Vector<BAN::ConstByteSpan> encoded_data_wrapper;
|
||||
TRY(encoded_data_wrapper.push_back({}));
|
||||
|
||||
const uint8_t filter_offset = (bits_per_channel < 8) ? 1 : channels * (bits_per_channel / 8);
|
||||
|
||||
for (uint64_t y = 0; y < image_height; y++)
|
||||
{
|
||||
auto scanline = encoded_data.slice((y - 0) * pitch + 1, bytes_per_scanline);
|
||||
auto scanline_above = (y > 0) ? encoded_data.slice((y - 1) * pitch + 1, bytes_per_scanline) : BAN::ConstByteSpan(zero_scanline.span());
|
||||
|
||||
auto filter_type = static_cast<FilterType>(encoded_data[y * pitch]);
|
||||
switch (filter_type)
|
||||
{
|
||||
case FilterType::None:
|
||||
break;
|
||||
case FilterType::Sub:
|
||||
for (uint64_t x = filter_offset; x < bytes_per_scanline; x++)
|
||||
scanline[x] += scanline[x - filter_offset];
|
||||
break;
|
||||
case FilterType::Up:
|
||||
for (uint64_t x = 0; x < bytes_per_scanline; x++)
|
||||
scanline[x] += scanline_above[x];
|
||||
break;
|
||||
case FilterType::Average:
|
||||
for (uint8_t i = 0; i < filter_offset; i++)
|
||||
scanline[i] += scanline_above[i] / 2;
|
||||
for (uint64_t x = filter_offset; x < bytes_per_scanline; x++)
|
||||
scanline[x] += ((uint16_t)scanline[x - filter_offset] + (uint16_t)scanline_above[x]) / 2;
|
||||
break;
|
||||
case FilterType::Paeth:
|
||||
for (uint8_t i = 0; i < filter_offset; i++)
|
||||
scanline[i] += paeth_predictor(0, scanline_above[i], 0);
|
||||
for (uint64_t x = filter_offset; x < bytes_per_scanline; x++)
|
||||
scanline[x] += paeth_predictor(scanline[x - filter_offset], scanline_above[x], scanline_above[x - filter_offset]);
|
||||
break;
|
||||
default:
|
||||
dwarnln_if(DEBUG_PNG, "invalid filter type {}", static_cast<uint8_t>(filter_type));
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
encoded_data_wrapper[0] = scanline;
|
||||
BitBuffer bit_buffer(encoded_data_wrapper);
|
||||
|
||||
for (uint64_t x = 0; x < image_width; x++)
|
||||
color_bitmap[y * image_width + x] = extract_color(bit_buffer);
|
||||
}
|
||||
|
||||
return pitch * image_height;
|
||||
}
|
||||
|
||||
bool probe_png(BAN::ConstByteSpan image_data)
|
||||
{
|
||||
if (image_data.size() < 8)
|
||||
|
@ -578,12 +731,6 @@ namespace LibImage
|
|||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
if (ihdr.interlace_method == InterlaceMethod::Adam7)
|
||||
{
|
||||
dwarnln_if(DEBUG_PNG, "PNG with interlacing is not supported");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
const uint64_t image_width = ihdr.width;
|
||||
const uint64_t image_height = ihdr.height;
|
||||
|
||||
|
@ -708,153 +855,52 @@ namespace LibImage
|
|||
dprintln_if(DEBUG_PNG, " uncompressed size {}", inflated_data.size());
|
||||
dprintln_if(DEBUG_PNG, " compression ratio {}", (double)inflated_data.size() / total_size);
|
||||
|
||||
uint8_t bits_per_channel = ihdr.bit_depth;
|
||||
uint8_t channels = 0;
|
||||
switch (ihdr.colour_type)
|
||||
BAN::Vector<Image::Color> pixel_data;
|
||||
TRY(pixel_data.resize(image_width * image_height));
|
||||
|
||||
switch (ihdr.interlace_method)
|
||||
{
|
||||
case ColourType::Greyscale: channels = 1; break;
|
||||
case ColourType::Truecolour: channels = 3; break;
|
||||
case ColourType::IndexedColour: channels = 1; break;
|
||||
case ColourType::GreyscaleAlpha: channels = 2; break;
|
||||
case ColourType::TruecolourAlpha: channels = 4; break;
|
||||
case InterlaceMethod::NoInterlace:
|
||||
TRY(parse_pixel_data(pixel_data, image_width, image_height, ihdr, palette, inflated_data));
|
||||
break;
|
||||
case InterlaceMethod::Adam7:
|
||||
{
|
||||
constexpr uint8_t x_start[] { 0, 4, 0, 2, 0, 1, 0 };
|
||||
constexpr uint8_t x_increment[] { 8, 8, 4, 4, 2, 2, 1 };
|
||||
|
||||
constexpr uint8_t y_start[] { 0, 0, 4, 0, 2, 0, 1 };
|
||||
constexpr uint8_t y_increment[] { 8, 8, 8, 4, 4, 2, 2 };
|
||||
|
||||
BAN::Vector<Image::Color> pass_pixel_data;
|
||||
TRY(pass_pixel_data.resize(((image_height + 1) / 2) * image_width));
|
||||
|
||||
for (int pass = 0; pass < 7; pass++)
|
||||
{
|
||||
const uint64_t pass_width = BAN::Math::div_round_up<uint64_t>(image_width - x_start[pass], x_increment[pass]);
|
||||
const uint64_t pass_height = BAN::Math::div_round_up<uint64_t>(image_height - y_start[pass], y_increment[pass]);
|
||||
const uint64_t nparsed = TRY(parse_pixel_data(pass_pixel_data, pass_width, pass_height, ihdr, palette, inflated_data));
|
||||
|
||||
for (uint64_t y = 0; y < pass_height; y++)
|
||||
{
|
||||
for (uint64_t x = 0; x < pass_width; x++)
|
||||
{
|
||||
const uint64_t abs_x = x * x_increment[pass] + x_start[pass];
|
||||
const uint64_t abs_y = y * y_increment[pass] + y_start[pass];
|
||||
pixel_data[abs_y * image_width + abs_x] = pass_pixel_data[y * pass_width + x];
|
||||
}
|
||||
}
|
||||
|
||||
dprintln_if(DEBUG_PNG, "Adam7 pass {} done ({}x{})", pass + 1, pass_width, pass_height);
|
||||
inflated_data = inflated_data.slice(nparsed);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
const auto extract_channel =
|
||||
[&](auto& bit_buffer) -> uint8_t
|
||||
{
|
||||
uint16_t tmp = MUST(bit_buffer.get_bits(bits_per_channel));
|
||||
switch (bits_per_channel)
|
||||
{
|
||||
case 1: return tmp * 0xFF;
|
||||
case 2: return tmp * 0xFF / 3;
|
||||
case 4: return tmp * 0xFF / 15;
|
||||
case 8: return tmp;
|
||||
case 16: return tmp & 0xFF; // NOTE: stored in big endian
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
};
|
||||
|
||||
const auto extract_color =
|
||||
[&](auto& bit_buffer) -> Image::Color
|
||||
{
|
||||
uint8_t tmp;
|
||||
switch (ihdr.colour_type)
|
||||
{
|
||||
case ColourType::Greyscale:
|
||||
tmp = extract_channel(bit_buffer);
|
||||
return Image::Color {
|
||||
.r = tmp,
|
||||
.g = tmp,
|
||||
.b = tmp,
|
||||
.a = 0xFF
|
||||
};
|
||||
case ColourType::Truecolour:
|
||||
return Image::Color {
|
||||
.r = extract_channel(bit_buffer),
|
||||
.g = extract_channel(bit_buffer),
|
||||
.b = extract_channel(bit_buffer),
|
||||
.a = 0xFF
|
||||
};
|
||||
case ColourType::IndexedColour:
|
||||
return palette[MUST(bit_buffer.get_bits(bits_per_channel))];
|
||||
case ColourType::GreyscaleAlpha:
|
||||
tmp = extract_channel(bit_buffer);
|
||||
return Image::Color {
|
||||
.r = tmp,
|
||||
.g = tmp,
|
||||
.b = tmp,
|
||||
.a = extract_channel(bit_buffer)
|
||||
};
|
||||
case ColourType::TruecolourAlpha:
|
||||
return Image::Color {
|
||||
.r = extract_channel(bit_buffer),
|
||||
.g = extract_channel(bit_buffer),
|
||||
.b = extract_channel(bit_buffer),
|
||||
.a = extract_channel(bit_buffer)
|
||||
};
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
};
|
||||
|
||||
constexpr auto paeth_predictor =
|
||||
[](int16_t a, int16_t b, int16_t c) -> uint8_t
|
||||
{
|
||||
int16_t p = a + b - c;
|
||||
int16_t pa = BAN::Math::abs(p - a);
|
||||
int16_t pb = BAN::Math::abs(p - b);
|
||||
int16_t pc = BAN::Math::abs(p - c);
|
||||
if (pa <= pb && pa <= pc)
|
||||
return a;
|
||||
if (pb <= pc)
|
||||
return b;
|
||||
return c;
|
||||
};
|
||||
|
||||
const uint64_t bytes_per_scanline = BAN::Math::div_round_up<uint64_t>(image_width * channels * bits_per_channel, 8);
|
||||
const uint64_t pitch = bytes_per_scanline + 1;
|
||||
|
||||
if (inflated_data.size() < pitch * image_height)
|
||||
{
|
||||
dwarnln_if(DEBUG_PNG, "PNG does not contain enough image data");
|
||||
return BAN::Error::from_errno(ENODATA);
|
||||
}
|
||||
|
||||
BAN::Vector<uint8_t> zero_scanline;
|
||||
TRY(zero_scanline.resize(bytes_per_scanline, 0));
|
||||
|
||||
BAN::Vector<Image::Color> color_bitmap;
|
||||
TRY(color_bitmap.resize(image_width * image_height));
|
||||
|
||||
BAN::Vector<BAN::ConstByteSpan> inflated_data_wrapper;
|
||||
TRY(inflated_data_wrapper.push_back({}));
|
||||
|
||||
const uint8_t filter_offset = (bits_per_channel < 8) ? 1 : channels * (bits_per_channel / 8);
|
||||
|
||||
for (uint64_t y = 0; y < image_height; y++)
|
||||
{
|
||||
auto scanline = inflated_data.slice((y - 0) * pitch + 1, bytes_per_scanline);
|
||||
auto scanline_above = (y > 0) ? inflated_data.slice((y - 1) * pitch + 1, bytes_per_scanline) : BAN::ConstByteSpan(zero_scanline.span());
|
||||
|
||||
auto filter_type = static_cast<FilterType>(inflated_data[y * pitch]);
|
||||
switch (filter_type)
|
||||
{
|
||||
case FilterType::None:
|
||||
break;
|
||||
case FilterType::Sub:
|
||||
for (uint64_t x = filter_offset; x < bytes_per_scanline; x++)
|
||||
scanline[x] += scanline[x - filter_offset];
|
||||
break;
|
||||
case FilterType::Up:
|
||||
for (uint64_t x = 0; x < bytes_per_scanline; x++)
|
||||
scanline[x] += scanline_above[x];
|
||||
break;
|
||||
case FilterType::Average:
|
||||
for (uint8_t i = 0; i < filter_offset; i++)
|
||||
scanline[i] += scanline_above[i] / 2;
|
||||
for (uint64_t x = filter_offset; x < bytes_per_scanline; x++)
|
||||
scanline[x] += ((uint16_t)scanline[x - filter_offset] + (uint16_t)scanline_above[x]) / 2;
|
||||
break;
|
||||
case FilterType::Paeth:
|
||||
for (uint8_t i = 0; i < filter_offset; i++)
|
||||
scanline[i] += paeth_predictor(0, scanline_above[i], 0);
|
||||
for (uint64_t x = filter_offset; x < bytes_per_scanline; x++)
|
||||
scanline[x] += paeth_predictor(scanline[x - filter_offset], scanline_above[x], scanline_above[x - filter_offset]);
|
||||
break;
|
||||
default:
|
||||
dwarnln_if(DEBUG_PNG, "invalid filter type {}", static_cast<uint8_t>(filter_type));
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
inflated_data_wrapper[0] = scanline;
|
||||
BitBuffer bit_buffer(inflated_data_wrapper);
|
||||
|
||||
for (uint64_t x = 0; x < image_width; x++)
|
||||
color_bitmap[y * image_width + x] = extract_color(bit_buffer);
|
||||
}
|
||||
|
||||
return TRY(BAN::UniqPtr<Image>::create(image_width, image_height, BAN::move(color_bitmap)));
|
||||
return TRY(BAN::UniqPtr<Image>::create(image_width, image_height, BAN::move(pixel_data)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ foreach(project ${USERSPACE_PROGRAMS})
|
|||
# This is to allow cmake to link when libc updates
|
||||
target_link_options(${project} PRIVATE -nolibc)
|
||||
# Default compile options
|
||||
target_compile_options(${project} PRIVATE -g -O2)
|
||||
target_compile_options(${project} PRIVATE -g -O2 -Wall -Wextra -Werror)
|
||||
|
||||
target_compile_definitions(${project} PRIVATE __enable_sse=${BANAN_ENABLE_SSE})
|
||||
if (NOT BANAN_ENABLE_SSE)
|
||||
|
|
|
@ -222,13 +222,13 @@ bool Terminal::read_shell()
|
|||
}
|
||||
|
||||
// find the next ansi escape code or end of buffer
|
||||
size_t non_ansi_end = i;
|
||||
ssize_t non_ansi_end = i;
|
||||
while (non_ansi_end < nread && buffer[non_ansi_end] != '\e')
|
||||
non_ansi_end++;
|
||||
|
||||
// we only need to process maximum of `rows()` newlines.
|
||||
// anything before that would get overwritten anyway
|
||||
size_t start = non_ansi_end;
|
||||
ssize_t start = non_ansi_end;
|
||||
size_t newline_count = 0;
|
||||
while (start > i && newline_count < rows())
|
||||
newline_count += (buffer[--start] == '\n');
|
||||
|
@ -239,8 +239,7 @@ bool Terminal::read_shell()
|
|||
{
|
||||
const uint32_t scroll = m_cursor.y + newline_count - rows() + 1;
|
||||
m_cursor.y -= scroll;
|
||||
m_window->shift_vertical(-scroll * (int32_t)m_font.height());
|
||||
m_window->fill_rect(0, m_window->height() - scroll * m_font.height(), m_window->width(), scroll * m_font.height(), m_bg_color);
|
||||
m_window->shift_vertical(-scroll * (int32_t)m_font.height(), m_bg_color);
|
||||
should_invalidate = { 0, 0, m_window->width(), m_window->height() };
|
||||
}
|
||||
|
||||
|
@ -270,6 +269,12 @@ void Terminal::handle_sgr()
|
|||
m_bg_color = s_colors_dark[0];
|
||||
m_fg_color = s_colors_bright[7];
|
||||
break;
|
||||
case 1:
|
||||
// FIXME: bold
|
||||
break;
|
||||
case 7:
|
||||
BAN::swap(m_fg_color, m_bg_color);
|
||||
break;
|
||||
case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37:
|
||||
m_fg_color = s_colors_dark[m_csi_info.fields[0] - 30];
|
||||
break;
|
||||
|
@ -288,18 +293,18 @@ void Terminal::handle_sgr()
|
|||
}
|
||||
}
|
||||
|
||||
void Terminal::handle_csi(char ch)
|
||||
Rectangle Terminal::handle_csi(char ch)
|
||||
{
|
||||
if (ch == ';')
|
||||
{
|
||||
m_csi_info.index++;
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (ch == '?')
|
||||
{
|
||||
m_csi_info.question = true;
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (isdigit(ch))
|
||||
|
@ -309,9 +314,10 @@ void Terminal::handle_csi(char ch)
|
|||
auto& field = m_csi_info.fields[m_csi_info.index];
|
||||
field = (BAN::Math::max(field, 0) * 10) + (ch - '0');
|
||||
}
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
|
||||
Rectangle should_invalidate;
|
||||
switch (ch)
|
||||
{
|
||||
case 'C':
|
||||
|
@ -328,66 +334,106 @@ void Terminal::handle_csi(char ch)
|
|||
m_cursor.x = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, cols()) - 1;
|
||||
break;
|
||||
case 'H':
|
||||
m_cursor.y = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, rows()) - 1;
|
||||
m_cursor.x = BAN::Math::clamp<int32_t>(m_csi_info.fields[1], 1, cols()) - 1;
|
||||
m_cursor.y = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, rows()) - 1;
|
||||
break;
|
||||
case 'J':
|
||||
{
|
||||
uint32_t rects[2][4] { { (uint32_t)-1 }, { (uint32_t)-1 } };
|
||||
Rectangle rects[2];
|
||||
size_t rect_count = 0;
|
||||
|
||||
if (m_csi_info.fields[0] == -1 || m_csi_info.fields[0] == 0)
|
||||
{
|
||||
rects[0][0] = m_cursor.x * m_font.width();
|
||||
rects[0][1] = m_cursor.y * m_font.height();
|
||||
rects[0][2] = m_window->width() - rects[0][0];
|
||||
rects[0][3] = m_font.height();
|
||||
rects[0].x = m_cursor.x * m_font.width();
|
||||
rects[0].y = m_cursor.y * m_font.height();
|
||||
rects[0].width = m_window->width() - rects[0].x;
|
||||
rects[0].height = m_font.height();
|
||||
|
||||
rects[1][0] = 0;
|
||||
rects[1][1] = (m_cursor.y + 1) * m_font.height();
|
||||
rects[1][2] = m_window->width();
|
||||
rects[1][3] = m_window->height() - rects[1][1];
|
||||
rects[1].x = 0;
|
||||
rects[1].y = (m_cursor.y + 1) * m_font.height();
|
||||
rects[1].width = m_window->width();
|
||||
rects[1].height = m_window->height() - rects[1].y;
|
||||
|
||||
rect_count = 2;
|
||||
}
|
||||
else if (m_csi_info.fields[0] == 1)
|
||||
{
|
||||
rects[0][0] = 0;
|
||||
rects[0][1] = m_cursor.y * m_font.height();
|
||||
rects[0][2] = m_cursor.x * m_font.width();
|
||||
rects[0][3] = m_font.height();
|
||||
rects[0].x = 0;
|
||||
rects[0].y = m_cursor.y * m_font.height();
|
||||
rects[0].width = m_cursor.x * m_font.width();
|
||||
rects[0].height = m_font.height();
|
||||
|
||||
rects[1][0] = 0;
|
||||
rects[1][1] = 0;
|
||||
rects[1][2] = m_window->width();
|
||||
rects[1][3] = m_cursor.y * m_font.height();
|
||||
rects[1].x = 0;
|
||||
rects[1].y = 0;
|
||||
rects[1].width = m_window->width();
|
||||
rects[1].height = m_cursor.y * m_font.height();
|
||||
|
||||
rect_count = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
rects[0][0] = 0;
|
||||
rects[0][1] = 0;
|
||||
rects[0][2] = m_window->width();
|
||||
rects[0][3] = m_window->height();
|
||||
rects[0].x = 0;
|
||||
rects[0].y = 0;
|
||||
rects[0].width = m_window->width();
|
||||
rects[0].height = m_window->height();
|
||||
|
||||
rect_count = 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
for (size_t i = 0; i < rect_count; i++)
|
||||
{
|
||||
if (rects[i][0] == (uint32_t)-1)
|
||||
continue;
|
||||
m_window->fill_rect(rects[i][0], rects[i][1], rects[i][2], rects[i][3], m_bg_color);
|
||||
m_window->invalidate(rects[i][0], rects[i][1], rects[i][2], rects[i][3]);
|
||||
m_window->fill_rect(rects[i].x, rects[i].y, rects[i].width, rects[i].height, m_bg_color);
|
||||
should_invalidate = should_invalidate.get_bounding_box(rects[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'K':
|
||||
{
|
||||
m_csi_info.fields[0] = BAN::Math::max(m_csi_info.fields[0], 0);
|
||||
|
||||
uint32_t rect[4];
|
||||
rect[0] = (m_csi_info.fields[0] == 0) ? m_cursor.x * m_font.width() : 0;
|
||||
rect[1] = m_cursor.y * m_font.height();
|
||||
rect[2] = (m_csi_info.fields[0] == 1) ? m_cursor.x * m_font.width() : m_window->width() - rect[0];
|
||||
rect[3] = m_font.height();
|
||||
Rectangle rect;
|
||||
rect.x = (m_csi_info.fields[0] == 0) ? m_cursor.x * m_font.width() : 0;
|
||||
rect.y = m_cursor.y * m_font.height();
|
||||
rect.width = (m_csi_info.fields[0] == 1) ? m_cursor.x * m_font.width() : m_window->width() - rect.x;
|
||||
rect.height = m_font.height();
|
||||
|
||||
m_window->fill_rect(rect[0], rect[1], rect[2], rect[3], m_bg_color);
|
||||
m_window->invalidate(rect[0], rect[1], rect[2], rect[3]);
|
||||
m_window->fill_rect(rect.x, rect.y, rect.width, rect.height, m_bg_color);
|
||||
should_invalidate = rect;
|
||||
|
||||
break;
|
||||
}
|
||||
case 'L':
|
||||
{
|
||||
const uint32_t count = (m_csi_info.fields[0] == -1) ? 1 : m_csi_info.fields[0];
|
||||
const uint32_t src_y = m_cursor.y * m_font.height();
|
||||
const uint32_t dst_y = src_y + count * m_font.height();
|
||||
|
||||
m_window->copy_horizontal_slice(dst_y, src_y, m_window->height() - dst_y, m_bg_color);
|
||||
m_window->fill_rect(0, src_y, m_window->width(), count * m_font.height(), m_bg_color);
|
||||
should_invalidate = {
|
||||
0,
|
||||
src_y,
|
||||
m_window->width(),
|
||||
m_window->height() - src_y
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
case 'M':
|
||||
{
|
||||
const uint32_t count = (m_csi_info.fields[0] == -1) ? 1 : m_csi_info.fields[0];
|
||||
const uint32_t dst_y = m_cursor.y * m_font.height();
|
||||
const uint32_t src_y = dst_y + count * m_font.height();
|
||||
|
||||
m_window->copy_horizontal_slice(dst_y, src_y, m_window->height() - dst_y, m_bg_color);
|
||||
m_window->fill_rect(0, m_window->height() - count * m_font.height(), m_window->width(), count * m_font.height(), m_bg_color);
|
||||
should_invalidate = {
|
||||
0,
|
||||
src_y,
|
||||
m_window->width(),
|
||||
m_window->height() - src_y
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -413,7 +459,9 @@ void Terminal::handle_csi(char ch)
|
|||
dprintln("TODO: CSI {}", ch);
|
||||
break;
|
||||
}
|
||||
|
||||
m_state = State::Normal;
|
||||
return should_invalidate;
|
||||
}
|
||||
|
||||
Rectangle Terminal::putchar(uint8_t ch)
|
||||
|
@ -442,8 +490,7 @@ Rectangle Terminal::putchar(uint8_t ch)
|
|||
m_state = State::Normal;
|
||||
return {};
|
||||
}
|
||||
handle_csi(ch);
|
||||
return {};
|
||||
return handle_csi(ch);
|
||||
}
|
||||
|
||||
m_utf8_bytes[m_utf8_index++] = ch;
|
||||
|
@ -522,8 +569,7 @@ Rectangle Terminal::putchar(uint8_t ch)
|
|||
{
|
||||
const uint32_t scroll = m_cursor.y - rows() + 1;
|
||||
m_cursor.y -= scroll;
|
||||
m_window->shift_vertical(-scroll * (int32_t)m_font.height());
|
||||
m_window->fill_rect(0, m_window->height() - scroll * m_font.height(), m_window->width(), scroll * m_font.height(), m_bg_color);
|
||||
m_window->shift_vertical(-scroll * (int32_t)m_font.height(), m_bg_color);
|
||||
should_invalidate = { 0, 0, m_window->width(), m_window->height() };
|
||||
}
|
||||
|
||||
|
|
|
@ -35,8 +35,8 @@ public:
|
|||
uint32_t rows() const { return m_window->height() / m_font.height(); }
|
||||
|
||||
private:
|
||||
void handle_csi(char ch);
|
||||
void handle_sgr();
|
||||
Rectangle handle_csi(char ch);
|
||||
Rectangle putchar(uint8_t ch);
|
||||
bool read_shell();
|
||||
|
||||
|
|
|
@ -413,7 +413,7 @@ void WindowServer::invalidate(Rectangle area)
|
|||
const auto is_rounded_off =
|
||||
[&](Position pos) -> bool
|
||||
{
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
for (int32_t i = 0; i < 4; i++)
|
||||
{
|
||||
if (!corner_areas[i].contains(pos))
|
||||
continue;
|
||||
|
@ -558,8 +558,6 @@ void WindowServer::sync()
|
|||
dir_y = -dir_y;
|
||||
}
|
||||
|
||||
size_t synced_pages = 0;
|
||||
|
||||
for (size_t i = 0; i < m_pages_to_sync_bitmap.size() * 8; i++)
|
||||
{
|
||||
size_t byte = i / 8;
|
||||
|
@ -582,7 +580,6 @@ void WindowServer::sync()
|
|||
len * 4096,
|
||||
MS_SYNC
|
||||
);
|
||||
synced_pages += len;
|
||||
|
||||
i += len;
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ int list_directory(const BAN::String& path, config_t config)
|
|||
|
||||
if (!S_ISDIR(st.st_mode))
|
||||
{
|
||||
MUST(entries.emplace_back(path, st));
|
||||
MUST(entries.emplace_back(path, st, BAN::String()));
|
||||
if (S_ISLNK(st.st_mode))
|
||||
{
|
||||
if (readlink(path.data(), link_buffer, sizeof(link_buffer)) == -1)
|
||||
|
@ -166,7 +166,7 @@ int list_directory(const BAN::String& path, config_t config)
|
|||
continue;
|
||||
}
|
||||
|
||||
MUST(entries.emplace_back(BAN::StringView(dirent->d_name), st));
|
||||
MUST(entries.emplace_back(BAN::StringView(dirent->d_name), st, BAN::String()));
|
||||
if (S_ISLNK(st.st_mode))
|
||||
{
|
||||
if (readlinkat(dirfd(dirp), dirent->d_name, link_buffer, sizeof(link_buffer)) == -1)
|
||||
|
|
Loading…
Reference in New Issue