Skip to content

Commit 7d61a1a

Browse files
authored
Merge pull request #29 from blocknotes/adjust-font-spacing
Adjust spacing
2 parents 8d894ac + ef34fdb commit 7d61a1a

13 files changed

Lines changed: 57 additions & 21 deletions

File tree

examples/headings.pdf

0 Bytes
Binary file not shown.

examples/misc_elements.pdf

62 Bytes
Binary file not shown.

examples/random_content.pdf

172 Bytes
Binary file not shown.

examples/styles.pdf

0 Bytes
Binary file not shown.

lib/prawn-html.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

33
module PrawnHtml
4+
ADJUST_LEADING = { nil => 0.18, 'Courier' => -0.07, 'Helvetica' => -0.17, 'Times-Roman' => 0.03 }.freeze
45
PX = 0.6 # conversion constant for pixel sixes
56

67
COLORS = {

lib/prawn_html/context.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,17 @@ def remove_last
6767
last.on_context_remove(self) if last.respond_to?(:on_context_remove)
6868
@merged_styles = nil
6969
@last_text_node = false
70-
@previous_tag = last.tag
70+
@previous_tag = last
7171
pop
7272
end
7373

74+
# White space is equal to 'pre'?
75+
#
76+
# @return [boolean] white space property of the last element is equal to 'pre'
77+
def white_space_pre?
78+
last && last.styles[:white_space] == :pre
79+
end
80+
7481
private
7582

7683
def evaluate_element_styles(element, res)

lib/prawn_html/document_renderer.rb

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ def initialize(pdf)
1212
@buffer = []
1313
@context = Context.new
1414
@last_margin = 0
15+
@last_text = ''
16+
@last_tag_open = false
1517
@pdf = pdf
1618
end
1719

@@ -22,6 +24,8 @@ def on_tag_close(element)
2224
render_if_needed(element)
2325
apply_tag_close_styles(element)
2426
context.remove_last
27+
@last_tag_open = false
28+
@last_text = ''
2529
end
2630

2731
# On tag open callback
@@ -38,6 +42,7 @@ def on_tag_open(tag_name, attributes:, element_styles: '')
3842
options = { width: pdf.page_width, height: pdf.page_height }
3943
tag_class.new(tag_name, attributes: attributes, options: options).tap do |element|
4044
setup_element(element, element_styles: element_styles)
45+
@last_tag_open = true
4146
end
4247
end
4348

@@ -47,9 +52,10 @@ def on_tag_open(tag_name, attributes:, element_styles: '')
4752
#
4853
# @return [NilClass] nil value (=> no element)
4954
def on_text_node(content)
50-
return if content.match?(/\A\s*\Z/)
55+
return if context.previous_tag&.block? && content.match?(/\A\s*\Z/)
5156

52-
buffer << context.merged_styles.merge(text: prepare_text(content))
57+
text = prepare_text(content)
58+
buffer << context.merged_styles.merge(text: text) unless text.empty?
5359
context.last_text_node = true
5460
nil
5561
end
@@ -70,17 +76,13 @@ def render
7076
attr_reader :buffer, :context, :last_margin, :pdf
7177

7278
def setup_element(element, element_styles:)
73-
add_space_if_needed unless render_if_needed(element)
79+
render_if_needed(element)
7480
context.add(element)
7581
element.process_styles(element_styles: element_styles)
7682
apply_tag_open_styles(element)
7783
element.custom_render(pdf, context) if element.respond_to?(:custom_render)
7884
end
7985

80-
def add_space_if_needed
81-
buffer << SPACE if buffer.any? && !context.last_text_node && ![NEW_LINE, SPACE].include?(buffer.last)
82-
end
83-
8486
def render_if_needed(element)
8587
render_needed = element&.block? && buffer.any? && buffer.last != NEW_LINE
8688
return false unless render_needed
@@ -104,10 +106,12 @@ def apply_tag_open_styles(element)
104106
end
105107

106108
def prepare_text(content)
107-
white_space_pre = context.last && context.last.styles[:white_space] == :pre
108-
text = ::Oga::HTML::Entities.decode(context.before_content)
109-
text += white_space_pre ? content : content.gsub(/\A\s*\n\s*|\s*\n\s*\Z/, '').delete("\n").squeeze(' ')
110-
text
109+
text = context.before_content ? ::Oga::HTML::Entities.decode(context.before_content) : ''
110+
return (@last_text = text + content) if context.white_space_pre?
111+
112+
content = content.lstrip if @last_text[-1] == ' ' || @last_tag_open
113+
text += content.tr("\n", ' ').squeeze(' ')
114+
@last_text = text
111115
end
112116

113117
def output_content(buffer, block_styles)
@@ -129,7 +133,10 @@ def apply_callbacks(buffer)
129133
def adjust_leading(buffer, leading)
130134
return leading if leading
131135

132-
(buffer.map { |item| item[:size] || Context::DEFAULT_STYLES[:size] }.max * 0.055).round(4)
136+
leadings = buffer.map do |item|
137+
(item[:size] || Context::DEFAULT_STYLES[:size]) * (ADJUST_LEADING[item[:font]] || ADJUST_LEADING[nil])
138+
end
139+
leadings.max.round(4)
133140
end
134141

135142
def bounds(buffer, options, block_styles)

lib/prawn_html/tags/br.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def block?
1212
end
1313

1414
def custom_render(pdf, context)
15-
return if context.last_text_node || context.previous_tag != :br
15+
return if context.last_text_node || !context.previous_tag.is_a?(Br)
1616

1717
pdf.advance_cursor(BR_SPACING)
1818
end

spec/support/test_utils.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
module TestUtils
44
extend self
55

6-
def adjust_leading(size = PrawnHtml::Context::DEFAULT_STYLES[:size])
7-
(size * 0.055).round(4)
6+
def adjust_leading(size = PrawnHtml::Context::DEFAULT_STYLES[:size], font = nil)
7+
(size * PrawnHtml::ADJUST_LEADING[font]).round(4)
88
end
99

1010
def default_font

spec/units/prawn_html/context_spec.rb

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def on_context_remove(context)
110110
it 'removes the last element from the context', :aggregate_failures do
111111
expect { remove_last }.to(
112112
change(context, :size).from(1).to(0).and(
113-
change(context, :previous_tag).from(nil).to(:some_tag)
113+
change(context, :previous_tag).from(nil).to(tag)
114114
)
115115
)
116116
expect(tag).to have_received(:on_context_remove)
@@ -159,4 +159,22 @@ def update_styles(res)
159159
end
160160
end
161161
end
162+
163+
describe '#white_space_pre?' do
164+
subject(:white_space_pre?) { context.white_space_pre? }
165+
166+
before do
167+
context << instance_double(PrawnHtml::Tag, styles: {})
168+
end
169+
170+
it { is_expected.to be_falsey }
171+
172+
context 'when the last element has white-space property set to pre' do
173+
before do
174+
context << instance_double(PrawnHtml::Tag, styles: { white_space: :pre })
175+
end
176+
177+
it { is_expected.to be_truthy }
178+
end
179+
end
162180
end

0 commit comments

Comments
 (0)