Renderer.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. * Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Utf8View.h>
  7. #include <LibPDF/Renderer.h>
  8. #include <ctype.h>
  9. #include <math.h>
  10. namespace PDF {
  11. void Renderer::render(Document& document, const Page& page, RefPtr<Gfx::Bitmap> bitmap)
  12. {
  13. Renderer(document, page, bitmap).render();
  14. }
  15. Renderer::Renderer(RefPtr<Document> document, const Page& page, RefPtr<Gfx::Bitmap> bitmap)
  16. : m_document(document)
  17. , m_bitmap(bitmap)
  18. , m_page(page)
  19. , m_painter(*bitmap)
  20. {
  21. auto media_box = m_page.media_box;
  22. m_userspace_matrix.translate(media_box.lower_left_x, media_box.lower_left_y);
  23. float width = media_box.upper_right_x - media_box.lower_left_x;
  24. float height = media_box.upper_right_y - media_box.lower_left_y;
  25. float scale_x = static_cast<float>(bitmap->width()) / width;
  26. float scale_y = static_cast<float>(bitmap->height()) / height;
  27. m_userspace_matrix.scale(scale_x, scale_y);
  28. m_graphics_state_stack.append(GraphicsState { m_userspace_matrix });
  29. m_bitmap->fill(Gfx::Color::NamedColor::White);
  30. }
  31. void Renderer::render()
  32. {
  33. // Use our own vector, as the /Content can be an array with multiple
  34. // streams which gets concatenated
  35. // FIXME: Text operators are supposed to only have effects on the current
  36. // stream object. Do the text operators treat this concatenated stream
  37. // as one stream or multiple?
  38. ByteBuffer byte_buffer;
  39. if (m_page.contents->is_array()) {
  40. auto contents = object_cast<ArrayObject>(m_page.contents);
  41. for (auto& ref : *contents) {
  42. auto bytes = m_document->resolve_to<StreamObject>(ref)->bytes();
  43. byte_buffer.append(bytes.data(), bytes.size());
  44. }
  45. } else {
  46. VERIFY(m_page.contents->is_stream());
  47. auto bytes = object_cast<StreamObject>(m_page.contents)->bytes();
  48. byte_buffer.append(bytes.data(), bytes.size());
  49. }
  50. auto commands = Parser::parse_graphics_commands(byte_buffer);
  51. for (auto& command : commands)
  52. handle_command(command);
  53. }
  54. void Renderer::handle_command(const Command& command)
  55. {
  56. switch (command.command_type()) {
  57. #define V(name, snake_name, symbol) \
  58. case CommandType::name: \
  59. return handle_##snake_name(command.arguments());
  60. ENUMERATE_COMMANDS(V)
  61. #undef V
  62. case CommandType::TextNextLineShowString:
  63. return handle_text_next_line_show_string(command.arguments());
  64. }
  65. }
  66. void Renderer::handle_save_state(const Vector<Value>&)
  67. {
  68. m_graphics_state_stack.append(state());
  69. }
  70. void Renderer::handle_restore_state(const Vector<Value>&)
  71. {
  72. m_graphics_state_stack.take_last();
  73. }
  74. void Renderer::handle_concatenate_matrix(const Vector<Value>& args)
  75. {
  76. Gfx::AffineTransform new_transform(
  77. args[0].to_float(),
  78. args[1].to_float(),
  79. args[2].to_float(),
  80. args[3].to_float(),
  81. args[4].to_float(),
  82. args[5].to_float());
  83. state().ctm.multiply(new_transform);
  84. m_text_rendering_matrix_is_dirty = true;
  85. }
  86. void Renderer::handle_set_line_width(const Vector<Value>& args)
  87. {
  88. state().line_width = args[0].to_float();
  89. }
  90. void Renderer::handle_set_line_cap(const Vector<Value>& args)
  91. {
  92. state().line_cap_style = static_cast<LineCapStyle>(args[0].as_int());
  93. }
  94. void Renderer::handle_set_line_join(const Vector<Value>& args)
  95. {
  96. state().line_join_style = static_cast<LineJoinStyle>(args[0].as_int());
  97. }
  98. void Renderer::handle_set_miter_limit(const Vector<Value>& args)
  99. {
  100. state().miter_limit = args[0].to_float();
  101. }
  102. void Renderer::handle_set_dash_pattern(const Vector<Value>& args)
  103. {
  104. auto dash_array = m_document->resolve_to<ArrayObject>(args[0]);
  105. Vector<int> pattern;
  106. for (auto& element : *dash_array)
  107. pattern.append(element.as_int());
  108. state().line_dash_pattern = LineDashPattern { pattern, args[1].as_int() };
  109. }
  110. void Renderer::handle_path_begin(const Vector<Value>&)
  111. {
  112. m_path = Gfx::Path();
  113. }
  114. void Renderer::handle_path_end(const Vector<Value>&)
  115. {
  116. }
  117. void Renderer::handle_path_line(const Vector<Value>& args)
  118. {
  119. m_path.line_to(map(args[0].to_float(), args[1].to_float()));
  120. }
  121. void Renderer::handle_path_close(const Vector<Value>&)
  122. {
  123. m_path.close();
  124. }
  125. void Renderer::handle_path_append_rect(const Vector<Value>& args)
  126. {
  127. auto pos = map(args[0].to_float(), args[1].to_float());
  128. auto size = map(Gfx::FloatSize { args[2].to_float(), args[3].to_float() });
  129. m_path.move_to(pos);
  130. m_path.line_to({ pos.x() + size.width(), pos.y() });
  131. m_path.line_to({ pos.x() + size.width(), pos.y() + size.height() });
  132. m_path.line_to({ pos.x(), pos.y() + size.height() });
  133. m_path.close();
  134. }
  135. void Renderer::handle_path_stroke(const Vector<Value>&)
  136. {
  137. m_painter.stroke_path(m_path, state().stroke_color, state().line_width);
  138. }
  139. void Renderer::handle_path_close_and_stroke(const Vector<Value>& args)
  140. {
  141. m_path.close();
  142. handle_path_stroke(args);
  143. }
  144. void Renderer::handle_path_fill_nonzero(const Vector<Value>&)
  145. {
  146. m_painter.fill_path(m_path, state().paint_color, Gfx::Painter::WindingRule::Nonzero);
  147. }
  148. void Renderer::handle_path_fill_nonzero_deprecated(const Vector<Value>& args)
  149. {
  150. handle_path_fill_nonzero(args);
  151. }
  152. void Renderer::handle_path_fill_evenodd(const Vector<Value>&)
  153. {
  154. m_painter.fill_path(m_path, state().paint_color, Gfx::Painter::WindingRule::EvenOdd);
  155. }
  156. void Renderer::handle_path_fill_stroke_nonzero(const Vector<Value>& args)
  157. {
  158. m_painter.stroke_path(m_path, state().stroke_color, state().line_width);
  159. handle_path_fill_nonzero(args);
  160. }
  161. void Renderer::handle_path_fill_stroke_evenodd(const Vector<Value>& args)
  162. {
  163. m_painter.stroke_path(m_path, state().stroke_color, state().line_width);
  164. handle_path_fill_evenodd(args);
  165. }
  166. void Renderer::handle_path_close_fill_stroke_nonzero(const Vector<Value>& args)
  167. {
  168. m_path.close();
  169. handle_path_fill_stroke_nonzero(args);
  170. }
  171. void Renderer::handle_path_close_fill_stroke_evenodd(const Vector<Value>& args)
  172. {
  173. m_path.close();
  174. handle_path_fill_stroke_evenodd(args);
  175. }
  176. void Renderer::handle_text_set_char_space(const Vector<Value>& args)
  177. {
  178. text_state().character_spacing = args[0].to_float();
  179. }
  180. void Renderer::handle_text_set_word_space(const Vector<Value>& args)
  181. {
  182. text_state().word_spacing = args[0].to_float();
  183. }
  184. void Renderer::handle_text_set_horizontal_scale(const Vector<Value>& args)
  185. {
  186. m_text_rendering_matrix_is_dirty = true;
  187. text_state().horizontal_scaling = args[0].to_float() / 100.0f;
  188. }
  189. void Renderer::handle_text_set_leading(const Vector<Value>& args)
  190. {
  191. text_state().leading = args[0].to_float();
  192. }
  193. void Renderer::handle_text_set_font(const Vector<Value>& args)
  194. {
  195. auto target_font_name = m_document->resolve_to<NameObject>(args[0])->name();
  196. auto fonts_dictionary = m_page.resources->get_dict(m_document, "Font");
  197. auto font_dictionary = fonts_dictionary->get_dict(m_document, target_font_name);
  198. // FIXME: We do not yet have the standard 14 fonts, as some of them are not open fonts,
  199. // so we just use LiberationSerif for everything
  200. auto font_name = font_dictionary->get_name(m_document, "BaseFont")->name().to_lowercase();
  201. auto font_view = font_name.view();
  202. bool is_bold = font_view.contains("bold");
  203. bool is_italic = font_view.contains("italic");
  204. String font_variant;
  205. if (is_bold && is_italic) {
  206. font_variant = "BoldItalic";
  207. } else if (is_bold) {
  208. font_variant = "Bold";
  209. } else if (is_italic) {
  210. font_variant = "Italic";
  211. } else {
  212. font_variant = "Regular";
  213. }
  214. auto specified_font_size = args[1].to_float();
  215. // FIXME: This scaling should occur when drawing the glyph rather than selecting the font.
  216. // This should be removed when the painter supports arbitrary bitmap scaling.
  217. specified_font_size *= state().ctm.x_scale();
  218. text_state().font = Gfx::FontDatabase::the().get("Liberation Serif", font_variant, static_cast<int>(specified_font_size));
  219. VERIFY(text_state().font);
  220. m_text_rendering_matrix_is_dirty = true;
  221. }
  222. void Renderer::handle_text_set_rendering_mode(const Vector<Value>& args)
  223. {
  224. text_state().rendering_mode = static_cast<TextRenderingMode>(args[0].as_int());
  225. }
  226. void Renderer::handle_text_set_rise(const Vector<Value>& args)
  227. {
  228. m_text_rendering_matrix_is_dirty = true;
  229. text_state().rise = args[0].to_float();
  230. }
  231. void Renderer::handle_text_begin(const Vector<Value>&)
  232. {
  233. m_text_matrix = Gfx::AffineTransform();
  234. m_text_line_matrix = Gfx::AffineTransform();
  235. }
  236. void Renderer::handle_text_end(const Vector<Value>&)
  237. {
  238. // FIXME: Do we need to do anything here?
  239. }
  240. void Renderer::handle_text_next_line_offset(const Vector<Value>& args)
  241. {
  242. Gfx::AffineTransform transform(1.0f, 0.0f, 0.0f, 1.0f, args[0].to_float(), args[1].to_float());
  243. transform.multiply(m_text_line_matrix);
  244. m_text_matrix = transform;
  245. m_text_line_matrix = transform;
  246. m_text_rendering_matrix_is_dirty = true;
  247. }
  248. void Renderer::handle_text_next_line_and_set_leading(const Vector<Value>& args)
  249. {
  250. text_state().leading = -args[1].to_float();
  251. handle_text_next_line_offset(args);
  252. }
  253. void Renderer::handle_text_set_matrix_and_line_matrix(const Vector<Value>& args)
  254. {
  255. Gfx::AffineTransform new_transform(
  256. args[0].to_float(),
  257. args[1].to_float(),
  258. args[2].to_float(),
  259. args[3].to_float(),
  260. args[4].to_float(),
  261. args[5].to_float());
  262. m_text_line_matrix = new_transform;
  263. m_text_matrix = new_transform;
  264. m_text_rendering_matrix_is_dirty = true;
  265. }
  266. void Renderer::handle_text_next_line(const Vector<Value>&)
  267. {
  268. handle_text_next_line_offset({ 0.0f, -text_state().leading });
  269. }
  270. void Renderer::handle_text_show_string(const Vector<Value>& args)
  271. {
  272. auto text = m_document->resolve_to<StringObject>(args[0])->string();
  273. show_text(text);
  274. }
  275. void Renderer::handle_text_next_line_show_string(const Vector<Value>& args)
  276. {
  277. handle_text_next_line(args);
  278. handle_text_show_string(args);
  279. }
  280. template<typename T>
  281. Gfx::Point<T> Renderer::map(T x, T y) const
  282. {
  283. auto mapped = state().ctm.map(Gfx::Point<T> { x, y });
  284. return { mapped.x(), static_cast<T>(m_bitmap->height()) - mapped.y() };
  285. }
  286. template<typename T>
  287. Gfx::Size<T> Renderer::map(Gfx::Size<T> size) const
  288. {
  289. return state().ctm.map(size);
  290. }
  291. void Renderer::show_text(const String& string, int shift)
  292. {
  293. auto utf = Utf8View(string);
  294. auto& font = text_state().font;
  295. for (auto codepoint : utf) {
  296. // FIXME: Don't calculate this matrix for every character
  297. auto& text_rendering_matrix = calculate_text_rendering_matrix();
  298. auto text_position = text_rendering_matrix.map(Gfx::FloatPoint { 0.0f, 0.0f });
  299. text_position.set_y(static_cast<float>(m_bitmap->height()) - text_position.y());
  300. // FIXME: For some reason, the space character in LiberationSerif is drawn as an exclamation point
  301. if (codepoint != 0x20)
  302. m_painter.draw_glyph(text_position.to_type<int>(), codepoint, *text_state().font, state().paint_color);
  303. auto glyph_width = static_cast<float>(font->glyph_width(codepoint));
  304. auto tx = (glyph_width - static_cast<float>(shift) / 1000.0f);
  305. tx += text_state().character_spacing;
  306. if (codepoint == ' ')
  307. tx += text_state().word_spacing;
  308. tx *= text_state().horizontal_scaling;
  309. m_text_rendering_matrix_is_dirty = true;
  310. m_text_matrix = Gfx::AffineTransform(1, 0, 0, 1, tx, 0).multiply(m_text_matrix);
  311. }
  312. }
  313. const Gfx::AffineTransform& Renderer::calculate_text_rendering_matrix()
  314. {
  315. if (m_text_rendering_matrix_is_dirty) {
  316. m_text_rendering_matrix = Gfx::AffineTransform(
  317. text_state().horizontal_scaling,
  318. 0.0f,
  319. 0.0f,
  320. 1.0f,
  321. 0.0f,
  322. text_state().rise);
  323. m_text_rendering_matrix.multiply(m_text_matrix);
  324. m_text_rendering_matrix.multiply(state().ctm);
  325. m_text_rendering_matrix_is_dirty = false;
  326. }
  327. return m_text_rendering_matrix;
  328. }
  329. }