Skip to content

Commit a81e407

Browse files
InvalidUsernameExceptiongmta
authored andcommitted
LibWeb: Do not crash when converting a bitmap to RGB888
This makes it so that we can visit satellite and hybrid view on maps.apple.com. Previously this would crash from a bounds check due to us asking Skia to write 32bpp RGBx8888 data into a buffer sized for 24bpp RGB888.
1 parent 9e60dc5 commit a81e407

File tree

1 file changed

+37
-15
lines changed

1 file changed

+37
-15
lines changed

Libraries/LibGfx/ImmutableBitmap.cpp

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ static SkColorType export_format_to_skia_color_type(ExportFormat format)
8989
case ExportFormat::RGBA4444:
9090
return SkColorType::kARGB_4444_SkColorType;
9191
case ExportFormat::RGB888:
92-
return SkColorType::kRGB_888x_SkColorType;
92+
// This one needs to be converted manually because Skia has no valid 24-bit color type.
93+
VERIFY_NOT_REACHED();
9394
case ExportFormat::RGBA8888:
9495
return SkColorType::kRGBA_8888_SkColorType;
9596
default:
@@ -102,6 +103,12 @@ ErrorOr<BitmapExportResult> ImmutableBitmap::export_to_byte_buffer(ExportFormat
102103
int width = target_width.value_or(this->width());
103104
int height = target_height.value_or(this->height());
104105

106+
if (format == ExportFormat::RGB888 && (width != this->width() || height != this->height())) {
107+
dbgln("FIXME: Ignoring target width and height because scaling is not implemented for this export format.");
108+
width = this->width();
109+
height = this->height();
110+
}
111+
105112
Checked<size_t> buffer_pitch = width;
106113
int number_of_bytes = bytes_per_pixel_for_export_format(format);
107114
buffer_pitch *= number_of_bytes;
@@ -114,21 +121,36 @@ ErrorOr<BitmapExportResult> ImmutableBitmap::export_to_byte_buffer(ExportFormat
114121
auto buffer = MUST(ByteBuffer::create_zeroed(buffer_pitch.value() * height));
115122

116123
if (width > 0 && height > 0) {
117-
auto skia_format = export_format_to_skia_color_type(format);
118-
auto color_space = SkColorSpace::MakeSRGB();
119-
120-
auto image_info = SkImageInfo::Make(width, height, skia_format, flags & ExportFlags::PremultiplyAlpha ? SkAlphaType::kPremul_SkAlphaType : SkAlphaType::kUnpremul_SkAlphaType, color_space);
121-
auto surface = SkSurfaces::WrapPixels(image_info, buffer.data(), buffer_pitch.value());
122-
VERIFY(surface);
123-
auto* surface_canvas = surface->getCanvas();
124-
auto dst_rect = Gfx::to_skia_rect(Gfx::Rect { 0, 0, width, height });
125-
126-
if (flags & ExportFlags::FlipY) {
127-
surface_canvas->translate(0, dst_rect.height());
128-
surface_canvas->scale(1, -1);
124+
if (format == ExportFormat::RGB888) {
125+
// 24 bit RGB is not supported by Skia, so we need to handle this format ourselves.
126+
auto raw_buffer = buffer.data();
127+
for (auto y = 0; y < height; y++) {
128+
auto target_y = flags & ExportFlags::FlipY ? height - y - 1 : y;
129+
for (auto x = 0; x < width; x++) {
130+
auto pixel = get_pixel(x, y);
131+
auto buffer_offset = (target_y * buffer_pitch.value()) + (x * 3ull);
132+
raw_buffer[buffer_offset + 0] = pixel.red();
133+
raw_buffer[buffer_offset + 1] = pixel.green();
134+
raw_buffer[buffer_offset + 2] = pixel.blue();
135+
}
136+
}
137+
} else {
138+
auto skia_format = export_format_to_skia_color_type(format);
139+
auto color_space = SkColorSpace::MakeSRGB();
140+
141+
auto image_info = SkImageInfo::Make(width, height, skia_format, flags & ExportFlags::PremultiplyAlpha ? SkAlphaType::kPremul_SkAlphaType : SkAlphaType::kUnpremul_SkAlphaType, color_space);
142+
auto surface = SkSurfaces::WrapPixels(image_info, buffer.data(), buffer_pitch.value());
143+
VERIFY(surface);
144+
auto* surface_canvas = surface->getCanvas();
145+
auto dst_rect = Gfx::to_skia_rect(Gfx::Rect { 0, 0, width, height });
146+
147+
if (flags & ExportFlags::FlipY) {
148+
surface_canvas->translate(0, dst_rect.height());
149+
surface_canvas->scale(1, -1);
150+
}
151+
152+
surface_canvas->drawImageRect(sk_image(), dst_rect, Gfx::to_skia_sampling_options(Gfx::ScalingMode::NearestNeighbor));
129153
}
130-
131-
surface_canvas->drawImageRect(sk_image(), dst_rect, Gfx::to_skia_sampling_options(Gfx::ScalingMode::NearestNeighbor));
132154
} else {
133155
VERIFY(buffer.is_empty());
134156
}

0 commit comments

Comments
 (0)