LibPDF: Propagate errors in Renderer/PDFViewer

This commit is contained in:
Matthew Olsson 2022-03-05 18:12:58 -07:00 committed by Andreas Kling
parent d82bd885ce
commit b240d23a87
Notes: sideshowbarker 2024-07-17 17:50:53 +09:00
4 changed files with 140 additions and 72 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org> * Copyright (c) 2021-2022, Matthew Olsson <mattco@serenityos.org>
* Copyright (c) 2022, the SerenityOS developers. * Copyright (c) 2022, the SerenityOS developers.
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
@ -8,6 +8,7 @@
#include "PDFViewer.h" #include "PDFViewer.h"
#include <AK/Array.h> #include <AK/Array.h>
#include <LibGUI/Action.h> #include <LibGUI/Action.h>
#include <LibGUI/MessageBox.h>
#include <LibGUI/Painter.h> #include <LibGUI/Painter.h>
#include <LibPDF/Renderer.h> #include <LibPDF/Renderer.h>
@ -56,15 +57,15 @@ void PDFViewer::set_document(RefPtr<PDF::Document> document)
update(); update();
} }
RefPtr<Gfx::Bitmap> PDFViewer::get_rendered_page(u32 index) PDF::PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> PDFViewer::get_rendered_page(u32 index)
{ {
auto& rendered_page_map = m_rendered_page_list[index]; auto& rendered_page_map = m_rendered_page_list[index];
auto existing_rendered_page = rendered_page_map.get(m_zoom_level); auto existing_rendered_page = rendered_page_map.get(m_zoom_level);
if (existing_rendered_page.has_value() && existing_rendered_page.value().rotation == m_rotations) if (existing_rendered_page.has_value() && existing_rendered_page.value().rotation == m_rotations)
return existing_rendered_page.value().bitmap; return existing_rendered_page.value().bitmap;
// FIXME: Propogate errors in the Renderer auto page = TRY(m_document->get_page(index));
auto rendered_page = render_page(MUST(m_document->get_page(index))); auto rendered_page = TRY(render_page(page));
rendered_page_map.set(m_zoom_level, { rendered_page, m_rotations }); rendered_page_map.set(m_zoom_level, { rendered_page, m_rotations });
return rendered_page; return rendered_page;
} }
@ -81,7 +82,14 @@ void PDFViewer::paint_event(GUI::PaintEvent& event)
if (!m_document) if (!m_document)
return; return;
auto page = get_rendered_page(m_current_page_index); auto maybe_page = get_rendered_page(m_current_page_index);
if (maybe_page.is_error()) {
auto error = maybe_page.release_error();
GUI::MessageBox::show_error(nullptr, String::formatted("Error rendering page:\n{}", error.message()));
return;
}
auto page = maybe_page.release_value();
set_content_size(page->size()); set_content_size(page->size());
painter.translate(frame_thickness(), frame_thickness()); painter.translate(frame_thickness(), frame_thickness());
@ -196,7 +204,7 @@ void PDFViewer::rotate(int degrees)
update(); update();
} }
RefPtr<Gfx::Bitmap> PDFViewer::render_page(const PDF::Page& page) PDF::PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> PDFViewer::render_page(const PDF::Page& page)
{ {
auto zoom_scale_factor = static_cast<float>(zoom_levels[m_zoom_level]) / 100.0f; auto zoom_scale_factor = static_cast<float>(zoom_levels[m_zoom_level]) / 100.0f;
@ -208,7 +216,7 @@ RefPtr<Gfx::Bitmap> PDFViewer::render_page(const PDF::Page& page)
auto width = height / page_scale_factor; auto width = height / page_scale_factor;
auto bitmap = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, { width, height }).release_value_but_fixme_should_propagate_errors(); auto bitmap = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, { width, height }).release_value_but_fixme_should_propagate_errors();
PDF::Renderer::render(*m_document, page, bitmap); TRY(PDF::Renderer::render(*m_document, page, bitmap));
if (page.rotate + m_rotations != 0) { if (page.rotate + m_rotations != 0) {
int rotation_count = ((page.rotate + m_rotations) / 90) % 4; int rotation_count = ((page.rotate + m_rotations) / 90) % 4;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org> * Copyright (c) 2021-2022, Matthew Olsson <mattco@serenityos.org>
* Copyright (c) 2022, the SerenityOS developers. * Copyright (c) 2022, the SerenityOS developers.
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
@ -45,12 +45,12 @@ protected:
private: private:
struct RenderedPage { struct RenderedPage {
RefPtr<Gfx::Bitmap> bitmap; NonnullRefPtr<Gfx::Bitmap> bitmap;
int rotation; int rotation;
}; };
RefPtr<Gfx::Bitmap> get_rendered_page(u32 index); PDF::PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> get_rendered_page(u32 index);
RefPtr<Gfx::Bitmap> render_page(const PDF::Page&); PDF::PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> render_page(const PDF::Page&);
RefPtr<PDF::Document> m_document; RefPtr<PDF::Document> m_document;
u32 m_current_page_index { 0 }; u32 m_current_page_index { 0 };

View file

@ -9,7 +9,7 @@
#include <LibPDF/Renderer.h> #include <LibPDF/Renderer.h>
#define RENDERER_HANDLER(name) \ #define RENDERER_HANDLER(name) \
void Renderer::handle_##name([[maybe_unused]] Vector<Value> const& args) PDFErrorOr<void> Renderer::handle_##name([[maybe_unused]] Vector<Value> const& args)
#define RENDERER_TODO(name) \ #define RENDERER_TODO(name) \
RENDERER_HANDLER(name) \ RENDERER_HANDLER(name) \
@ -20,9 +20,9 @@
namespace PDF { namespace PDF {
void Renderer::render(Document& document, Page const& page, RefPtr<Gfx::Bitmap> bitmap) PDFErrorOr<void> Renderer::render(Document& document, Page const& page, RefPtr<Gfx::Bitmap> bitmap)
{ {
Renderer(document, page, bitmap).render(); return Renderer(document, page, bitmap).render();
} }
Renderer::Renderer(RefPtr<Document> document, Page const& page, RefPtr<Gfx::Bitmap> bitmap) Renderer::Renderer(RefPtr<Document> document, Page const& page, RefPtr<Gfx::Bitmap> bitmap)
@ -56,7 +56,7 @@ Renderer::Renderer(RefPtr<Document> document, Page const& page, RefPtr<Gfx::Bitm
m_bitmap->fill(Gfx::Color::NamedColor::White); m_bitmap->fill(Gfx::Color::NamedColor::White);
} }
void Renderer::render() PDFErrorOr<void> Renderer::render()
{ {
// Use our own vector, as the /Content can be an array with multiple // Use our own vector, as the /Content can be an array with multiple
// streams which gets concatenated // streams which gets concatenated
@ -68,7 +68,7 @@ void Renderer::render()
if (m_page.contents->is<ArrayObject>()) { if (m_page.contents->is<ArrayObject>()) {
auto contents = m_page.contents->cast<ArrayObject>(); auto contents = m_page.contents->cast<ArrayObject>();
for (auto& ref : *contents) { for (auto& ref : *contents) {
auto bytes = MUST(m_document->resolve_to<StreamObject>(ref))->bytes(); auto bytes = TRY(m_document->resolve_to<StreamObject>(ref))->bytes();
byte_buffer.append(bytes.data(), bytes.size()); byte_buffer.append(bytes.data(), bytes.size());
} }
} else { } else {
@ -76,38 +76,44 @@ void Renderer::render()
byte_buffer.append(bytes.data(), bytes.size()); byte_buffer.append(bytes.data(), bytes.size());
} }
auto commands = MUST(Parser::parse_graphics_commands(byte_buffer)); auto commands = TRY(Parser::parse_graphics_commands(byte_buffer));
for (auto& command : commands) for (auto& command : commands)
handle_command(command); TRY(handle_command(command));
return {};
} }
void Renderer::handle_command(Command const& command) PDFErrorOr<void> Renderer::handle_command(Command const& command)
{ {
switch (command.command_type()) { switch (command.command_type()) {
#define V(name, snake_name, symbol) \ #define V(name, snake_name, symbol) \
case CommandType::name: \ case CommandType::name: \
handle_##snake_name(command.arguments()); \ TRY(handle_##snake_name(command.arguments())); \
break; break;
ENUMERATE_COMMANDS(V) ENUMERATE_COMMANDS(V)
#undef V #undef V
case CommandType::TextNextLineShowString: case CommandType::TextNextLineShowString:
handle_text_next_line_show_string(command.arguments()); TRY(handle_text_next_line_show_string(command.arguments()));
break; break;
case CommandType::TextNextLineShowStringSetSpacing: case CommandType::TextNextLineShowStringSetSpacing:
handle_text_next_line_show_string_set_spacing(command.arguments()); TRY(handle_text_next_line_show_string_set_spacing(command.arguments()));
break; break;
} }
return {};
} }
RENDERER_HANDLER(save_state) RENDERER_HANDLER(save_state)
{ {
m_graphics_state_stack.append(state()); m_graphics_state_stack.append(state());
return {};
} }
RENDERER_HANDLER(restore_state) RENDERER_HANDLER(restore_state)
{ {
m_graphics_state_stack.take_last(); m_graphics_state_stack.take_last();
return {};
} }
RENDERER_HANDLER(concatenate_matrix) RENDERER_HANDLER(concatenate_matrix)
@ -122,26 +128,31 @@ RENDERER_HANDLER(concatenate_matrix)
state().ctm.multiply(new_transform); state().ctm.multiply(new_transform);
m_text_rendering_matrix_is_dirty = true; m_text_rendering_matrix_is_dirty = true;
return {};
} }
RENDERER_HANDLER(set_line_width) RENDERER_HANDLER(set_line_width)
{ {
state().line_width = args[0].to_float(); state().line_width = args[0].to_float();
return {};
} }
RENDERER_HANDLER(set_line_cap) RENDERER_HANDLER(set_line_cap)
{ {
state().line_cap_style = static_cast<LineCapStyle>(args[0].get<int>()); state().line_cap_style = static_cast<LineCapStyle>(args[0].get<int>());
return {};
} }
RENDERER_HANDLER(set_line_join) RENDERER_HANDLER(set_line_join)
{ {
state().line_join_style = static_cast<LineJoinStyle>(args[0].get<int>()); state().line_join_style = static_cast<LineJoinStyle>(args[0].get<int>());
return {};
} }
RENDERER_HANDLER(set_miter_limit) RENDERER_HANDLER(set_miter_limit)
{ {
state().miter_limit = args[0].to_float(); state().miter_limit = args[0].to_float();
return {};
} }
RENDERER_HANDLER(set_dash_pattern) RENDERER_HANDLER(set_dash_pattern)
@ -151,10 +162,11 @@ RENDERER_HANDLER(set_dash_pattern)
for (auto& element : *dash_array) for (auto& element : *dash_array)
pattern.append(element.get<int>()); pattern.append(element.get<int>());
state().line_dash_pattern = LineDashPattern { pattern, args[1].get<int>() }; state().line_dash_pattern = LineDashPattern { pattern, args[1].get<int>() };
return {};
} }
RENDERER_TODO(set_color_rendering_intent); RENDERER_TODO(set_color_rendering_intent)
RENDERER_TODO(set_flatness_tolerance); RENDERER_TODO(set_flatness_tolerance)
RENDERER_HANDLER(set_graphics_state_from_dict) RENDERER_HANDLER(set_graphics_state_from_dict)
{ {
@ -162,27 +174,31 @@ RENDERER_HANDLER(set_graphics_state_from_dict)
auto dict_name = MUST(m_document->resolve_to<NameObject>(args[0]))->name(); auto dict_name = MUST(m_document->resolve_to<NameObject>(args[0]))->name();
auto ext_gstate_dict = MUST(m_page.resources->get_dict(m_document, CommonNames::ExtGState)); auto ext_gstate_dict = MUST(m_page.resources->get_dict(m_document, CommonNames::ExtGState));
auto target_dict = MUST(ext_gstate_dict->get_dict(m_document, dict_name)); auto target_dict = MUST(ext_gstate_dict->get_dict(m_document, dict_name));
set_graphics_state_from_dict(target_dict); TRY(set_graphics_state_from_dict(target_dict));
return {};
} }
RENDERER_HANDLER(path_move) RENDERER_HANDLER(path_move)
{ {
m_current_path.move_to(map(args[0].to_float(), args[1].to_float())); m_current_path.move_to(map(args[0].to_float(), args[1].to_float()));
return {};
} }
RENDERER_HANDLER(path_line) RENDERER_HANDLER(path_line)
{ {
VERIFY(!m_current_path.segments().is_empty()); VERIFY(!m_current_path.segments().is_empty());
m_current_path.line_to(map(args[0].to_float(), args[1].to_float())); m_current_path.line_to(map(args[0].to_float(), args[1].to_float()));
return {};
} }
RENDERER_TODO(path_cubic_bezier_curve); RENDERER_TODO(path_cubic_bezier_curve)
RENDERER_TODO(path_cubic_bezier_curve_no_first_control); RENDERER_TODO(path_cubic_bezier_curve_no_first_control)
RENDERER_TODO(path_cubic_bezier_curve_no_second_control); RENDERER_TODO(path_cubic_bezier_curve_no_second_control)
RENDERER_HANDLER(path_close) RENDERER_HANDLER(path_close)
{ {
m_current_path.close(); m_current_path.close();
return {};
} }
RENDERER_HANDLER(path_append_rect) RENDERER_HANDLER(path_append_rect)
@ -195,63 +211,74 @@ RENDERER_HANDLER(path_append_rect)
m_current_path.line_to({ pos.x() + size.width(), pos.y() + size.height() }); m_current_path.line_to({ pos.x() + size.width(), pos.y() + size.height() });
m_current_path.line_to({ pos.x(), pos.y() + size.height() }); m_current_path.line_to({ pos.x(), pos.y() + size.height() });
m_current_path.close(); m_current_path.close();
return {};
} }
RENDERER_HANDLER(path_stroke) RENDERER_HANDLER(path_stroke)
{ {
m_painter.stroke_path(m_current_path, state().stroke_color, state().line_width); m_painter.stroke_path(m_current_path, state().stroke_color, state().line_width);
m_current_path.clear(); m_current_path.clear();
return {};
} }
RENDERER_HANDLER(path_close_and_stroke) RENDERER_HANDLER(path_close_and_stroke)
{ {
m_current_path.close(); m_current_path.close();
handle_path_stroke(args); TRY(handle_path_stroke(args));
return {};
} }
RENDERER_HANDLER(path_fill_nonzero) RENDERER_HANDLER(path_fill_nonzero)
{ {
m_painter.fill_path(m_current_path, state().paint_color, Gfx::Painter::WindingRule::Nonzero); m_painter.fill_path(m_current_path, state().paint_color, Gfx::Painter::WindingRule::Nonzero);
m_current_path.clear(); m_current_path.clear();
return {};
} }
RENDERER_HANDLER(path_fill_nonzero_deprecated) RENDERER_HANDLER(path_fill_nonzero_deprecated)
{ {
handle_path_fill_nonzero(args); TRY(handle_path_fill_nonzero(args));
return {};
} }
RENDERER_HANDLER(path_fill_evenodd) RENDERER_HANDLER(path_fill_evenodd)
{ {
m_painter.fill_path(m_current_path, state().paint_color, Gfx::Painter::WindingRule::EvenOdd); m_painter.fill_path(m_current_path, state().paint_color, Gfx::Painter::WindingRule::EvenOdd);
m_current_path.clear(); m_current_path.clear();
return {};
} }
RENDERER_HANDLER(path_fill_stroke_nonzero) RENDERER_HANDLER(path_fill_stroke_nonzero)
{ {
m_painter.stroke_path(m_current_path, state().stroke_color, state().line_width); m_painter.stroke_path(m_current_path, state().stroke_color, state().line_width);
handle_path_fill_nonzero(args); TRY(handle_path_fill_nonzero(args));
return {};
} }
RENDERER_HANDLER(path_fill_stroke_evenodd) RENDERER_HANDLER(path_fill_stroke_evenodd)
{ {
m_painter.stroke_path(m_current_path, state().stroke_color, state().line_width); m_painter.stroke_path(m_current_path, state().stroke_color, state().line_width);
handle_path_fill_evenodd(args); TRY(handle_path_fill_evenodd(args));
return {};
} }
RENDERER_HANDLER(path_close_fill_stroke_nonzero) RENDERER_HANDLER(path_close_fill_stroke_nonzero)
{ {
m_current_path.close(); m_current_path.close();
handle_path_fill_stroke_nonzero(args); TRY(handle_path_fill_stroke_nonzero(args));
return {};
} }
RENDERER_HANDLER(path_close_fill_stroke_evenodd) RENDERER_HANDLER(path_close_fill_stroke_evenodd)
{ {
m_current_path.close(); m_current_path.close();
handle_path_fill_stroke_evenodd(args); TRY(handle_path_fill_stroke_evenodd(args));
return {};
} }
RENDERER_HANDLER(path_end) RENDERER_HANDLER(path_end)
{ {
return {};
} }
RENDERER_HANDLER(path_intersect_clip_nonzero) RENDERER_HANDLER(path_intersect_clip_nonzero)
@ -259,6 +286,7 @@ RENDERER_HANDLER(path_intersect_clip_nonzero)
// FIXME: Support arbitrary path clipping in the painter and utilize that here // FIXME: Support arbitrary path clipping in the painter and utilize that here
auto bounding_box = map(m_current_path.bounding_box()); auto bounding_box = map(m_current_path.bounding_box());
m_painter.add_clip_rect(bounding_box.to_type<int>()); m_painter.add_clip_rect(bounding_box.to_type<int>());
return {};
} }
RENDERER_HANDLER(path_intersect_clip_evenodd) RENDERER_HANDLER(path_intersect_clip_evenodd)
@ -266,38 +294,45 @@ RENDERER_HANDLER(path_intersect_clip_evenodd)
// FIXME: Support arbitrary path clipping in the painter and utilize that here // FIXME: Support arbitrary path clipping in the painter and utilize that here
auto bounding_box = map(m_current_path.bounding_box()); auto bounding_box = map(m_current_path.bounding_box());
m_painter.add_clip_rect(bounding_box.to_type<int>()); m_painter.add_clip_rect(bounding_box.to_type<int>());
return {};
} }
RENDERER_HANDLER(text_begin) RENDERER_HANDLER(text_begin)
{ {
m_text_matrix = Gfx::AffineTransform(); m_text_matrix = Gfx::AffineTransform();
m_text_line_matrix = Gfx::AffineTransform(); m_text_line_matrix = Gfx::AffineTransform();
return {};
} }
RENDERER_HANDLER(text_end) RENDERER_HANDLER(text_end)
{ {
// FIXME: Do we need to do anything here? // FIXME: Do we need to do anything here?
return {};
} }
RENDERER_HANDLER(text_set_char_space) RENDERER_HANDLER(text_set_char_space)
{ {
text_state().character_spacing = args[0].to_float(); text_state().character_spacing = args[0].to_float();
return {};
} }
RENDERER_HANDLER(text_set_word_space) RENDERER_HANDLER(text_set_word_space)
{ {
text_state().word_spacing = args[0].to_float(); text_state().word_spacing = args[0].to_float();
return {};
} }
RENDERER_HANDLER(text_set_horizontal_scale) RENDERER_HANDLER(text_set_horizontal_scale)
{ {
m_text_rendering_matrix_is_dirty = true; m_text_rendering_matrix_is_dirty = true;
text_state().horizontal_scaling = args[0].to_float() / 100.0f; text_state().horizontal_scaling = args[0].to_float() / 100.0f;
return {};
} }
RENDERER_HANDLER(text_set_leading) RENDERER_HANDLER(text_set_leading)
{ {
text_state().leading = args[0].to_float(); text_state().leading = args[0].to_float();
return {};
} }
RENDERER_HANDLER(text_set_font) RENDERER_HANDLER(text_set_font)
@ -330,17 +365,20 @@ RENDERER_HANDLER(text_set_font)
text_state().font_variant = font_variant; text_state().font_variant = font_variant;
m_text_rendering_matrix_is_dirty = true; m_text_rendering_matrix_is_dirty = true;
return {};
} }
RENDERER_HANDLER(text_set_rendering_mode) RENDERER_HANDLER(text_set_rendering_mode)
{ {
text_state().rendering_mode = static_cast<TextRenderingMode>(args[0].get<int>()); text_state().rendering_mode = static_cast<TextRenderingMode>(args[0].get<int>());
return {};
} }
RENDERER_HANDLER(text_set_rise) RENDERER_HANDLER(text_set_rise)
{ {
m_text_rendering_matrix_is_dirty = true; m_text_rendering_matrix_is_dirty = true;
text_state().rise = args[0].to_float(); text_state().rise = args[0].to_float();
return {};
} }
RENDERER_HANDLER(text_next_line_offset) RENDERER_HANDLER(text_next_line_offset)
@ -350,12 +388,14 @@ RENDERER_HANDLER(text_next_line_offset)
m_text_matrix = transform; m_text_matrix = transform;
m_text_line_matrix = transform; m_text_line_matrix = transform;
m_text_rendering_matrix_is_dirty = true; m_text_rendering_matrix_is_dirty = true;
return {};
} }
RENDERER_HANDLER(text_next_line_and_set_leading) RENDERER_HANDLER(text_next_line_and_set_leading)
{ {
text_state().leading = -args[1].to_float(); text_state().leading = -args[1].to_float();
handle_text_next_line_offset(args); TRY(handle_text_next_line_offset(args));
return {};
} }
RENDERER_HANDLER(text_set_matrix_and_line_matrix) RENDERER_HANDLER(text_set_matrix_and_line_matrix)
@ -370,26 +410,30 @@ RENDERER_HANDLER(text_set_matrix_and_line_matrix)
m_text_line_matrix = new_transform; m_text_line_matrix = new_transform;
m_text_matrix = new_transform; m_text_matrix = new_transform;
m_text_rendering_matrix_is_dirty = true; m_text_rendering_matrix_is_dirty = true;
return {};
} }
RENDERER_HANDLER(text_next_line) RENDERER_HANDLER(text_next_line)
{ {
handle_text_next_line_offset({ 0.0f, -text_state().leading }); TRY(handle_text_next_line_offset({ 0.0f, -text_state().leading }));
return {};
} }
RENDERER_HANDLER(text_show_string) RENDERER_HANDLER(text_show_string)
{ {
auto text = MUST(m_document->resolve_to<StringObject>(args[0]))->string(); auto text = MUST(m_document->resolve_to<StringObject>(args[0]))->string();
show_text(text); show_text(text);
return {};
} }
RENDERER_HANDLER(text_next_line_show_string) RENDERER_HANDLER(text_next_line_show_string)
{ {
handle_text_next_line(args); TRY(handle_text_next_line(args));
handle_text_show_string(args); TRY(handle_text_show_string(args));
return {};
} }
RENDERER_TODO(text_next_line_show_string_set_spacing); RENDERER_TODO(text_next_line_show_string_set_spacing)
RENDERER_HANDLER(text_show_string_array) RENDERER_HANDLER(text_show_string_array)
{ {
@ -406,85 +450,97 @@ RENDERER_HANDLER(text_show_string_array)
show_text(str, next_shift); show_text(str, next_shift);
} }
} }
return {};
} }
RENDERER_TODO(type3_font_set_glyph_width); RENDERER_TODO(type3_font_set_glyph_width)
RENDERER_TODO(type3_font_set_glyph_width_and_bbox); RENDERER_TODO(type3_font_set_glyph_width_and_bbox)
RENDERER_HANDLER(set_stroking_space) RENDERER_HANDLER(set_stroking_space)
{ {
state().stroke_color_space = MUST(get_color_space(args[0])); state().stroke_color_space = MUST(get_color_space(args[0]));
VERIFY(state().stroke_color_space); VERIFY(state().stroke_color_space);
return {};
} }
RENDERER_HANDLER(set_painting_space) RENDERER_HANDLER(set_painting_space)
{ {
state().paint_color_space = MUST(get_color_space(args[0])); state().paint_color_space = MUST(get_color_space(args[0]));
VERIFY(state().paint_color_space); VERIFY(state().paint_color_space);
return {};
} }
RENDERER_HANDLER(set_stroking_color) RENDERER_HANDLER(set_stroking_color)
{ {
state().stroke_color = state().stroke_color_space->color(args); state().stroke_color = state().stroke_color_space->color(args);
return {};
} }
RENDERER_TODO(set_stroking_color_extended); RENDERER_TODO(set_stroking_color_extended)
RENDERER_HANDLER(set_painting_color) RENDERER_HANDLER(set_painting_color)
{ {
state().paint_color = state().paint_color_space->color(args); state().paint_color = state().paint_color_space->color(args);
return {};
} }
RENDERER_TODO(set_painting_color_extended); RENDERER_TODO(set_painting_color_extended)
RENDERER_HANDLER(set_stroking_color_and_space_to_gray) RENDERER_HANDLER(set_stroking_color_and_space_to_gray)
{ {
state().stroke_color_space = DeviceGrayColorSpace::the(); state().stroke_color_space = DeviceGrayColorSpace::the();
state().stroke_color = state().stroke_color_space->color(args); state().stroke_color = state().stroke_color_space->color(args);
return {};
} }
RENDERER_HANDLER(set_painting_color_and_space_to_gray) RENDERER_HANDLER(set_painting_color_and_space_to_gray)
{ {
state().paint_color_space = DeviceGrayColorSpace::the(); state().paint_color_space = DeviceGrayColorSpace::the();
state().paint_color = state().paint_color_space->color(args); state().paint_color = state().paint_color_space->color(args);
return {};
} }
RENDERER_HANDLER(set_stroking_color_and_space_to_rgb) RENDERER_HANDLER(set_stroking_color_and_space_to_rgb)
{ {
state().stroke_color_space = DeviceRGBColorSpace::the(); state().stroke_color_space = DeviceRGBColorSpace::the();
state().stroke_color = state().stroke_color_space->color(args); state().stroke_color = state().stroke_color_space->color(args);
return {};
} }
RENDERER_HANDLER(set_painting_color_and_space_to_rgb) RENDERER_HANDLER(set_painting_color_and_space_to_rgb)
{ {
state().paint_color_space = DeviceRGBColorSpace::the(); state().paint_color_space = DeviceRGBColorSpace::the();
state().paint_color = state().paint_color_space->color(args); state().paint_color = state().paint_color_space->color(args);
return {};
} }
RENDERER_HANDLER(set_stroking_color_and_space_to_cmyk) RENDERER_HANDLER(set_stroking_color_and_space_to_cmyk)
{ {
state().stroke_color_space = DeviceCMYKColorSpace::the(); state().stroke_color_space = DeviceCMYKColorSpace::the();
state().stroke_color = state().stroke_color_space->color(args); state().stroke_color = state().stroke_color_space->color(args);
return {};
} }
RENDERER_HANDLER(set_painting_color_and_space_to_cmyk) RENDERER_HANDLER(set_painting_color_and_space_to_cmyk)
{ {
state().paint_color_space = DeviceCMYKColorSpace::the(); state().paint_color_space = DeviceCMYKColorSpace::the();
state().paint_color = state().paint_color_space->color(args); state().paint_color = state().paint_color_space->color(args);
return {};
} }
RENDERER_TODO(shade); RENDERER_TODO(shade)
RENDERER_TODO(inline_image_begin); RENDERER_TODO(inline_image_begin)
RENDERER_TODO(inline_image_begin_data); RENDERER_TODO(inline_image_begin_data)
RENDERER_TODO(inline_image_end); RENDERER_TODO(inline_image_end)
RENDERER_TODO(paint_xobject); RENDERER_TODO(paint_xobject)
RENDERER_TODO(marked_content_point); RENDERER_TODO(marked_content_point)
RENDERER_TODO(marked_content_designate); RENDERER_TODO(marked_content_designate)
RENDERER_TODO(marked_content_begin); RENDERER_TODO(marked_content_begin)
RENDERER_TODO(marked_content_begin_with_property_list); RENDERER_TODO(marked_content_begin_with_property_list)
RENDERER_TODO(marked_content_end); RENDERER_TODO(marked_content_end)
RENDERER_TODO(compatibility_begin); RENDERER_TODO(compatibility_begin)
RENDERER_TODO(compatibility_end); RENDERER_TODO(compatibility_end)
template<typename T> template<typename T>
Gfx::Point<T> Renderer::map(T x, T y) const Gfx::Point<T> Renderer::map(T x, T y) const
@ -505,25 +561,29 @@ Gfx::Rect<T> Renderer::map(Gfx::Rect<T> rect) const
return state().ctm.map(rect); return state().ctm.map(rect);
} }
void Renderer::set_graphics_state_from_dict(NonnullRefPtr<DictObject> dict) PDFErrorOr<void> Renderer::set_graphics_state_from_dict(NonnullRefPtr<DictObject> dict)
{ {
if (dict->contains(CommonNames::LW)) if (dict->contains(CommonNames::LW))
handle_set_line_width({ dict->get_value(CommonNames::LW) }); TRY(handle_set_line_width({ dict->get_value(CommonNames::LW) }));
if (dict->contains(CommonNames::LC)) if (dict->contains(CommonNames::LC))
handle_set_line_cap({ dict->get_value(CommonNames::LC) }); TRY(handle_set_line_cap({ dict->get_value(CommonNames::LC) }));
if (dict->contains(CommonNames::LJ)) if (dict->contains(CommonNames::LJ))
handle_set_line_join({ dict->get_value(CommonNames::LJ) }); TRY(handle_set_line_join({ dict->get_value(CommonNames::LJ) }));
if (dict->contains(CommonNames::ML)) if (dict->contains(CommonNames::ML))
handle_set_miter_limit({ dict->get_value(CommonNames::ML) }); TRY(handle_set_miter_limit({ dict->get_value(CommonNames::ML) }));
if (dict->contains(CommonNames::D)) if (dict->contains(CommonNames::D)) {
handle_set_dash_pattern(MUST(dict->get_array(m_document, CommonNames::D))->elements()); auto array = MUST(dict->get_array(m_document, CommonNames::D));
TRY(handle_set_dash_pattern(array->elements()));
}
if (dict->contains(CommonNames::FL)) if (dict->contains(CommonNames::FL))
handle_set_flatness_tolerance({ dict->get_value(CommonNames::FL) }); TRY(handle_set_flatness_tolerance({ dict->get_value(CommonNames::FL) }));
return {};
} }
void Renderer::show_text(String const& string, float shift) void Renderer::show_text(String const& string, float shift)

View file

@ -79,22 +79,22 @@ struct GraphicsState {
class Renderer { class Renderer {
public: public:
static void render(Document&, Page const&, RefPtr<Gfx::Bitmap>); static PDFErrorOr<void> render(Document&, Page const&, RefPtr<Gfx::Bitmap>);
private: private:
Renderer(RefPtr<Document>, Page const&, RefPtr<Gfx::Bitmap>); Renderer(RefPtr<Document>, Page const&, RefPtr<Gfx::Bitmap>);
void render(); PDFErrorOr<void> render();
void handle_command(Command const&); PDFErrorOr<void> handle_command(Command const&);
#define V(name, snake_name, symbol) \ #define V(name, snake_name, symbol) \
void handle_##snake_name(Vector<Value> const& args); PDFErrorOr<void> handle_##snake_name(Vector<Value> const& args);
ENUMERATE_COMMANDS(V) ENUMERATE_COMMANDS(V)
#undef V #undef V
void handle_text_next_line_show_string(Vector<Value> const& args); PDFErrorOr<void> handle_text_next_line_show_string(Vector<Value> const& args);
void handle_text_next_line_show_string_set_spacing(Vector<Value> const& args); PDFErrorOr<void> handle_text_next_line_show_string_set_spacing(Vector<Value> const& args);
void set_graphics_state_from_dict(NonnullRefPtr<DictObject>); PDFErrorOr<void> set_graphics_state_from_dict(NonnullRefPtr<DictObject>);
// shift is the manual advance given in the TJ command array // shift is the manual advance given in the TJ command array
void show_text(String const&, float shift = 0.0f); void show_text(String const&, float shift = 0.0f);
PDFErrorOr<NonnullRefPtr<ColorSpace>> get_color_space(Value const&); PDFErrorOr<NonnullRefPtr<ColorSpace>> get_color_space(Value const&);