Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 5 additions & 102 deletions Userland/Libraries/LibPDF/ColorSpace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ PDFErrorOr<NonnullRefPtr<ColorSpace>> ColorSpace::create(Document* document, Non
return Error { Error::Type::MalformedPDF, "Color space must be name or array" };
}

PDFErrorOr<NonnullRefPtr<ColorSpace>> ColorSpace::create(DeprecatedFlyString const& name, Renderer& renderer)
PDFErrorOr<NonnullRefPtr<ColorSpace>> ColorSpace::create(DeprecatedFlyString const& name, Renderer&)
{
// Simple color spaces with no parameters, which can be specified directly
if (name == CommonNames::DeviceGray)
Expand All @@ -55,7 +55,7 @@ PDFErrorOr<NonnullRefPtr<ColorSpace>> ColorSpace::create(DeprecatedFlyString con
if (name == CommonNames::DeviceCMYK)
return DeviceCMYKColorSpace::the();
if (name == CommonNames::Pattern)
return PatternColorSpace::create(renderer);
return Error::rendering_unsupported_error("Pattern color spaces not yet implemented");
VERIFY_NOT_REACHED();
}

Expand Down Expand Up @@ -86,6 +86,9 @@ PDFErrorOr<NonnullRefPtr<ColorSpace>> ColorSpace::create(Document* document, Non
if (color_space_name == CommonNames::Lab)
return TRY(LabColorSpace::create(document, move(parameters)));

if (color_space_name == CommonNames::Pattern)
return Error::rendering_unsupported_error("Pattern color spaces not yet implemented");

if (color_space_name == CommonNames::Separation)
return TRY(SeparationColorSpace::create(document, move(parameters), renderer));

Expand Down Expand Up @@ -770,104 +773,4 @@ Vector<float> SeparationColorSpace::default_decode() const
{
return { 0.0f, 1.0f };
}
NonnullRefPtr<PatternColorSpace> PatternColorSpace::create(Renderer& renderer)
{
return adopt_ref(*new PatternColorSpace(renderer));
}

PDFErrorOr<ColorOrStyle> PatternColorSpace::style(ReadonlySpan<Value> arguments) const
{
VERIFY(arguments.size() >= 1);

auto resources = m_renderer.m_page.resources;

auto pattern_resource = resources->get_value(CommonNames::Pattern);
auto doc_pattern_dict = pattern_resource.get<NonnullRefPtr<Object>>()->cast<DictObject>();

auto const& pattern_name = arguments.last().get<NonnullRefPtr<Object>>()->cast<NameObject>()->name();
if (!doc_pattern_dict->contains(pattern_name))
return Error::malformed_error("Pattern dictionary does not contain pattern {}", pattern_name);

auto const pattern = TRY(m_renderer.m_document->resolve_to<StreamObject>(doc_pattern_dict->get_value(pattern_name)));

auto const type = pattern->dict()->get(CommonNames::Type)->get<NonnullRefPtr<Object>>()->cast<NameObject>();
if (type->name() != CommonNames::Pattern)
return Error::rendering_unsupported_error("Unsupported pattern type {}", type->name());

auto const pattern_type = pattern->dict()->get(CommonNames::PatternType)->get_u16();
if (pattern_type != 1)
return Error::rendering_unsupported_error("Unsupported pattern type {}", pattern_type);

auto const pattern_paint_type = pattern->dict()->get("PaintType")->get_u16();
if (pattern_paint_type != 1)
return Error::rendering_unsupported_error("Unsupported pattern paint type {}", pattern_paint_type);

Vector<Value> pattern_matrix;
if (pattern->dict()->contains(CommonNames::Matrix)) {
pattern_matrix = pattern->dict()->get_array(m_renderer.m_document, CommonNames::Matrix).value()->elements();
} else {
pattern_matrix = Vector { Value { 1 }, Value { 0 }, Value { 0 }, Value { 1 }, Value { 0 }, Value { 0 } };
}

auto pattern_bounding_box = pattern->dict()->get_array(m_renderer.m_document, "BBox").value()->elements();
auto pattern_transform = Gfx::AffineTransform(
pattern_matrix[0].to_float(),
pattern_matrix[1].to_float(),
pattern_matrix[2].to_float(),
pattern_matrix[3].to_float(),
pattern_matrix[4].to_float(),
pattern_matrix[5].to_float());

// To get the device space size for the bitmap, apply the pattern transform to the pattern space bounding box, and then apply the initial ctm.
// NB: the pattern pattern_matrix maps pattern space to the default (initial) coordinate space of the page. (i.e cannot be updated via cm).

auto initial_ctm = Gfx::AffineTransform(m_renderer.m_graphics_state_stack.first().ctm);
initial_ctm.set_translation(0, 0);
initial_ctm.set_scale(initial_ctm.x_scale(), initial_ctm.y_scale());

auto pattern_space_lower_left = Gfx::FloatPoint { pattern_bounding_box[0].to_int(), pattern_bounding_box[1].to_int() };
auto pattern_space_upper_right = Gfx::FloatPoint { pattern_bounding_box[2].to_int(), pattern_bounding_box[3].to_int() };

auto device_space_lower_left = initial_ctm.map(pattern_transform.map(pattern_space_lower_left));
auto device_space_upper_right = initial_ctm.map(pattern_transform.map(pattern_space_upper_right));

auto bitmap_width = (int)device_space_upper_right.x() - (int)device_space_lower_left.x();
auto bitmap_height = (int)device_space_upper_right.y() - (int)device_space_lower_left.y();

auto pattern_cell = TRY(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, { bitmap_width, bitmap_height }));
auto page = Page(m_renderer.m_page);
page.media_box = Rectangle {
pattern_space_lower_left.x(), pattern_space_lower_left.y(),
pattern_space_upper_right.x(), pattern_space_upper_right.y()
};
page.crop_box = page.media_box;

auto pattern_renderer = Renderer(m_renderer.m_document, page, pattern_cell, {}, m_renderer.m_rendering_preferences);

auto operators = TRY(Parser::parse_operators(m_renderer.m_document, pattern->bytes()));
for (auto& op : operators)
TRY(pattern_renderer.handle_operator(op, resources));

auto x_steps = pattern->dict()->get("XStep").value_or(bitmap_width).to_int();
auto y_steps = pattern->dict()->get("YStep").value_or(bitmap_height).to_int();

auto device_space_steps = initial_ctm.map(pattern_transform.map(Gfx::IntPoint { x_steps, y_steps }));

NonnullRefPtr<Gfx::PaintStyle> style = MUST(Gfx::RepeatingBitmapPaintStyle::create(
*pattern_cell,
device_space_steps,
{}));

return style;
}
int PatternColorSpace::number_of_components() const
{
// Not permitted
VERIFY_NOT_REACHED();
}
Vector<float> PatternColorSpace::default_decode() const
{
// Not permitted
VERIFY_NOT_REACHED();
}
}
20 changes: 0 additions & 20 deletions Userland/Libraries/LibPDF/ColorSpace.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,24 +252,4 @@ class SeparationColorSpace final : public ColorSpace {
NonnullRefPtr<Function> m_tint_transform;
Vector<Value> mutable m_tint_output_values;
};

class PatternColorSpace final : public ColorSpace {
public:
static NonnullRefPtr<PatternColorSpace> create(Renderer& renderer);
~PatternColorSpace() override = default;

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::Pattern; }

private:
PatternColorSpace(Renderer& renderer)
: m_renderer(renderer)
{
}

Renderer& m_renderer;
};

}
2 changes: 0 additions & 2 deletions Userland/Libraries/LibPDF/CommonNames.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,8 @@
X(Outlines) \
X(P) \
X(Pages) \
X(PaintType) \
X(Parent) \
X(Pattern) \
X(PatternType) \
X(Perms) \
X(Predictor) \
X(Prev) \
Expand Down
29 changes: 15 additions & 14 deletions Userland/Libraries/LibPDF/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,12 +293,6 @@ RENDERER_HANDLER(path_append_rect)

void Renderer::begin_path_paint()
{
if (state().paint_style.has<NonnullRefPtr<Gfx::PaintStyle>>()) {
VERIFY(!m_original_paint_style);
m_original_paint_style = state().paint_style.get<NonnullRefPtr<Gfx::PaintStyle>>();
auto translation = Gfx::AffineTransform().translate(m_current_path.bounding_box().x(), m_current_path.bounding_box().y());
state().paint_style = { MUST(Gfx::OffsetPaintStyle::create(state().paint_style.get<NonnullRefPtr<Gfx::PaintStyle>>(), translation)) };
}
auto bounding_box = state().clipping_paths.current.bounding_box();
m_painter.clear_clip_rect();
if (m_rendering_preferences.show_clipping_paths) {
Expand All @@ -312,11 +306,6 @@ void Renderer::end_path_paint()
m_current_path.clear();
m_painter.clear_clip_rect();
state().clipping_paths.current = state().clipping_paths.next;

if (m_original_paint_style) {
state().paint_style = m_original_paint_style.release_nonnull();
m_original_paint_style = nullptr;
}
}

RENDERER_HANDLER(path_stroke)
Expand Down Expand Up @@ -627,8 +616,14 @@ RENDERER_HANDLER(set_stroking_color)

RENDERER_HANDLER(set_stroking_color_extended)
{
// FIXME: Pattern color spaces might need extra resources
state().paint_style = TRY(state().paint_color_space->style(args));
// FIXME: Handle Pattern color spaces
auto last_arg = args.last();
if (last_arg.has<NonnullRefPtr<Object>>() && last_arg.get<NonnullRefPtr<Object>>()->is<NameObject>()) {
dbgln("pattern space {}", last_arg.get<NonnullRefPtr<Object>>()->cast<NameObject>()->name());
return Error::rendering_unsupported_error("Pattern color spaces not yet implemented");
}

state().stroke_style = TRY(state().stroke_color_space->style(args));
return {};
}

Expand All @@ -640,7 +635,13 @@ RENDERER_HANDLER(set_painting_color)

RENDERER_HANDLER(set_painting_color_extended)
{
// FIXME: Pattern color spaces might need extra resources
// FIXME: Handle Pattern color spaces
auto last_arg = args.last();
if (last_arg.has<NonnullRefPtr<Object>>() && last_arg.get<NonnullRefPtr<Object>>()->is<NameObject>()) {
dbgln("pattern space {}", last_arg.get<NonnullRefPtr<Object>>()->cast<NameObject>()->name());
return Error::rendering_unsupported_error("Pattern color spaces not yet implemented");
}

state().paint_style = TRY(state().paint_color_space->style(args));
return {};
}
Expand Down
4 changes: 0 additions & 4 deletions Userland/Libraries/LibPDF/Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,6 @@ struct RenderingPreferences {
};

class Renderer {
friend class PatternColorSpace;

public:
static PDFErrorsOr<void> render(Document&, Page const&, RefPtr<Gfx::Bitmap>, Color background_color, RenderingPreferences preferences);

Expand Down Expand Up @@ -173,8 +171,6 @@ class Renderer {
Gfx::AffineTransform mutable m_text_rendering_matrix;

HashMap<FontCacheKey, NonnullRefPtr<PDFFont>> m_font_cache;
// Used to offset the PaintStyle's origin when rendering a pattern.
RefPtr<Gfx::PaintStyle> m_original_paint_style;
};

}
Expand Down