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,
|
"cmake.configureOnOpen": false,
|
||||||
"editor.tabSize": 4,
|
"editor.tabSize": 4,
|
||||||
"editor.insertSpaces": false,
|
"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(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||||
set(BUILD_SHARED_LIBS True)
|
set(BUILD_SHARED_LIBS True)
|
||||||
|
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,10 @@ namespace Kernel
|
||||||
m_background = TerminalColor::BLACK;
|
m_background = TerminalColor::BLACK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
BAN::swap(m_foreground, m_background);
|
||||||
|
break;
|
||||||
|
|
||||||
case 30: m_foreground = TerminalColor::BLACK; break;
|
case 30: m_foreground = TerminalColor::BLACK; break;
|
||||||
case 31: m_foreground = TerminalColor::RED; break;
|
case 31: m_foreground = TerminalColor::RED; break;
|
||||||
case 32: m_foreground = TerminalColor::GREEN; 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
|
# This is to allow cmake to link when libc updates
|
||||||
target_link_options(${library_lower} PRIVATE -nolibc)
|
target_link_options(${library_lower} PRIVATE -nolibc)
|
||||||
# Default compile options
|
# 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})
|
target_compile_definitions(${library_lower} PRIVATE __enable_sse=${BANAN_ENABLE_SSE})
|
||||||
if (NOT 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;
|
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)
|
auto digit_char = [](int digit, bool upper)
|
||||||
{
|
{
|
||||||
if (digit < 10)
|
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_length = 1;
|
||||||
prefix[0] = '0';
|
prefix[0] = '0';
|
||||||
|
digits--;
|
||||||
}
|
}
|
||||||
else if (options.alternate_form && base == 16)
|
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--;
|
||||||
format++;
|
format++;
|
||||||
|
|
||||||
char conversion[128];
|
// FIXME: this should be thread-local to keep
|
||||||
|
// satisfy multithreaded requirement
|
||||||
|
static char conversion[4096];
|
||||||
const char* string = nullptr;
|
const char* string = nullptr;
|
||||||
|
|
||||||
int length = -1;
|
int length = -1;
|
||||||
|
|
|
@ -135,14 +135,53 @@ namespace LibGUI
|
||||||
draw_character(text[i], font, tl_x + (int32_t)(i * font.width()), tl_y, color);
|
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())
|
if (amount_abs == 0 || amount_abs >= height())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32_t* dst = (amount > 0) ? m_framebuffer.data() + width() * amount_abs : m_framebuffer.data();
|
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();
|
uint32_t* src = (amount < 0) ? m_framebuffer.data() + width() * amount_abs : m_framebuffer.data();
|
||||||
memmove(dst, src, width() * (height() - amount_abs) * 4);
|
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
|
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_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 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(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||||
bool invalidate() { return invalidate(0, 0, width(), 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)
|
bool probe_png(BAN::ConstByteSpan image_data)
|
||||||
{
|
{
|
||||||
if (image_data.size() < 8)
|
if (image_data.size() < 8)
|
||||||
|
@ -578,12 +731,6 @@ namespace LibImage
|
||||||
return BAN::Error::from_errno(EINVAL);
|
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_width = ihdr.width;
|
||||||
const uint64_t image_height = ihdr.height;
|
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, " uncompressed size {}", inflated_data.size());
|
||||||
dprintln_if(DEBUG_PNG, " compression ratio {}", (double)inflated_data.size() / total_size);
|
dprintln_if(DEBUG_PNG, " compression ratio {}", (double)inflated_data.size() / total_size);
|
||||||
|
|
||||||
uint8_t bits_per_channel = ihdr.bit_depth;
|
BAN::Vector<Image::Color> pixel_data;
|
||||||
uint8_t channels = 0;
|
TRY(pixel_data.resize(image_width * image_height));
|
||||||
switch (ihdr.colour_type)
|
|
||||||
|
switch (ihdr.interlace_method)
|
||||||
{
|
{
|
||||||
case ColourType::Greyscale: channels = 1; break;
|
case InterlaceMethod::NoInterlace:
|
||||||
case ColourType::Truecolour: channels = 3; break;
|
TRY(parse_pixel_data(pixel_data, image_width, image_height, ihdr, palette, inflated_data));
|
||||||
case ColourType::IndexedColour: channels = 1; break;
|
break;
|
||||||
case ColourType::GreyscaleAlpha: channels = 2; break;
|
case InterlaceMethod::Adam7:
|
||||||
case ColourType::TruecolourAlpha: channels = 4; break;
|
{
|
||||||
|
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:
|
default:
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto extract_channel =
|
return TRY(BAN::UniqPtr<Image>::create(image_width, image_height, BAN::move(pixel_data)));
|
||||||
[&](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)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ foreach(project ${USERSPACE_PROGRAMS})
|
||||||
# This is to allow cmake to link when libc updates
|
# This is to allow cmake to link when libc updates
|
||||||
target_link_options(${project} PRIVATE -nolibc)
|
target_link_options(${project} PRIVATE -nolibc)
|
||||||
# Default compile options
|
# 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})
|
target_compile_definitions(${project} PRIVATE __enable_sse=${BANAN_ENABLE_SSE})
|
||||||
if (NOT 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
|
// 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')
|
while (non_ansi_end < nread && buffer[non_ansi_end] != '\e')
|
||||||
non_ansi_end++;
|
non_ansi_end++;
|
||||||
|
|
||||||
// we only need to process maximum of `rows()` newlines.
|
// we only need to process maximum of `rows()` newlines.
|
||||||
// anything before that would get overwritten anyway
|
// anything before that would get overwritten anyway
|
||||||
size_t start = non_ansi_end;
|
ssize_t start = non_ansi_end;
|
||||||
size_t newline_count = 0;
|
size_t newline_count = 0;
|
||||||
while (start > i && newline_count < rows())
|
while (start > i && newline_count < rows())
|
||||||
newline_count += (buffer[--start] == '\n');
|
newline_count += (buffer[--start] == '\n');
|
||||||
|
@ -239,8 +239,7 @@ bool Terminal::read_shell()
|
||||||
{
|
{
|
||||||
const uint32_t scroll = m_cursor.y + newline_count - rows() + 1;
|
const uint32_t scroll = m_cursor.y + newline_count - rows() + 1;
|
||||||
m_cursor.y -= scroll;
|
m_cursor.y -= scroll;
|
||||||
m_window->shift_vertical(-scroll * (int32_t)m_font.height());
|
m_window->shift_vertical(-scroll * (int32_t)m_font.height(), m_bg_color);
|
||||||
m_window->fill_rect(0, m_window->height() - scroll * m_font.height(), m_window->width(), scroll * m_font.height(), m_bg_color);
|
|
||||||
should_invalidate = { 0, 0, m_window->width(), m_window->height() };
|
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_bg_color = s_colors_dark[0];
|
||||||
m_fg_color = s_colors_bright[7];
|
m_fg_color = s_colors_bright[7];
|
||||||
break;
|
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:
|
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];
|
m_fg_color = s_colors_dark[m_csi_info.fields[0] - 30];
|
||||||
break;
|
break;
|
||||||
|
@ -288,18 +293,18 @@ void Terminal::handle_sgr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::handle_csi(char ch)
|
Rectangle Terminal::handle_csi(char ch)
|
||||||
{
|
{
|
||||||
if (ch == ';')
|
if (ch == ';')
|
||||||
{
|
{
|
||||||
m_csi_info.index++;
|
m_csi_info.index++;
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch == '?')
|
if (ch == '?')
|
||||||
{
|
{
|
||||||
m_csi_info.question = true;
|
m_csi_info.question = true;
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isdigit(ch))
|
if (isdigit(ch))
|
||||||
|
@ -309,9 +314,10 @@ void Terminal::handle_csi(char ch)
|
||||||
auto& field = m_csi_info.fields[m_csi_info.index];
|
auto& field = m_csi_info.fields[m_csi_info.index];
|
||||||
field = (BAN::Math::max(field, 0) * 10) + (ch - '0');
|
field = (BAN::Math::max(field, 0) * 10) + (ch - '0');
|
||||||
}
|
}
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle should_invalidate;
|
||||||
switch (ch)
|
switch (ch)
|
||||||
{
|
{
|
||||||
case 'C':
|
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;
|
m_cursor.x = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, cols()) - 1;
|
||||||
break;
|
break;
|
||||||
case 'H':
|
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.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;
|
break;
|
||||||
case 'J':
|
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)
|
if (m_csi_info.fields[0] == -1 || m_csi_info.fields[0] == 0)
|
||||||
{
|
{
|
||||||
rects[0][0] = m_cursor.x * m_font.width();
|
rects[0].x = m_cursor.x * m_font.width();
|
||||||
rects[0][1] = m_cursor.y * m_font.height();
|
rects[0].y = m_cursor.y * m_font.height();
|
||||||
rects[0][2] = m_window->width() - rects[0][0];
|
rects[0].width = m_window->width() - rects[0].x;
|
||||||
rects[0][3] = m_font.height();
|
rects[0].height = m_font.height();
|
||||||
|
|
||||||
rects[1][0] = 0;
|
rects[1].x = 0;
|
||||||
rects[1][1] = (m_cursor.y + 1) * m_font.height();
|
rects[1].y = (m_cursor.y + 1) * m_font.height();
|
||||||
rects[1][2] = m_window->width();
|
rects[1].width = m_window->width();
|
||||||
rects[1][3] = m_window->height() - rects[1][1];
|
rects[1].height = m_window->height() - rects[1].y;
|
||||||
|
|
||||||
|
rect_count = 2;
|
||||||
}
|
}
|
||||||
else if (m_csi_info.fields[0] == 1)
|
else if (m_csi_info.fields[0] == 1)
|
||||||
{
|
{
|
||||||
rects[0][0] = 0;
|
rects[0].x = 0;
|
||||||
rects[0][1] = m_cursor.y * m_font.height();
|
rects[0].y = m_cursor.y * m_font.height();
|
||||||
rects[0][2] = m_cursor.x * m_font.width();
|
rects[0].width = m_cursor.x * m_font.width();
|
||||||
rects[0][3] = m_font.height();
|
rects[0].height = m_font.height();
|
||||||
|
|
||||||
rects[1][0] = 0;
|
rects[1].x = 0;
|
||||||
rects[1][1] = 0;
|
rects[1].y = 0;
|
||||||
rects[1][2] = m_window->width();
|
rects[1].width = m_window->width();
|
||||||
rects[1][3] = m_cursor.y * m_font.height();
|
rects[1].height = m_cursor.y * m_font.height();
|
||||||
|
|
||||||
|
rect_count = 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rects[0][0] = 0;
|
rects[0].x = 0;
|
||||||
rects[0][1] = 0;
|
rects[0].y = 0;
|
||||||
rects[0][2] = m_window->width();
|
rects[0].width = m_window->width();
|
||||||
rects[0][3] = m_window->height();
|
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)
|
m_window->fill_rect(rects[i].x, rects[i].y, rects[i].width, rects[i].height, m_bg_color);
|
||||||
continue;
|
should_invalidate = should_invalidate.get_bounding_box(rects[i]);
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'K':
|
case 'K':
|
||||||
{
|
{
|
||||||
m_csi_info.fields[0] = BAN::Math::max(m_csi_info.fields[0], 0);
|
m_csi_info.fields[0] = BAN::Math::max(m_csi_info.fields[0], 0);
|
||||||
|
|
||||||
uint32_t rect[4];
|
Rectangle rect;
|
||||||
rect[0] = (m_csi_info.fields[0] == 0) ? m_cursor.x * m_font.width() : 0;
|
rect.x = (m_csi_info.fields[0] == 0) ? m_cursor.x * m_font.width() : 0;
|
||||||
rect[1] = m_cursor.y * m_font.height();
|
rect.y = 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.width = (m_csi_info.fields[0] == 1) ? m_cursor.x * m_font.width() : m_window->width() - rect.x;
|
||||||
rect[3] = m_font.height();
|
rect.height = m_font.height();
|
||||||
|
|
||||||
m_window->fill_rect(rect[0], rect[1], rect[2], rect[3], m_bg_color);
|
m_window->fill_rect(rect.x, rect.y, rect.width, rect.height, m_bg_color);
|
||||||
m_window->invalidate(rect[0], rect[1], rect[2], rect[3]);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -413,7 +459,9 @@ void Terminal::handle_csi(char ch)
|
||||||
dprintln("TODO: CSI {}", ch);
|
dprintln("TODO: CSI {}", ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_state = State::Normal;
|
m_state = State::Normal;
|
||||||
|
return should_invalidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle Terminal::putchar(uint8_t ch)
|
Rectangle Terminal::putchar(uint8_t ch)
|
||||||
|
@ -442,8 +490,7 @@ Rectangle Terminal::putchar(uint8_t ch)
|
||||||
m_state = State::Normal;
|
m_state = State::Normal;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
handle_csi(ch);
|
return handle_csi(ch);
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_utf8_bytes[m_utf8_index++] = 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;
|
const uint32_t scroll = m_cursor.y - rows() + 1;
|
||||||
m_cursor.y -= scroll;
|
m_cursor.y -= scroll;
|
||||||
m_window->shift_vertical(-scroll * (int32_t)m_font.height());
|
m_window->shift_vertical(-scroll * (int32_t)m_font.height(), m_bg_color);
|
||||||
m_window->fill_rect(0, m_window->height() - scroll * m_font.height(), m_window->width(), scroll * m_font.height(), m_bg_color);
|
|
||||||
should_invalidate = { 0, 0, m_window->width(), m_window->height() };
|
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(); }
|
uint32_t rows() const { return m_window->height() / m_font.height(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handle_csi(char ch);
|
|
||||||
void handle_sgr();
|
void handle_sgr();
|
||||||
|
Rectangle handle_csi(char ch);
|
||||||
Rectangle putchar(uint8_t ch);
|
Rectangle putchar(uint8_t ch);
|
||||||
bool read_shell();
|
bool read_shell();
|
||||||
|
|
||||||
|
|
|
@ -413,7 +413,7 @@ void WindowServer::invalidate(Rectangle area)
|
||||||
const auto is_rounded_off =
|
const auto is_rounded_off =
|
||||||
[&](Position pos) -> bool
|
[&](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))
|
if (!corner_areas[i].contains(pos))
|
||||||
continue;
|
continue;
|
||||||
|
@ -558,8 +558,6 @@ void WindowServer::sync()
|
||||||
dir_y = -dir_y;
|
dir_y = -dir_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t synced_pages = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_pages_to_sync_bitmap.size() * 8; i++)
|
for (size_t i = 0; i < m_pages_to_sync_bitmap.size() * 8; i++)
|
||||||
{
|
{
|
||||||
size_t byte = i / 8;
|
size_t byte = i / 8;
|
||||||
|
@ -582,7 +580,6 @@ void WindowServer::sync()
|
||||||
len * 4096,
|
len * 4096,
|
||||||
MS_SYNC
|
MS_SYNC
|
||||||
);
|
);
|
||||||
synced_pages += len;
|
|
||||||
|
|
||||||
i += len;
|
i += len;
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@ int list_directory(const BAN::String& path, config_t config)
|
||||||
|
|
||||||
if (!S_ISDIR(st.st_mode))
|
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 (S_ISLNK(st.st_mode))
|
||||||
{
|
{
|
||||||
if (readlink(path.data(), link_buffer, sizeof(link_buffer)) == -1)
|
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;
|
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 (S_ISLNK(st.st_mode))
|
||||||
{
|
{
|
||||||
if (readlinkat(dirfd(dirp), dirent->d_name, link_buffer, sizeof(link_buffer)) == -1)
|
if (readlinkat(dirfd(dirp), dirent->d_name, link_buffer, sizeof(link_buffer)) == -1)
|
||||||
|
|
Loading…
Reference in New Issue