mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:52:45 +00:00 
			
		
		
		
	LibPDF: Propagate errors in Renderer/PDFViewer
This commit is contained in:
		
							parent
							
								
									d82bd885ce
								
							
						
					
					
						commit
						b240d23a87
					
				
					 4 changed files with 140 additions and 72 deletions
				
			
		|  | @ -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. | ||||
|  * | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  | @ -8,6 +8,7 @@ | |||
| #include "PDFViewer.h" | ||||
| #include <AK/Array.h> | ||||
| #include <LibGUI/Action.h> | ||||
| #include <LibGUI/MessageBox.h> | ||||
| #include <LibGUI/Painter.h> | ||||
| #include <LibPDF/Renderer.h> | ||||
| 
 | ||||
|  | @ -56,15 +57,15 @@ void PDFViewer::set_document(RefPtr<PDF::Document> document) | |||
|     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 existing_rendered_page = rendered_page_map.get(m_zoom_level); | ||||
|     if (existing_rendered_page.has_value() && existing_rendered_page.value().rotation == m_rotations) | ||||
|         return existing_rendered_page.value().bitmap; | ||||
| 
 | ||||
|     // FIXME: Propogate errors in the Renderer
 | ||||
|     auto rendered_page = render_page(MUST(m_document->get_page(index))); | ||||
|     auto page = TRY(m_document->get_page(index)); | ||||
|     auto rendered_page = TRY(render_page(page)); | ||||
|     rendered_page_map.set(m_zoom_level, { rendered_page, m_rotations }); | ||||
|     return rendered_page; | ||||
| } | ||||
|  | @ -81,7 +82,14 @@ void PDFViewer::paint_event(GUI::PaintEvent& event) | |||
|     if (!m_document) | ||||
|         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()); | ||||
| 
 | ||||
|     painter.translate(frame_thickness(), frame_thickness()); | ||||
|  | @ -196,7 +204,7 @@ void PDFViewer::rotate(int degrees) | |||
|     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; | ||||
| 
 | ||||
|  | @ -208,7 +216,7 @@ RefPtr<Gfx::Bitmap> PDFViewer::render_page(const PDF::Page& page) | |||
|     auto width = height / page_scale_factor; | ||||
|     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) { | ||||
|         int rotation_count = ((page.rotate + m_rotations) / 90) % 4; | ||||
|  |  | |||
|  | @ -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. | ||||
|  * | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  | @ -45,12 +45,12 @@ protected: | |||
| 
 | ||||
| private: | ||||
|     struct RenderedPage { | ||||
|         RefPtr<Gfx::Bitmap> bitmap; | ||||
|         NonnullRefPtr<Gfx::Bitmap> bitmap; | ||||
|         int rotation; | ||||
|     }; | ||||
| 
 | ||||
|     RefPtr<Gfx::Bitmap> get_rendered_page(u32 index); | ||||
|     RefPtr<Gfx::Bitmap> render_page(const PDF::Page&); | ||||
|     PDF::PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> get_rendered_page(u32 index); | ||||
|     PDF::PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> render_page(const PDF::Page&); | ||||
| 
 | ||||
|     RefPtr<PDF::Document> m_document; | ||||
|     u32 m_current_page_index { 0 }; | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ | |||
| #include <LibPDF/Renderer.h> | ||||
| 
 | ||||
| #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)                                         \ | ||||
|     RENDERER_HANDLER(name)                                          \ | ||||
|  | @ -20,9 +20,9 @@ | |||
| 
 | ||||
| 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) | ||||
|  | @ -56,7 +56,7 @@ Renderer::Renderer(RefPtr<Document> document, Page const& page, RefPtr<Gfx::Bitm | |||
|     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
 | ||||
|     // streams which gets concatenated
 | ||||
|  | @ -68,7 +68,7 @@ void Renderer::render() | |||
|     if (m_page.contents->is<ArrayObject>()) { | ||||
|         auto contents = m_page.contents->cast<ArrayObject>(); | ||||
|         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()); | ||||
|         } | ||||
|     } else { | ||||
|  | @ -76,38 +76,44 @@ void Renderer::render() | |||
|         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) | ||||
|         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()) { | ||||
| #define V(name, snake_name, symbol)                    \ | ||||
|     case CommandType::name:                            \ | ||||
|         handle_##snake_name(command.arguments()); \ | ||||
|         TRY(handle_##snake_name(command.arguments())); \ | ||||
|         break; | ||||
|         ENUMERATE_COMMANDS(V) | ||||
| #undef V | ||||
|     case CommandType::TextNextLineShowString: | ||||
|         handle_text_next_line_show_string(command.arguments()); | ||||
|         TRY(handle_text_next_line_show_string(command.arguments())); | ||||
|         break; | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(save_state) | ||||
| { | ||||
|     m_graphics_state_stack.append(state()); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(restore_state) | ||||
| { | ||||
|     m_graphics_state_stack.take_last(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(concatenate_matrix) | ||||
|  | @ -122,26 +128,31 @@ RENDERER_HANDLER(concatenate_matrix) | |||
| 
 | ||||
|     state().ctm.multiply(new_transform); | ||||
|     m_text_rendering_matrix_is_dirty = true; | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(set_line_width) | ||||
| { | ||||
|     state().line_width = args[0].to_float(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(set_line_cap) | ||||
| { | ||||
|     state().line_cap_style = static_cast<LineCapStyle>(args[0].get<int>()); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(set_line_join) | ||||
| { | ||||
|     state().line_join_style = static_cast<LineJoinStyle>(args[0].get<int>()); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(set_miter_limit) | ||||
| { | ||||
|     state().miter_limit = args[0].to_float(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(set_dash_pattern) | ||||
|  | @ -151,10 +162,11 @@ RENDERER_HANDLER(set_dash_pattern) | |||
|     for (auto& element : *dash_array) | ||||
|         pattern.append(element.get<int>()); | ||||
|     state().line_dash_pattern = LineDashPattern { pattern, args[1].get<int>() }; | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_TODO(set_color_rendering_intent); | ||||
| RENDERER_TODO(set_flatness_tolerance); | ||||
| RENDERER_TODO(set_color_rendering_intent) | ||||
| RENDERER_TODO(set_flatness_tolerance) | ||||
| 
 | ||||
| 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 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)); | ||||
|     set_graphics_state_from_dict(target_dict); | ||||
|     TRY(set_graphics_state_from_dict(target_dict)); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(path_move) | ||||
| { | ||||
|     m_current_path.move_to(map(args[0].to_float(), args[1].to_float())); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(path_line) | ||||
| { | ||||
|     VERIFY(!m_current_path.segments().is_empty()); | ||||
|     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_no_first_control); | ||||
| RENDERER_TODO(path_cubic_bezier_curve_no_second_control); | ||||
| RENDERER_TODO(path_cubic_bezier_curve) | ||||
| RENDERER_TODO(path_cubic_bezier_curve_no_first_control) | ||||
| RENDERER_TODO(path_cubic_bezier_curve_no_second_control) | ||||
| 
 | ||||
| RENDERER_HANDLER(path_close) | ||||
| { | ||||
|     m_current_path.close(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| 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(), pos.y() + size.height() }); | ||||
|     m_current_path.close(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(path_stroke) | ||||
| { | ||||
|     m_painter.stroke_path(m_current_path, state().stroke_color, state().line_width); | ||||
|     m_current_path.clear(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(path_close_and_stroke) | ||||
| { | ||||
|     m_current_path.close(); | ||||
|     handle_path_stroke(args); | ||||
|     TRY(handle_path_stroke(args)); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(path_fill_nonzero) | ||||
| { | ||||
|     m_painter.fill_path(m_current_path, state().paint_color, Gfx::Painter::WindingRule::Nonzero); | ||||
|     m_current_path.clear(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(path_fill_nonzero_deprecated) | ||||
| { | ||||
|     handle_path_fill_nonzero(args); | ||||
|     TRY(handle_path_fill_nonzero(args)); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(path_fill_evenodd) | ||||
| { | ||||
|     m_painter.fill_path(m_current_path, state().paint_color, Gfx::Painter::WindingRule::EvenOdd); | ||||
|     m_current_path.clear(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(path_fill_stroke_nonzero) | ||||
| { | ||||
|     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) | ||||
| { | ||||
|     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) | ||||
| { | ||||
|     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) | ||||
| { | ||||
|     m_current_path.close(); | ||||
|     handle_path_fill_stroke_evenodd(args); | ||||
|     TRY(handle_path_fill_stroke_evenodd(args)); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(path_end) | ||||
| { | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| 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
 | ||||
|     auto bounding_box = map(m_current_path.bounding_box()); | ||||
|     m_painter.add_clip_rect(bounding_box.to_type<int>()); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| 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
 | ||||
|     auto bounding_box = map(m_current_path.bounding_box()); | ||||
|     m_painter.add_clip_rect(bounding_box.to_type<int>()); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(text_begin) | ||||
| { | ||||
|     m_text_matrix = Gfx::AffineTransform(); | ||||
|     m_text_line_matrix = Gfx::AffineTransform(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(text_end) | ||||
| { | ||||
|     // FIXME: Do we need to do anything here?
 | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(text_set_char_space) | ||||
| { | ||||
|     text_state().character_spacing = args[0].to_float(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(text_set_word_space) | ||||
| { | ||||
|     text_state().word_spacing = args[0].to_float(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(text_set_horizontal_scale) | ||||
| { | ||||
|     m_text_rendering_matrix_is_dirty = true; | ||||
|     text_state().horizontal_scaling = args[0].to_float() / 100.0f; | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(text_set_leading) | ||||
| { | ||||
|     text_state().leading = args[0].to_float(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(text_set_font) | ||||
|  | @ -330,17 +365,20 @@ RENDERER_HANDLER(text_set_font) | |||
|     text_state().font_variant = font_variant; | ||||
| 
 | ||||
|     m_text_rendering_matrix_is_dirty = true; | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(text_set_rendering_mode) | ||||
| { | ||||
|     text_state().rendering_mode = static_cast<TextRenderingMode>(args[0].get<int>()); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(text_set_rise) | ||||
| { | ||||
|     m_text_rendering_matrix_is_dirty = true; | ||||
|     text_state().rise = args[0].to_float(); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(text_next_line_offset) | ||||
|  | @ -350,12 +388,14 @@ RENDERER_HANDLER(text_next_line_offset) | |||
|     m_text_matrix = transform; | ||||
|     m_text_line_matrix = transform; | ||||
|     m_text_rendering_matrix_is_dirty = true; | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(text_next_line_and_set_leading) | ||||
| { | ||||
|     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) | ||||
|  | @ -370,26 +410,30 @@ RENDERER_HANDLER(text_set_matrix_and_line_matrix) | |||
|     m_text_line_matrix = new_transform; | ||||
|     m_text_matrix = new_transform; | ||||
|     m_text_rendering_matrix_is_dirty = true; | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
|     auto text = MUST(m_document->resolve_to<StringObject>(args[0]))->string(); | ||||
|     show_text(text); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(text_next_line_show_string) | ||||
| { | ||||
|     handle_text_next_line(args); | ||||
|     handle_text_show_string(args); | ||||
|     TRY(handle_text_next_line(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) | ||||
| { | ||||
|  | @ -406,85 +450,97 @@ RENDERER_HANDLER(text_show_string_array) | |||
|             show_text(str, next_shift); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_TODO(type3_font_set_glyph_width); | ||||
| RENDERER_TODO(type3_font_set_glyph_width_and_bbox); | ||||
| RENDERER_TODO(type3_font_set_glyph_width) | ||||
| RENDERER_TODO(type3_font_set_glyph_width_and_bbox) | ||||
| 
 | ||||
| RENDERER_HANDLER(set_stroking_space) | ||||
| { | ||||
|     state().stroke_color_space = MUST(get_color_space(args[0])); | ||||
|     VERIFY(state().stroke_color_space); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(set_painting_space) | ||||
| { | ||||
|     state().paint_color_space = MUST(get_color_space(args[0])); | ||||
|     VERIFY(state().paint_color_space); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(set_stroking_color) | ||||
| { | ||||
|     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) | ||||
| { | ||||
|     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) | ||||
| { | ||||
|     state().stroke_color_space = DeviceGrayColorSpace::the(); | ||||
|     state().stroke_color = state().stroke_color_space->color(args); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(set_painting_color_and_space_to_gray) | ||||
| { | ||||
|     state().paint_color_space = DeviceGrayColorSpace::the(); | ||||
|     state().paint_color = state().paint_color_space->color(args); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(set_stroking_color_and_space_to_rgb) | ||||
| { | ||||
|     state().stroke_color_space = DeviceRGBColorSpace::the(); | ||||
|     state().stroke_color = state().stroke_color_space->color(args); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(set_painting_color_and_space_to_rgb) | ||||
| { | ||||
|     state().paint_color_space = DeviceRGBColorSpace::the(); | ||||
|     state().paint_color = state().paint_color_space->color(args); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(set_stroking_color_and_space_to_cmyk) | ||||
| { | ||||
|     state().stroke_color_space = DeviceCMYKColorSpace::the(); | ||||
|     state().stroke_color = state().stroke_color_space->color(args); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_HANDLER(set_painting_color_and_space_to_cmyk) | ||||
| { | ||||
|     state().paint_color_space = DeviceCMYKColorSpace::the(); | ||||
|     state().paint_color = state().paint_color_space->color(args); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| RENDERER_TODO(shade); | ||||
| RENDERER_TODO(inline_image_begin); | ||||
| RENDERER_TODO(inline_image_begin_data); | ||||
| RENDERER_TODO(inline_image_end); | ||||
| RENDERER_TODO(paint_xobject); | ||||
| RENDERER_TODO(marked_content_point); | ||||
| RENDERER_TODO(marked_content_designate); | ||||
| RENDERER_TODO(marked_content_begin); | ||||
| RENDERER_TODO(marked_content_begin_with_property_list); | ||||
| RENDERER_TODO(marked_content_end); | ||||
| RENDERER_TODO(compatibility_begin); | ||||
| RENDERER_TODO(compatibility_end); | ||||
| RENDERER_TODO(shade) | ||||
| RENDERER_TODO(inline_image_begin) | ||||
| RENDERER_TODO(inline_image_begin_data) | ||||
| RENDERER_TODO(inline_image_end) | ||||
| RENDERER_TODO(paint_xobject) | ||||
| RENDERER_TODO(marked_content_point) | ||||
| RENDERER_TODO(marked_content_designate) | ||||
| RENDERER_TODO(marked_content_begin) | ||||
| RENDERER_TODO(marked_content_begin_with_property_list) | ||||
| RENDERER_TODO(marked_content_end) | ||||
| RENDERER_TODO(compatibility_begin) | ||||
| RENDERER_TODO(compatibility_end) | ||||
| 
 | ||||
| template<typename T> | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| 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)) | ||||
|         handle_set_line_width({ dict->get_value(CommonNames::LW) }); | ||||
|         TRY(handle_set_line_width({ dict->get_value(CommonNames::LW) })); | ||||
| 
 | ||||
|     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)) | ||||
|         handle_set_line_join({ dict->get_value(CommonNames::LJ) }); | ||||
|         TRY(handle_set_line_join({ dict->get_value(CommonNames::LJ) })); | ||||
| 
 | ||||
|     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)) | ||||
|         handle_set_dash_pattern(MUST(dict->get_array(m_document, CommonNames::D))->elements()); | ||||
|     if (dict->contains(CommonNames::D)) { | ||||
|         auto array = MUST(dict->get_array(m_document, CommonNames::D)); | ||||
|         TRY(handle_set_dash_pattern(array->elements())); | ||||
|     } | ||||
| 
 | ||||
|     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) | ||||
|  |  | |||
|  | @ -79,22 +79,22 @@ struct GraphicsState { | |||
| 
 | ||||
| class Renderer { | ||||
| public: | ||||
|     static void render(Document&, Page const&, RefPtr<Gfx::Bitmap>); | ||||
|     static PDFErrorOr<void> render(Document&, Page const&, RefPtr<Gfx::Bitmap>); | ||||
| 
 | ||||
| private: | ||||
|     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) \ | ||||
|     void handle_##snake_name(Vector<Value> const& args); | ||||
|     PDFErrorOr<void> handle_##snake_name(Vector<Value> const& args); | ||||
|     ENUMERATE_COMMANDS(V) | ||||
| #undef V | ||||
|     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(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
 | ||||
|     void show_text(String const&, float shift = 0.0f); | ||||
|     PDFErrorOr<NonnullRefPtr<ColorSpace>> get_color_space(Value const&); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Matthew Olsson
						Matthew Olsson