Skip to content

Commit

Permalink
Inherit gradient attributes from the linked/parent element
Browse files Browse the repository at this point in the history
  • Loading branch information
tonymarklove committed Sep 16, 2024
1 parent ba87994 commit 0158ec1
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 25 deletions.
47 changes: 25 additions & 22 deletions lib/prawn/svg/elements/gradient.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -86,44 +89,44 @@ 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

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'
Expand Down
41 changes: 38 additions & 3 deletions spec/prawn/svg/elements/gradient_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -133,4 +133,39 @@
)
end
end

context 'when a gradient is linked to another' do
let(:svg) do
<<-SVG
<svg>
<linearGradient id="flag" gradientUnits="userSpaceOnUse" x1="100" y1="500" x2="200" y2="600">
<stop offset="0" stop-color="red"/>
<stop offset="1" stop-color="blue"/>
</linearGradient>
<linearGradient id="flag-2" href="#flag" x1="150" x2="220" />
<linearGradient id="flag-3" href="#flag-2" x1="170" />
</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

0 comments on commit 0158ec1

Please sign in to comment.