瀏覽代碼

LibPDF: Use a RAII object to restore state in recursive render

Previously, if one operator returned an error, the TRY() would cause
us to return without restoring the outer graphics state, leading to
problems such as handing a 3-tuple to a grayscale color space
(because the inner object set up a grayscale color space that we
failed to dispose of).

Makes us crash later on page 43 of
https://devstreaming-cdn.apple.com/videos/wwdc/2017/821kjtggolzxsv/821/821_get_started_with_display_p3.pdf
Nico Weber 1 年之前
父節點
當前提交
b835d2bd66
共有 1 個文件被更改,包括 19 次插入2 次删除
  1. 19 2
      Userland/Libraries/LibPDF/Renderer.cpp

+ 19 - 2
Userland/Libraries/LibPDF/Renderer.cpp

@@ -644,7 +644,25 @@ RENDERER_HANDLER(paint_xobject)
         return {};
         return {};
     }
     }
 
 
-    MUST(handle_save_state({}));
+    // Use a RAII object to restore the graphics state, to make sure it gets restored even if
+    // a TRY(handle_operator()) causes us to exit the operators loop early.
+    class ScopedState {
+    public:
+        ScopedState(Renderer& renderer)
+            : m_renderer(renderer)
+        {
+            MUST(m_renderer.handle_save_state({}));
+        }
+        ~ScopedState()
+        {
+            MUST(m_renderer.handle_restore_state({}));
+        }
+
+    private:
+        Renderer& m_renderer;
+    };
+    ScopedState scoped_state { *this };
+
     Vector<Value> matrix;
     Vector<Value> matrix;
     if (xobject->dict()->contains(CommonNames::Matrix)) {
     if (xobject->dict()->contains(CommonNames::Matrix)) {
         matrix = xobject->dict()->get_array(m_document, CommonNames::Matrix).value()->elements();
         matrix = xobject->dict()->get_array(m_document, CommonNames::Matrix).value()->elements();
@@ -655,7 +673,6 @@ RENDERER_HANDLER(paint_xobject)
     auto operators = TRY(Parser::parse_operators(m_document, xobject->bytes()));
     auto operators = TRY(Parser::parse_operators(m_document, xobject->bytes()));
     for (auto& op : operators)
     for (auto& op : operators)
         TRY(handle_operator(op, xobject_resources));
         TRY(handle_operator(op, xobject_resources));
-    MUST(handle_restore_state({}));
     return {};
     return {};
 }
 }