From 0158ec1e51f0acc14328dbe579280cd0f77b0e1b Mon Sep 17 00:00:00 2001 From: Tony Marklove Date: Mon, 16 Sep 2024 15:24:06 +0100 Subject: [PATCH] Inherit gradient attributes from the linked/parent element --- lib/prawn/svg/elements/gradient.rb | 47 +++++++++++++----------- spec/prawn/svg/elements/gradient_spec.rb | 41 +++++++++++++++++++-- 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/lib/prawn/svg/elements/gradient.rb b/lib/prawn/svg/elements/gradient.rb index 2d580ec..89c478a 100644 --- a/lib/prawn/svg/elements/gradient.rb +++ b/lib/prawn/svg/elements/gradient.rb @@ -12,7 +12,6 @@ def parse raise SkipElementQuietly if attributes['id'].nil? @parent_gradient = document.gradients[href_attribute[1..]] if href_attribute && href_attribute[0] == '#' - assert_compatible_prawn_version load_gradient_configuration load_coordinates @@ -34,6 +33,10 @@ def gradient_arguments(element) arguments&.merge(base_arguments) end + def derive_attribute(name) + attributes[name] || parent_gradient&.derive_attribute(name) + end + private def specific_gradient_arguments(element) @@ -86,13 +89,13 @@ def assert_compatible_prawn_version end def load_gradient_configuration - @units = attributes['gradientUnits'] == 'userSpaceOnUse' ? :user_space : :bounding_box + @units = derive_attribute('gradientUnits') == 'userSpaceOnUse' ? :user_space : :bounding_box - if (transform = attributes['gradientTransform']) + if (transform = derive_attribute('gradientTransform')) @transform_matrix = parse_transform_attribute(transform) end - if (spread_method = attributes['spreadMethod']) && spread_method != 'pad' + if (spread_method = derive_attribute('spreadMethod')) && spread_method != 'pad' warnings << "prawn-svg only currently supports the 'pad' spreadMethod attribute value" end end @@ -100,30 +103,30 @@ def load_gradient_configuration def load_coordinates case [type, units] when [:linear, :bounding_box] - @x1 = parse_zero_to_one(attributes['x1'], 0) - @y1 = parse_zero_to_one(attributes['y1'], 0) - @x2 = parse_zero_to_one(attributes['x2'], 1) - @y2 = parse_zero_to_one(attributes['y2'], 0) + @x1 = parse_zero_to_one(derive_attribute('x1'), 0) + @y1 = parse_zero_to_one(derive_attribute('y1'), 0) + @x2 = parse_zero_to_one(derive_attribute('x2'), 1) + @y2 = parse_zero_to_one(derive_attribute('y2'), 0) when [:linear, :user_space] - @x1 = x(attributes['x1']) - @y1 = y(attributes['y1']) - @x2 = x(attributes['x2']) - @y2 = y(attributes['y2']) + @x1 = x(derive_attribute('x1')) + @y1 = y(derive_attribute('y1')) + @x2 = x(derive_attribute('x2')) + @y2 = y(derive_attribute('y2')) when [:radial, :bounding_box] - @cx = parse_zero_to_one(attributes['cx'], 0.5) - @cy = parse_zero_to_one(attributes['cy'], 0.5) - @fx = parse_zero_to_one(attributes['fx'], cx) - @fy = parse_zero_to_one(attributes['fy'], cy) - @radius = parse_zero_to_one(attributes['r'], 0.5) + @cx = parse_zero_to_one(derive_attribute('cx'), 0.5) + @cy = parse_zero_to_one(derive_attribute('cy'), 0.5) + @fx = parse_zero_to_one(derive_attribute('fx'), cx) + @fy = parse_zero_to_one(derive_attribute('fy'), cy) + @radius = parse_zero_to_one(derive_attribute('r'), 0.5) when [:radial, :user_space] - @cx = x(attributes['cx'] || '50%') - @cy = y(attributes['cy'] || '50%') - @fx = x(attributes['fx'] || attributes['cx']) - @fy = y(attributes['fy'] || attributes['cy']) - @radius = pixels(attributes['r'] || '50%') + @cx = x(derive_attribute('cx') || '50%') + @cy = y(derive_attribute('cy') || '50%') + @fx = x(derive_attribute('fx') || derive_attribute('cx')) + @fy = y(derive_attribute('fy') || derive_attribute('cy')) + @radius = pixels(derive_attribute('r') || '50%') else raise 'unexpected type/unit system' diff --git a/spec/prawn/svg/elements/gradient_spec.rb b/spec/prawn/svg/elements/gradient_spec.rb index 0bec82d..f3cf34d 100644 --- a/spec/prawn/svg/elements/gradient_spec.rb +++ b/spec/prawn/svg/elements/gradient_spec.rb @@ -2,11 +2,11 @@ describe Prawn::SVG::Elements::Gradient do let(:document) { Prawn::SVG::Document.new(svg, [800, 600], { width: 800, height: 600 }) } - let(:element) { Prawn::SVG::Elements::Gradient.new(document, document.root, [], fake_state) } + let(:root_element) { Prawn::SVG::Elements::Root.new(document, document.root, []) } + let(:element) { document.gradients['flag'] } before do - allow(element).to receive(:assert_compatible_prawn_version) - element.process + root_element.process end describe 'object bounding box with linear gradient' do @@ -133,4 +133,39 @@ ) end end + + context 'when a gradient is linked to another' do + let(:svg) do + <<-SVG + + + + + + + + + + + SVG + end + + it 'correctly inherits the attributes from the parent element' do + arguments = document.gradients['flag-2'].gradient_arguments(double) + expect(arguments).to eq( + from: [150.0, 100.0], + to: [220.0, 0.0], + stops: [[0, 'ff0000'], [1, '0000ff']], + apply_transformations: true + ) + + arguments = document.gradients['flag-3'].gradient_arguments(double) + expect(arguments).to eq( + from: [170.0, 100.0], + to: [220.0, 0.0], + stops: [[0, 'ff0000'], [1, '0000ff']], + apply_transformations: true + ) + end + end end