Ver código fonte

LibPDF: Use Variant<Color, PaintStyle> instead of Color for ColorSpaces

This is in anticipation of Pattern color space support which does not
yield a simple color.
Kyle Pereira 1 ano atrás
pai
commit
082a4197b6

+ 13 - 14
Userland/Libraries/LibPDF/ColorSpace.cpp

@@ -101,7 +101,7 @@ NonnullRefPtr<DeviceGrayColorSpace> DeviceGrayColorSpace::the()
     return instance;
 }
 
-PDFErrorOr<Color> DeviceGrayColorSpace::color(ReadonlySpan<Value> arguments) const
+PDFErrorOr<ColorOrStyle> DeviceGrayColorSpace::style(ReadonlySpan<Value> arguments) const
 {
     VERIFY(arguments.size() == 1);
     auto gray = static_cast<u8>(arguments[0].to_float() * 255.0f);
@@ -119,7 +119,7 @@ NonnullRefPtr<DeviceRGBColorSpace> DeviceRGBColorSpace::the()
     return instance;
 }
 
-PDFErrorOr<Color> DeviceRGBColorSpace::color(ReadonlySpan<Value> arguments) const
+PDFErrorOr<ColorOrStyle> DeviceRGBColorSpace::style(ReadonlySpan<Value> arguments) const
 {
     VERIFY(arguments.size() == 3);
     auto r = static_cast<u8>(arguments[0].to_float() * 255.0f);
@@ -139,7 +139,7 @@ NonnullRefPtr<DeviceCMYKColorSpace> DeviceCMYKColorSpace::the()
     return instance;
 }
 
-PDFErrorOr<Color> DeviceCMYKColorSpace::color(ReadonlySpan<Value> arguments) const
+PDFErrorOr<ColorOrStyle> DeviceCMYKColorSpace::style(ReadonlySpan<Value> arguments) const
 {
     VERIFY(arguments.size() == 4);
     auto c = arguments[0].to_float();
@@ -197,7 +197,7 @@ DeviceNColorSpace::DeviceNColorSpace(NonnullRefPtr<ColorSpace> alternate_space,
 {
 }
 
-PDFErrorOr<Color> DeviceNColorSpace::color(ReadonlySpan<Value> arguments) const
+PDFErrorOr<ColorOrStyle> DeviceNColorSpace::style(ReadonlySpan<Value> arguments) const
 {
     // FIXME: Does this need handling for the special colorant name "None"?
     // FIXME: When drawing to a printer, do something else.
@@ -211,7 +211,7 @@ PDFErrorOr<Color> DeviceNColorSpace::color(ReadonlySpan<Value> arguments) const
     for (size_t i = 0; i < tint_output.size(); ++i)
         m_tint_output_values[i] = tint_output[i];
 
-    return m_alternate_space->color(m_tint_output_values);
+    return m_alternate_space->style(m_tint_output_values);
 }
 
 int DeviceNColorSpace::number_of_components() const
@@ -347,7 +347,7 @@ PDFErrorOr<NonnullRefPtr<CalGrayColorSpace>> CalGrayColorSpace::create(Document*
     return color_space;
 }
 
-PDFErrorOr<Color> CalGrayColorSpace::color(ReadonlySpan<Value> arguments) const
+PDFErrorOr<ColorOrStyle> CalGrayColorSpace::style(ReadonlySpan<Value> arguments) const
 {
     VERIFY(arguments.size() == 1);
     auto a = clamp(arguments[0].to_float(), 0.0f, 1.0f);
@@ -433,7 +433,7 @@ PDFErrorOr<NonnullRefPtr<CalRGBColorSpace>> CalRGBColorSpace::create(Document* d
     return color_space;
 }
 
-PDFErrorOr<Color> CalRGBColorSpace::color(ReadonlySpan<Value> arguments) const
+PDFErrorOr<ColorOrStyle> CalRGBColorSpace::style(ReadonlySpan<Value> arguments) const
 {
     VERIFY(arguments.size() == 3);
     auto a = clamp(arguments[0].to_float(), 0.0f, 1.0f);
@@ -493,7 +493,7 @@ ICCBasedColorSpace::ICCBasedColorSpace(NonnullRefPtr<Gfx::ICC::Profile> profile)
 {
 }
 
-PDFErrorOr<Color> ICCBasedColorSpace::color(ReadonlySpan<Value> arguments) const
+PDFErrorOr<ColorOrStyle> ICCBasedColorSpace::style(ReadonlySpan<Value> arguments) const
 {
     if (!s_srgb_profile)
         s_srgb_profile = TRY(Gfx::ICC::sRGB());
@@ -593,7 +593,7 @@ PDFErrorOr<NonnullRefPtr<LabColorSpace>> LabColorSpace::create(Document* documen
     return color_space;
 }
 
-PDFErrorOr<Color> LabColorSpace::color(ReadonlySpan<Value> arguments) const
+PDFErrorOr<ColorOrStyle> LabColorSpace::style(ReadonlySpan<Value> arguments) const
 {
     VERIFY(arguments.size() == 3);
     auto L_star = clamp(arguments[0].to_float(), 0.0f, 100.0f);
@@ -692,7 +692,7 @@ IndexedColorSpace::IndexedColorSpace(NonnullRefPtr<ColorSpace> base)
 {
 }
 
-PDFErrorOr<Color> IndexedColorSpace::color(ReadonlySpan<Value> arguments) const
+PDFErrorOr<ColorOrStyle> IndexedColorSpace::style(ReadonlySpan<Value> arguments) const
 {
     VERIFY(arguments.size() == 1);
 
@@ -705,7 +705,7 @@ PDFErrorOr<Color> IndexedColorSpace::color(ReadonlySpan<Value> arguments) const
     for (size_t i = 0; i < n; ++i)
         TRY(components.try_append(Value(m_lookup[index * n + i] / 255.0f)));
 
-    return m_base->color(components);
+    return m_base->style(components);
 }
 
 Vector<float> IndexedColorSpace::default_decode() const
@@ -748,7 +748,7 @@ SeparationColorSpace::SeparationColorSpace(NonnullRefPtr<ColorSpace> alternate_s
 {
 }
 
-PDFErrorOr<Color> SeparationColorSpace::color(ReadonlySpan<Value> arguments) const
+PDFErrorOr<ColorOrStyle> SeparationColorSpace::style(ReadonlySpan<Value> arguments) const
 {
     // "For an additive device such as a computer display, a Separation color space never applies a process colorant directly;
     //  it always reverts to the alternate color space as described below."
@@ -765,12 +765,11 @@ PDFErrorOr<Color> SeparationColorSpace::color(ReadonlySpan<Value> arguments) con
     for (size_t i = 0; i < tint_output.size(); ++i)
         m_tint_output_values[i] = tint_output[i];
 
-    return m_alternate_space->color(m_tint_output_values);
+    return m_alternate_space->style(m_tint_output_values);
 }
 
 Vector<float> SeparationColorSpace::default_decode() const
 {
     return { 0.0f, 1.0f };
 }
-
 }

+ 15 - 12
Userland/Libraries/LibPDF/ColorSpace.h

@@ -10,6 +10,7 @@
 #include <AK/Forward.h>
 #include <LibGfx/Color.h>
 #include <LibGfx/ICC/Profile.h>
+#include <LibGfx/PaintStyle.h>
 #include <LibPDF/Function.h>
 #include <LibPDF/Value.h>
 
@@ -28,6 +29,9 @@
 
 namespace PDF {
 
+typedef Variant<Gfx::Color, NonnullRefPtr<Gfx::PaintStyle>> ColorOrStyle;
+class Renderer;
+
 class ColorSpaceFamily {
 public:
     ColorSpaceFamily(DeprecatedFlyString name, bool may_be_specified_directly)
@@ -62,7 +66,7 @@ public:
 
     virtual ~ColorSpace() = default;
 
-    virtual PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const = 0;
+    virtual PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const = 0;
     virtual int number_of_components() const = 0;
     virtual Vector<float> default_decode() const = 0; // "TABLE 4.40 Default Decode arrays"
     virtual ColorSpaceFamily const& family() const = 0;
@@ -74,7 +78,7 @@ public:
 
     ~DeviceGrayColorSpace() override = default;
 
-    PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
+    PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
     int number_of_components() const override { return 1; }
     Vector<float> default_decode() const override;
     ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceGray; }
@@ -89,7 +93,7 @@ public:
 
     ~DeviceRGBColorSpace() override = default;
 
-    PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
+    PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
     int number_of_components() const override { return 3; }
     Vector<float> default_decode() const override;
     ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceRGB; }
@@ -104,7 +108,7 @@ public:
 
     ~DeviceCMYKColorSpace() override = default;
 
-    PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
+    PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
     int number_of_components() const override { return 4; }
     Vector<float> default_decode() const override;
     ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceCMYK; }
@@ -119,7 +123,7 @@ public:
 
     ~DeviceNColorSpace() override = default;
 
-    PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
+    PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
     int number_of_components() const override;
     Vector<float> default_decode() const override;
     ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceN; }
@@ -140,7 +144,7 @@ public:
 
     ~CalGrayColorSpace() override = default;
 
-    PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
+    PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
     int number_of_components() const override { return 1; }
     Vector<float> default_decode() const override;
     ColorSpaceFamily const& family() const override { return ColorSpaceFamily::CalGray; }
@@ -159,7 +163,7 @@ public:
 
     ~CalRGBColorSpace() override = default;
 
-    PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
+    PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
     int number_of_components() const override { return 3; }
     Vector<float> default_decode() const override;
     ColorSpaceFamily const& family() const override { return ColorSpaceFamily::CalRGB; }
@@ -179,7 +183,7 @@ public:
 
     ~ICCBasedColorSpace() override = default;
 
-    PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
+    PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
     int number_of_components() const override;
     Vector<float> default_decode() const override;
     ColorSpaceFamily const& family() const override { return ColorSpaceFamily::ICCBased; }
@@ -197,7 +201,7 @@ public:
 
     ~LabColorSpace() override = default;
 
-    PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
+    PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
     int number_of_components() const override { return 3; }
     Vector<float> default_decode() const override;
     ColorSpaceFamily const& family() const override { return ColorSpaceFamily::Lab; }
@@ -216,7 +220,7 @@ public:
 
     ~IndexedColorSpace() override = default;
 
-    PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
+    PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
     int number_of_components() const override { return 1; }
     Vector<float> default_decode() const override;
     ColorSpaceFamily const& family() const override { return ColorSpaceFamily::Indexed; }
@@ -235,7 +239,7 @@ public:
 
     ~SeparationColorSpace() override = default;
 
-    PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
+    PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
     int number_of_components() const override { return 1; }
     Vector<float> default_decode() const override;
     ColorSpaceFamily const& family() const override { return ColorSpaceFamily::Separation; }
@@ -248,5 +252,4 @@ private:
     NonnullRefPtr<Function> m_tint_transform;
     Vector<Value> mutable m_tint_output_values;
 };
-
 }

+ 10 - 3
Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp

@@ -48,13 +48,20 @@ void TrueTypeFont::set_font_size(float font_size)
     m_font = m_font->with_size((font_size * POINTS_PER_INCH) / DEFAULT_DPI);
 }
 
-PDFErrorOr<void> TrueTypeFont::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float, u8 char_code, Renderer const& renderer)
+PDFErrorOr<void> TrueTypeFont::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float width, u8 char_code, Renderer const& renderer)
 {
-    auto color = renderer.state().paint_color;
+    auto style = renderer.state().paint_style;
 
     // Account for the reversed font baseline
     auto position = point.translated(0, -m_font->baseline());
-    painter.draw_glyph(position, char_code, *m_font, color);
+    if (style.has<Color>()) {
+        painter.draw_glyph(position, char_code, *m_font, style.get<Color>());
+    } else {
+        // FIXME: Bounding box and sample point look to be pretty wrong
+        style.get<NonnullRefPtr<Gfx::PaintStyle>>()->paint(Gfx::IntRect(position.x(), position.y(), width, 0), [&](auto sample) {
+            painter.draw_glyph(position, char_code, *m_font, sample(Gfx::IntPoint(position.x(), position.y())));
+        });
+    }
     return {};
 }
 

+ 21 - 5
Userland/Libraries/LibPDF/Fonts/Type1Font.cpp

@@ -67,12 +67,19 @@ void Type1Font::set_font_size(float font_size)
 
 PDFErrorOr<void> Type1Font::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float width, u8 char_code, Renderer const& renderer)
 {
-    auto color = renderer.state().paint_color;
+    auto style = renderer.state().paint_style;
 
     if (!m_font_program) {
         // Account for the reversed font baseline
         auto position = point.translated(0, -m_font->baseline());
-        painter.draw_glyph(position, char_code, *m_font, color);
+        // FIXME: Bounding box and sample point look to be pretty wrong
+        if (style.has<Color>()) {
+            painter.draw_glyph(position, char_code, *m_font, style.get<Color>());
+        } else {
+            style.get<NonnullRefPtr<Gfx::PaintStyle>>()->paint(Gfx::IntRect(position.x(), position.y(), width, 0), [&](auto sample) {
+                painter.draw_glyph(position, char_code, *m_font, sample(Gfx::IntPoint(position.x(), position.y())));
+            });
+        }
         return {};
     }
 
@@ -97,9 +104,18 @@ PDFErrorOr<void> Type1Font::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint po
         m_glyph_cache.set(index, bitmap);
     }
 
-    painter.blit_filtered(glyph_position.blit_position, *bitmap, bitmap->rect(), [color](Color pixel) -> Color {
-        return pixel.multiply(color);
-    });
+    if (style.has<Color>()) {
+        painter.blit_filtered(glyph_position.blit_position, *bitmap, bitmap->rect(), [style](Color pixel) -> Color {
+            return pixel.multiply(style.get<Color>());
+        });
+    } else {
+        style.get<NonnullRefPtr<Gfx::PaintStyle>>()->paint(bitmap->physical_rect(), [&](auto sample) {
+            painter.blit_filtered(glyph_position.blit_position, *bitmap, bitmap->rect(), [&](Color pixel) -> Color {
+                // FIXME: Presumably we need to sample at every point in the glyph, not just the top left?
+                return pixel.multiply(sample(glyph_position.blit_position));
+            });
+        });
+    }
     return {};
 }
 }

+ 45 - 17
Userland/Libraries/LibPDF/Renderer.cpp

@@ -311,7 +311,11 @@ void Renderer::end_path_paint()
 RENDERER_HANDLER(path_stroke)
 {
     begin_path_paint();
-    m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_color, state().ctm.x_scale() * state().line_width);
+    if (state().stroke_style.has<NonnullRefPtr<Gfx::PaintStyle>>()) {
+        m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get<NonnullRefPtr<Gfx::PaintStyle>>(), state().ctm.x_scale() * state().line_width);
+    } else {
+        m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get<Color>(), state().ctm.x_scale() * state().line_width);
+    }
     end_path_paint();
     return {};
 }
@@ -327,7 +331,11 @@ RENDERER_HANDLER(path_fill_nonzero)
 {
     begin_path_paint();
     m_current_path.close_all_subpaths();
-    m_anti_aliasing_painter.fill_path(m_current_path, state().paint_color, Gfx::Painter::WindingRule::Nonzero);
+    if (state().paint_style.has<NonnullRefPtr<Gfx::PaintStyle>>()) {
+        m_anti_aliasing_painter.fill_path(m_current_path, state().paint_style.get<NonnullRefPtr<Gfx::PaintStyle>>(), 1.0, Gfx::Painter::WindingRule::Nonzero);
+    } else {
+        m_anti_aliasing_painter.fill_path(m_current_path, state().paint_style.get<Color>(), Gfx::Painter::WindingRule::Nonzero);
+    }
     end_path_paint();
     return {};
 }
@@ -341,20 +349,32 @@ RENDERER_HANDLER(path_fill_evenodd)
 {
     begin_path_paint();
     m_current_path.close_all_subpaths();
-    m_anti_aliasing_painter.fill_path(m_current_path, state().paint_color, Gfx::Painter::WindingRule::EvenOdd);
+    if (state().paint_style.has<NonnullRefPtr<Gfx::PaintStyle>>()) {
+        m_anti_aliasing_painter.fill_path(m_current_path, state().paint_style.get<NonnullRefPtr<Gfx::PaintStyle>>(), 1.0, Gfx::Painter::WindingRule::EvenOdd);
+    } else {
+        m_anti_aliasing_painter.fill_path(m_current_path, state().paint_style.get<Color>(), Gfx::Painter::WindingRule::EvenOdd);
+    }
     end_path_paint();
     return {};
 }
 
 RENDERER_HANDLER(path_fill_stroke_nonzero)
 {
-    m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_color, state().ctm.x_scale() * state().line_width);
+    if (state().stroke_style.has<NonnullRefPtr<Gfx::PaintStyle>>()) {
+        m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get<NonnullRefPtr<Gfx::PaintStyle>>(), state().ctm.x_scale() * state().line_width);
+    } else {
+        m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get<Color>(), state().ctm.x_scale() * state().line_width);
+    }
     return handle_path_fill_nonzero(args);
 }
 
 RENDERER_HANDLER(path_fill_stroke_evenodd)
 {
-    m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_color, state().ctm.x_scale() * state().line_width);
+    if (state().stroke_style.has<NonnullRefPtr<Gfx::PaintStyle>>()) {
+        m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get<NonnullRefPtr<Gfx::PaintStyle>>(), state().ctm.x_scale() * state().line_width);
+    } else {
+        m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get<Color>(), state().ctm.x_scale() * state().line_width);
+    }
     return handle_path_fill_evenodd(args);
 }
 
@@ -590,7 +610,7 @@ RENDERER_HANDLER(set_painting_space)
 
 RENDERER_HANDLER(set_stroking_color)
 {
-    state().stroke_color = TRY(state().stroke_color_space->color(args));
+    state().stroke_style = TRY(state().stroke_color_space->style(args));
     return {};
 }
 
@@ -603,13 +623,13 @@ RENDERER_HANDLER(set_stroking_color_extended)
         return Error::rendering_unsupported_error("Pattern color spaces not yet implemented");
     }
 
-    state().stroke_color = TRY(state().stroke_color_space->color(args));
+    state().stroke_style = TRY(state().stroke_color_space->style(args));
     return {};
 }
 
 RENDERER_HANDLER(set_painting_color)
 {
-    state().paint_color = TRY(state().paint_color_space->color(args));
+    state().paint_style = TRY(state().paint_color_space->style(args));
     return {};
 }
 
@@ -622,49 +642,49 @@ RENDERER_HANDLER(set_painting_color_extended)
         return Error::rendering_unsupported_error("Pattern color spaces not yet implemented");
     }
 
-    state().paint_color = TRY(state().paint_color_space->color(args));
+    state().paint_style = TRY(state().paint_color_space->style(args));
     return {};
 }
 
 RENDERER_HANDLER(set_stroking_color_and_space_to_gray)
 {
     state().stroke_color_space = DeviceGrayColorSpace::the();
-    state().stroke_color = TRY(state().stroke_color_space->color(args));
+    state().stroke_style = TRY(state().stroke_color_space->style(args));
     return {};
 }
 
 RENDERER_HANDLER(set_painting_color_and_space_to_gray)
 {
     state().paint_color_space = DeviceGrayColorSpace::the();
-    state().paint_color = TRY(state().paint_color_space->color(args));
+    state().paint_style = TRY(state().paint_color_space->style(args));
     return {};
 }
 
 RENDERER_HANDLER(set_stroking_color_and_space_to_rgb)
 {
     state().stroke_color_space = DeviceRGBColorSpace::the();
-    state().stroke_color = TRY(state().stroke_color_space->color(args));
+    state().stroke_style = TRY(state().stroke_color_space->style(args));
     return {};
 }
 
 RENDERER_HANDLER(set_painting_color_and_space_to_rgb)
 {
     state().paint_color_space = DeviceRGBColorSpace::the();
-    state().paint_color = TRY(state().paint_color_space->color(args));
+    state().paint_style = TRY(state().paint_color_space->style(args));
     return {};
 }
 
 RENDERER_HANDLER(set_stroking_color_and_space_to_cmyk)
 {
     state().stroke_color_space = DeviceCMYKColorSpace::the();
-    state().stroke_color = TRY(state().stroke_color_space->color(args));
+    state().stroke_style = TRY(state().stroke_color_space->style(args));
     return {};
 }
 
 RENDERER_HANDLER(set_painting_color_and_space_to_cmyk)
 {
     state().paint_color_space = DeviceCMYKColorSpace::the();
-    state().paint_color = TRY(state().paint_color_space->color(args));
+    state().paint_style = TRY(state().paint_color_space->style(args));
     return {};
 }
 
@@ -956,8 +976,16 @@ PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> Renderer::load_image(NonnullRefPtr<Stream
             sample = sample.slice(bytes_per_component);
             component_values[i] = Value { component_value_decoders[i].interpolate(component[0]) };
         }
-        auto color = TRY(color_space->color(component_values));
-        bitmap->set_pixel(x, y, color);
+        auto color = TRY(color_space->style(component_values));
+        if (color.has<Color>()) {
+            auto c = color.get<Color>();
+            bitmap->set_pixel(x, y, c);
+        } else {
+            auto paint_style = color.get<NonnullRefPtr<Gfx::PaintStyle>>();
+            paint_style->paint(bitmap->rect(), [&](auto sample) {
+                bitmap->set_pixel(x, y, sample(Gfx::IntPoint(x, y)));
+            });
+        }
         ++x;
         if (x == width) {
             x = 0;

+ 12 - 4
Userland/Libraries/LibPDF/Renderer.h

@@ -74,8 +74,8 @@ struct GraphicsState {
     ClippingPaths clipping_paths;
     RefPtr<ColorSpace> stroke_color_space { DeviceGrayColorSpace::the() };
     RefPtr<ColorSpace> paint_color_space { DeviceGrayColorSpace::the() };
-    Gfx::Color stroke_color { Gfx::Color::NamedColor::Black };
-    Gfx::Color paint_color { Gfx::Color::NamedColor::Black };
+    ColorOrStyle stroke_style { Color::Black };
+    ColorOrStyle paint_style { Color::Black };
     DeprecatedString color_rendering_intent { "RelativeColorimetric"sv };
     float flatness_tolerance { 0.0f };
     float line_width { 1.0f };
@@ -286,8 +286,16 @@ struct Formatter<PDF::GraphicsState> : Formatter<StringView> {
         StringBuilder builder;
         builder.append("GraphicsState {\n"sv);
         builder.appendff("  ctm={}\n", state.ctm);
-        builder.appendff("  stroke_color={}\n", state.stroke_color);
-        builder.appendff("  paint_color={}\n", state.paint_color);
+        if (state.stroke_style.has<Color>()) {
+            builder.appendff("  stroke_style={}\n", state.stroke_style.get<Color>());
+        } else {
+            builder.appendff("  stroke_style={}\n", state.stroke_style.get<NonnullRefPtr<Gfx::PaintStyle>>());
+        }
+        if (state.paint_style.has<Color>()) {
+            builder.appendff("  paint_style={}\n", state.paint_style.get<Color>());
+        } else {
+            builder.appendff("  paint_style={}\n", state.paint_style.get<NonnullRefPtr<Gfx::PaintStyle>>());
+        }
         builder.appendff("  color_rendering_intent={}\n", state.color_rendering_intent);
         builder.appendff("  flatness_tolerance={}\n", state.flatness_tolerance);
         builder.appendff("  line_width={}\n", state.line_width);