prawn 2.0.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/GPLv2 +20 -21
- data/Gemfile +3 -9
- data/Rakefile +20 -23
- data/lib/prawn.rb +37 -49
- data/lib/prawn/document.rb +181 -133
- data/lib/prawn/document/bounding_box.rb +41 -29
- data/lib/prawn/document/column_box.rb +7 -7
- data/lib/prawn/document/internals.rb +18 -8
- data/lib/prawn/document/span.rb +21 -16
- data/lib/prawn/encoding.rb +69 -68
- data/lib/prawn/errors.rb +12 -7
- data/lib/prawn/font.rb +115 -69
- data/lib/prawn/font_metric_cache.rb +14 -8
- data/lib/prawn/{font → fonts}/afm.rb +102 -68
- data/lib/prawn/{font → fonts}/dfont.rb +5 -11
- data/lib/prawn/fonts/otf.rb +11 -0
- data/lib/prawn/fonts/ttc.rb +36 -0
- data/lib/prawn/{font → fonts}/ttf.rb +87 -68
- data/lib/prawn/graphics.rb +120 -80
- data/lib/prawn/graphics/blend_mode.rb +65 -0
- data/lib/prawn/graphics/cap_style.rb +3 -3
- data/lib/prawn/graphics/color.rb +27 -25
- data/lib/prawn/graphics/dash.rb +23 -11
- data/lib/prawn/graphics/join_style.rb +9 -3
- data/lib/prawn/graphics/patterns.rb +197 -67
- data/lib/prawn/graphics/transformation.rb +17 -8
- data/lib/prawn/graphics/transparency.rb +17 -13
- data/lib/prawn/grid.rb +48 -47
- data/lib/prawn/image_handler.rb +5 -5
- data/lib/prawn/images.rb +39 -30
- data/lib/prawn/images/image.rb +2 -1
- data/lib/prawn/images/jpg.rb +28 -22
- data/lib/prawn/images/png.rb +107 -66
- data/lib/prawn/measurement_extensions.rb +10 -9
- data/lib/prawn/measurements.rb +19 -15
- data/lib/prawn/outline.rb +97 -77
- data/lib/prawn/repeater.rb +14 -10
- data/lib/prawn/security.rb +81 -61
- data/lib/prawn/security/arcfour.rb +2 -2
- data/lib/prawn/soft_mask.rb +26 -26
- data/lib/prawn/stamp.rb +20 -13
- data/lib/prawn/text.rb +68 -52
- data/lib/prawn/text/box.rb +11 -8
- data/lib/prawn/text/formatted.rb +5 -5
- data/lib/prawn/text/formatted/arranger.rb +78 -49
- data/lib/prawn/text/formatted/box.rb +134 -100
- data/lib/prawn/text/formatted/fragment.rb +11 -14
- data/lib/prawn/text/formatted/line_wrap.rb +121 -63
- data/lib/prawn/text/formatted/parser.rb +139 -117
- data/lib/prawn/text/formatted/wrap.rb +43 -31
- data/lib/prawn/transformation_stack.rb +44 -0
- data/lib/prawn/utilities.rb +7 -22
- data/lib/prawn/version.rb +2 -2
- data/lib/prawn/view.rb +17 -7
- data/manual/basic_concepts/adding_pages.rb +6 -7
- data/manual/basic_concepts/basic_concepts.rb +31 -22
- data/manual/basic_concepts/creation.rb +10 -11
- data/manual/basic_concepts/cursor.rb +4 -5
- data/manual/basic_concepts/measurement.rb +6 -7
- data/manual/basic_concepts/origin.rb +5 -6
- data/manual/basic_concepts/other_cursor_helpers.rb +11 -12
- data/manual/basic_concepts/view.rb +22 -16
- data/manual/bounding_box/bounding_box.rb +29 -24
- data/manual/bounding_box/bounds.rb +11 -12
- data/manual/bounding_box/canvas.rb +4 -5
- data/manual/bounding_box/creation.rb +6 -7
- data/manual/bounding_box/indentation.rb +14 -15
- data/manual/bounding_box/nesting.rb +24 -17
- data/manual/bounding_box/russian_boxes.rb +14 -13
- data/manual/bounding_box/stretchy.rb +12 -13
- data/manual/contents.rb +28 -22
- data/manual/cover.rb +33 -28
- data/manual/document_and_page_options/background.rb +11 -13
- data/manual/document_and_page_options/document_and_page_options.rb +25 -20
- data/manual/document_and_page_options/metadata.rb +18 -16
- data/manual/document_and_page_options/page_margins.rb +18 -20
- data/manual/document_and_page_options/page_size.rb +13 -12
- data/manual/document_and_page_options/print_scaling.rb +17 -15
- data/manual/example_helper.rb +5 -4
- data/manual/graphics/blend_mode.rb +52 -0
- data/manual/graphics/circle_and_ellipse.rb +4 -5
- data/manual/graphics/color.rb +7 -9
- data/manual/graphics/common_lines.rb +7 -8
- data/manual/graphics/fill_and_stroke.rb +4 -5
- data/manual/graphics/fill_rules.rb +9 -10
- data/manual/graphics/gradients.rb +27 -21
- data/manual/graphics/graphics.rb +48 -39
- data/manual/graphics/helper.rb +12 -9
- data/manual/graphics/line_width.rb +8 -7
- data/manual/graphics/lines_and_curves.rb +7 -8
- data/manual/graphics/polygon.rb +6 -8
- data/manual/graphics/rectangle.rb +4 -5
- data/manual/graphics/rotate.rb +6 -7
- data/manual/graphics/scale.rb +14 -15
- data/manual/graphics/soft_masks.rb +4 -5
- data/manual/graphics/stroke_cap.rb +6 -7
- data/manual/graphics/stroke_dash.rb +11 -12
- data/manual/graphics/stroke_join.rb +5 -6
- data/manual/graphics/translate.rb +9 -10
- data/manual/graphics/transparency.rb +7 -8
- data/manual/how_to_read_this_manual.rb +6 -6
- data/manual/images/absolute_position.rb +6 -7
- data/manual/images/fit.rb +7 -8
- data/manual/images/horizontal.rb +9 -10
- data/manual/images/images.rb +28 -24
- data/manual/images/plain_image.rb +5 -6
- data/manual/images/scale.rb +9 -10
- data/manual/images/vertical.rb +13 -14
- data/manual/images/width_and_height.rb +10 -11
- data/manual/layout/boxes.rb +5 -6
- data/manual/layout/content.rb +7 -8
- data/manual/layout/layout.rb +18 -16
- data/manual/layout/simple_grid.rb +6 -7
- data/manual/outline/add_subsection_to.rb +20 -21
- data/manual/outline/insert_section_after.rb +15 -16
- data/manual/outline/outline.rb +21 -17
- data/manual/outline/sections_and_pages.rb +17 -18
- data/manual/repeatable_content/alternate_page_numbering.rb +21 -17
- data/manual/repeatable_content/page_numbering.rb +17 -16
- data/manual/repeatable_content/repeatable_content.rb +25 -19
- data/manual/repeatable_content/repeater.rb +14 -15
- data/manual/repeatable_content/stamp.rb +14 -15
- data/manual/security/encryption.rb +9 -10
- data/manual/security/permissions.rb +19 -14
- data/manual/security/security.rb +19 -16
- data/manual/table.rb +3 -3
- data/manual/text/alignment.rb +16 -17
- data/manual/text/color.rb +12 -11
- data/manual/text/column_box.rb +9 -10
- data/manual/text/fallback_fonts.rb +25 -21
- data/manual/text/font.rb +11 -12
- data/manual/text/font_size.rb +13 -14
- data/manual/text/font_style.rb +7 -8
- data/manual/text/formatted_callbacks.rb +25 -21
- data/manual/text/formatted_text.rb +33 -25
- data/manual/text/free_flowing_text.rb +20 -21
- data/manual/text/inline.rb +18 -19
- data/manual/text/kerning_and_character_spacing.rb +14 -15
- data/manual/text/leading.rb +7 -8
- data/manual/text/line_wrapping.rb +37 -18
- data/manual/text/paragraph_indentation.rb +13 -14
- data/manual/text/positioned_text.rb +15 -16
- data/manual/text/registering_families.rb +20 -21
- data/manual/text/rendering_and_color.rb +9 -10
- data/manual/text/right_to_left_text.rb +26 -19
- data/manual/text/rotation.rb +28 -23
- data/manual/text/single_usage.rb +8 -9
- data/manual/text/text.rb +57 -52
- data/manual/text/text_box_excess.rb +20 -17
- data/manual/text/text_box_extensions.rb +18 -15
- data/manual/text/text_box_overflow.rb +18 -19
- data/manual/text/utf8.rb +11 -12
- data/manual/text/win_ansi_charset.rb +21 -19
- data/prawn.gemspec +45 -33
- data/spec/extensions/encoding_helpers.rb +3 -3
- data/spec/prawn/document/bounding_box_spec.rb +546 -0
- data/spec/prawn/document/column_box_spec.rb +75 -0
- data/spec/prawn/document/security_spec.rb +176 -0
- data/spec/prawn/document_annotations_spec.rb +76 -0
- data/spec/prawn/document_destinations_spec.rb +15 -0
- data/spec/prawn/document_grid_spec.rb +99 -0
- data/spec/prawn/document_reference_spec.rb +27 -0
- data/spec/prawn/document_span_spec.rb +36 -0
- data/spec/prawn/document_spec.rb +802 -0
- data/spec/prawn/font_metric_cache_spec.rb +54 -0
- data/spec/prawn/font_spec.rb +542 -0
- data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
- data/spec/prawn/graphics/transparency_spec.rb +81 -0
- data/spec/prawn/graphics_spec.rb +837 -0
- data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
- data/spec/prawn/image_handler_spec.rb +53 -0
- data/spec/prawn/images/jpg_spec.rb +20 -0
- data/spec/prawn/images/png_spec.rb +283 -0
- data/spec/prawn/images_spec.rb +224 -0
- data/spec/prawn/measurements_extensions_spec.rb +24 -0
- data/spec/prawn/outline_spec.rb +412 -0
- data/spec/prawn/repeater_spec.rb +165 -0
- data/spec/prawn/soft_mask_spec.rb +74 -0
- data/spec/prawn/stamp_spec.rb +172 -0
- data/spec/prawn/text/box_spec.rb +1112 -0
- data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
- data/spec/prawn/text/formatted/box_spec.rb +846 -0
- data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
- data/spec/prawn/text/formatted/line_wrap_spec.rb +494 -0
- data/spec/prawn/text/formatted/parser_spec.rb +697 -0
- data/spec/prawn/text_draw_text_spec.rb +149 -0
- data/spec/prawn/text_rendering_mode_spec.rb +48 -0
- data/spec/prawn/text_spacing_spec.rb +95 -0
- data/spec/prawn/text_spec.rb +603 -0
- data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
- data/spec/prawn/transformation_stack_spec.rb +66 -0
- data/spec/prawn/view_spec.rb +63 -0
- data/spec/prawn_manual_spec.rb +35 -0
- data/spec/spec_helper.rb +19 -23
- metadata +145 -185
- metadata.gz.sig +4 -0
- data/data/images/16bit.alpha +0 -0
- data/data/images/16bit.color +0 -0
- data/data/images/16bit.png +0 -0
- data/data/images/arrow.png +0 -0
- data/data/images/arrow2.png +0 -0
- data/data/images/dice.alpha +0 -0
- data/data/images/dice.color +0 -0
- data/data/images/dice.png +0 -0
- data/data/images/dice_interlaced.png +0 -0
- data/data/images/fractal.jpg +0 -0
- data/data/images/indexed_color.dat +0 -0
- data/data/images/indexed_color.png +0 -0
- data/data/images/letterhead.jpg +0 -0
- data/data/images/license.md +0 -8
- data/data/images/page_white_text.alpha +0 -0
- data/data/images/page_white_text.color +0 -0
- data/data/images/page_white_text.png +0 -0
- data/data/images/pal_bk.png +0 -0
- data/data/images/pigs.jpg +0 -0
- data/data/images/prawn.png +0 -0
- data/data/images/ruport.png +0 -0
- data/data/images/ruport_data.dat +0 -0
- data/data/images/ruport_transparent.png +0 -0
- data/data/images/ruport_type0.png +0 -0
- data/data/images/stef.jpg +0 -0
- data/data/images/tru256.bmp +0 -0
- data/data/images/web-links.dat +0 -1
- data/data/images/web-links.png +0 -0
- data/data/pdfs/complex_template.pdf +0 -0
- data/data/pdfs/contains_ttf_font.pdf +0 -0
- data/data/pdfs/encrypted.pdf +0 -0
- data/data/pdfs/form.pdf +1 -819
- data/data/pdfs/hexagon.pdf +0 -61
- data/data/pdfs/indirect_reference.pdf +0 -86
- data/data/pdfs/multipage_template.pdf +0 -127
- data/data/pdfs/nested_pages.pdf +0 -118
- data/data/pdfs/page_without_mediabox.pdf +0 -193
- data/data/pdfs/resources_as_indirect_object.pdf +0 -83
- data/data/pdfs/two_hexagons.pdf +0 -90
- data/data/pdfs/version_1_6.pdf +0 -61
- data/data/shift_jis_text.txt +0 -1
- data/spec/acceptance/png.rb +0 -24
- data/spec/annotations_spec.rb +0 -67
- data/spec/bounding_box_spec.rb +0 -501
- data/spec/column_box_spec.rb +0 -59
- data/spec/destinations_spec.rb +0 -13
- data/spec/document_spec.rb +0 -742
- data/spec/extensions/mocha.rb +0 -45
- data/spec/font_metric_cache_spec.rb +0 -52
- data/spec/font_spec.rb +0 -475
- data/spec/formatted_text_arranger_spec.rb +0 -423
- data/spec/formatted_text_box_spec.rb +0 -716
- data/spec/formatted_text_fragment_spec.rb +0 -299
- data/spec/graphics_spec.rb +0 -666
- data/spec/grid_spec.rb +0 -95
- data/spec/image_handler_spec.rb +0 -53
- data/spec/images_spec.rb +0 -167
- data/spec/inline_formatted_text_parser_spec.rb +0 -568
- data/spec/jpg_spec.rb +0 -23
- data/spec/line_wrap_spec.rb +0 -366
- data/spec/measurement_units_spec.rb +0 -22
- data/spec/outline_spec.rb +0 -409
- data/spec/png_spec.rb +0 -235
- data/spec/reference_spec.rb +0 -25
- data/spec/repeater_spec.rb +0 -154
- data/spec/security_spec.rb +0 -151
- data/spec/soft_mask_spec.rb +0 -78
- data/spec/span_spec.rb +0 -43
- data/spec/stamp_spec.rb +0 -179
- data/spec/stroke_styles_spec.rb +0 -208
- data/spec/text_at_spec.rb +0 -142
- data/spec/text_box_spec.rb +0 -1038
- data/spec/text_rendering_mode_spec.rb +0 -45
- data/spec/text_spacing_spec.rb +0 -93
- data/spec/text_spec.rb +0 -549
- data/spec/text_with_inline_formatting_spec.rb +0 -35
- data/spec/transparency_spec.rb +0 -91
- data/spec/view_spec.rb +0 -42
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Prawn::Text do
|
6
|
+
describe '#draw_text' do
|
7
|
+
let(:pdf) { create_pdf }
|
8
|
+
|
9
|
+
it 'raise_errors ArgumentError if :at option omitted' do
|
10
|
+
expect { pdf.draw_text('hai', {}) }.to raise_error(ArgumentError)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'raise_errors ArgumentError if :align option included' do
|
14
|
+
expect do
|
15
|
+
pdf.draw_text('hai', at: [0, 0], align: :center)
|
16
|
+
end.to raise_error(ArgumentError)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'allows drawing empty strings to the page' do
|
20
|
+
pdf.draw_text(' ', at: [100, 100])
|
21
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
22
|
+
expect(text.strings.first).to eq(' ')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'defaults to 12 point helvetica' do
|
26
|
+
pdf.draw_text('Blah', at: [100, 100])
|
27
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
28
|
+
expect(text.font_settings[0][:name]).to eq(:Helvetica)
|
29
|
+
expect(text.font_settings[0][:size]).to eq(12)
|
30
|
+
expect(text.strings.first).to eq('Blah')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'allows setting font size' do
|
34
|
+
pdf.draw_text('Blah', at: [100, 100], size: 16)
|
35
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
36
|
+
expect(text.font_settings[0][:size]).to eq(16)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'allows setting a default font size' do
|
40
|
+
pdf.font_size = 16
|
41
|
+
pdf.draw_text('Blah', at: [0, 0])
|
42
|
+
|
43
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
44
|
+
expect(text.font_settings[0][:size]).to eq(16)
|
45
|
+
end
|
46
|
+
|
47
|
+
# rubocop: disable Naming/AccessorMethodName
|
48
|
+
rotated_text_inspector = Class.new(PDF::Inspector) do
|
49
|
+
attr_reader :tm_operator_used
|
50
|
+
|
51
|
+
def initialize
|
52
|
+
@tm_operator_used = false
|
53
|
+
end
|
54
|
+
|
55
|
+
def set_text_matrix_and_text_line_matrix(*_arguments)
|
56
|
+
@tm_operator_used = true
|
57
|
+
end
|
58
|
+
end
|
59
|
+
# rubocop: enable Naming/AccessorMethodName
|
60
|
+
|
61
|
+
it 'allows rotation' do
|
62
|
+
pdf.draw_text('Test', at: [100, 100], rotate: 90)
|
63
|
+
|
64
|
+
text = rotated_text_inspector.analyze(pdf.render)
|
65
|
+
|
66
|
+
expect(text.tm_operator_used).to eq true
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'does not use rotation matrix by default' do
|
70
|
+
pdf.draw_text('Test', at: [100, 100])
|
71
|
+
|
72
|
+
text = rotated_text_inspector.analyze(pdf.render)
|
73
|
+
|
74
|
+
expect(text.tm_operator_used).to eq false
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'allows overriding default font for a single instance' do
|
78
|
+
pdf.font_size = 16
|
79
|
+
|
80
|
+
pdf.draw_text('Blah', size: 11, at: [0, 0])
|
81
|
+
pdf.draw_text('Blaz', at: [0, 0])
|
82
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
83
|
+
expect(text.font_settings[0][:size]).to eq(11)
|
84
|
+
expect(text.font_settings[1][:size]).to eq(16)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'allows setting a font size transaction with a block' do
|
88
|
+
pdf.font_size 16 do
|
89
|
+
pdf.draw_text('Blah', at: [0, 0])
|
90
|
+
end
|
91
|
+
|
92
|
+
pdf.draw_text('blah', at: [0, 0])
|
93
|
+
|
94
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
95
|
+
expect(text.font_settings[0][:size]).to eq(16)
|
96
|
+
expect(text.font_settings[1][:size]).to eq(12)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'allows manual setting the font size when in a font size block' do
|
100
|
+
pdf.font_size(16) do
|
101
|
+
pdf.draw_text('Foo', at: [0, 0])
|
102
|
+
pdf.draw_text('Blah', size: 11, at: [0, 0])
|
103
|
+
pdf.draw_text('Blaz', at: [0, 0])
|
104
|
+
end
|
105
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
106
|
+
expect(text.font_settings[0][:size]).to eq(16)
|
107
|
+
expect(text.font_settings[1][:size]).to eq(11)
|
108
|
+
expect(text.font_settings[2][:size]).to eq(16)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'allows registering of built-in font_settings on the fly' do
|
112
|
+
pdf.font 'Times-Roman'
|
113
|
+
pdf.draw_text('Blah', at: [100, 100])
|
114
|
+
pdf.font 'Courier'
|
115
|
+
pdf.draw_text('Blaz', at: [150, 150])
|
116
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
117
|
+
expect(text.font_settings[0][:name]).to eq(:"Times-Roman")
|
118
|
+
expect(text.font_settings[1][:name]).to eq(:Courier)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'raise_errors an exception when an unknown font is used' do
|
122
|
+
expect { pdf.font 'Pao bu' }.to raise_error(Prawn::Errors::UnknownFont)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'correctlies render a utf-8 string when using a built-in font' do
|
126
|
+
str = '©' # copyright symbol
|
127
|
+
pdf.draw_text(str, at: [0, 0])
|
128
|
+
|
129
|
+
# grab the text from the rendered PDF and ensure it matches
|
130
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
131
|
+
expect(text.strings.first).to eq(str)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'raises an exception when a utf-8 incompatible string is rendered' do
|
135
|
+
str = "Blah \xDD"
|
136
|
+
expect { pdf.draw_text(str, at: [0, 0]) }.to raise_error(
|
137
|
+
Prawn::Errors::IncompatibleStringEncoding
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'does not raise an exception when a shift-jis string is rendered' do
|
142
|
+
datafile = "#{Prawn::DATADIR}/shift_jis_text.txt"
|
143
|
+
sjis_str = File.open(datafile, 'r:shift_jis', &:gets)
|
144
|
+
pdf.font("#{Prawn::DATADIR}/fonts/gkai00mp.ttf")
|
145
|
+
|
146
|
+
pdf.draw_text(sjis_str, at: [0, 0])
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Prawn::Text do
|
6
|
+
let(:pdf) { create_pdf }
|
7
|
+
|
8
|
+
describe '#text_rendering_mode' do
|
9
|
+
it 'draws the text rendering mode to the document' do
|
10
|
+
pdf.text_rendering_mode(:stroke) do
|
11
|
+
pdf.text('hello world')
|
12
|
+
end
|
13
|
+
contents = PDF::Inspector::Text.analyze(pdf.render)
|
14
|
+
expect(contents.text_rendering_mode.first).to eq(1)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'does not draw the text rendering mode to the document' \
|
18
|
+
' when the new mode matches the old' do
|
19
|
+
pdf.text_rendering_mode(:fill) do
|
20
|
+
pdf.text('hello world')
|
21
|
+
end
|
22
|
+
contents = PDF::Inspector::Text.analyze(pdf.render)
|
23
|
+
expect(contents.text_rendering_mode).to be_empty
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'restores character spacing to 0' do
|
27
|
+
pdf.text_rendering_mode(:stroke) do
|
28
|
+
pdf.text('hello world')
|
29
|
+
end
|
30
|
+
contents = PDF::Inspector::Text.analyze(pdf.render)
|
31
|
+
expect(contents.text_rendering_mode).to eq([1, 0])
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'functions as an accessor when no parameter given' do
|
35
|
+
pdf.text_rendering_mode(:fill_stroke) do
|
36
|
+
pdf.text('hello world')
|
37
|
+
expect(pdf.text_rendering_mode).to eq(:fill_stroke)
|
38
|
+
end
|
39
|
+
expect(pdf.text_rendering_mode).to eq(:fill)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'raise_errors an exception when passed an invalid mode' do
|
43
|
+
expect { pdf.text_rendering_mode(-1) }.to raise_error(ArgumentError)
|
44
|
+
expect { pdf.text_rendering_mode(8) }.to raise_error(ArgumentError)
|
45
|
+
expect { pdf.text_rendering_mode(:flil) }.to raise_error(ArgumentError)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Prawn::Text do
|
6
|
+
let(:pdf) { create_pdf }
|
7
|
+
|
8
|
+
describe '#character_spacing' do
|
9
|
+
it 'draws the character spacing to the document' do
|
10
|
+
pdf.character_spacing(10.555555) do
|
11
|
+
pdf.text('hello world')
|
12
|
+
end
|
13
|
+
contents = PDF::Inspector::Text.analyze(pdf.render)
|
14
|
+
expect(contents.character_spacing.first).to eq(10.5556)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'does not draw the character spacing to the document' \
|
18
|
+
' when the new character spacing matches the old' do
|
19
|
+
pdf.character_spacing(0) do
|
20
|
+
pdf.text('hello world')
|
21
|
+
end
|
22
|
+
contents = PDF::Inspector::Text.analyze(pdf.render)
|
23
|
+
expect(contents.character_spacing).to be_empty
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'restores character spacing to 0' do
|
27
|
+
pdf.character_spacing(10.555555) do
|
28
|
+
pdf.text('hello world')
|
29
|
+
end
|
30
|
+
contents = PDF::Inspector::Text.analyze(pdf.render)
|
31
|
+
expect(contents.character_spacing.last).to eq(0)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'functions as an accessor when no parameter given' do
|
35
|
+
pdf.character_spacing(10.555555) do
|
36
|
+
pdf.text('hello world')
|
37
|
+
expect(pdf.character_spacing).to eq(10.555555)
|
38
|
+
end
|
39
|
+
expect(pdf.character_spacing).to eq(0)
|
40
|
+
end
|
41
|
+
|
42
|
+
# ensure that we properly internationalize by using the number of characters
|
43
|
+
# in a string, not the number of bytes, to insert character spaces
|
44
|
+
#
|
45
|
+
it 'calculates character spacing widths by characters, not bytes' do
|
46
|
+
pdf.font("#{Prawn::DATADIR}/fonts/gkai00mp.ttf")
|
47
|
+
|
48
|
+
str = 'こんにちは世界'
|
49
|
+
raw_width = nil
|
50
|
+
pdf.character_spacing(0) do
|
51
|
+
raw_width = pdf.width_of(str)
|
52
|
+
end
|
53
|
+
|
54
|
+
pdf.character_spacing(10) do
|
55
|
+
# the new width should include six 10-pt character spaces.
|
56
|
+
expect(pdf.width_of(str)).to be_within(0.001).of(raw_width + (10 * 6))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#word_spacing' do
|
62
|
+
it 'draws the word spacing to the document' do
|
63
|
+
pdf.word_spacing(10.555555) do
|
64
|
+
pdf.text('hello world')
|
65
|
+
end
|
66
|
+
contents = PDF::Inspector::Text.analyze(pdf.render)
|
67
|
+
expect(contents.word_spacing.first).to eq(10.5556)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'draws the word spacing to the document' \
|
71
|
+
' when the new word spacing matches the old' do
|
72
|
+
pdf.word_spacing(0) do
|
73
|
+
pdf.text('hello world')
|
74
|
+
end
|
75
|
+
contents = PDF::Inspector::Text.analyze(pdf.render)
|
76
|
+
expect(contents.word_spacing).to be_empty
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'restores word spacing to 0' do
|
80
|
+
pdf.word_spacing(10.555555) do
|
81
|
+
pdf.text('hello world')
|
82
|
+
end
|
83
|
+
contents = PDF::Inspector::Text.analyze(pdf.render)
|
84
|
+
expect(contents.word_spacing.last).to eq(0)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'functions as an accessor when no parameter given' do
|
88
|
+
pdf.word_spacing(10.555555) do
|
89
|
+
pdf.text('hello world')
|
90
|
+
expect(pdf.word_spacing).to eq(10.555555)
|
91
|
+
end
|
92
|
+
expect(pdf.word_spacing).to eq(0)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,603 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Prawn::Text do
|
6
|
+
describe 'NBSP' do
|
7
|
+
it 'is defined' do
|
8
|
+
expect(Prawn::Text::NBSP).to eq("\u00a0")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#height_of' do
|
13
|
+
let(:pdf) { create_pdf }
|
14
|
+
|
15
|
+
it 'returns the height that would be required to print a' \
|
16
|
+
'particular string of text' do
|
17
|
+
original_y = pdf.y
|
18
|
+
pdf.text('Foo')
|
19
|
+
new_y = pdf.y
|
20
|
+
expect(pdf.height_of('Foo')).to be_within(0.0001).of(original_y - new_y)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'omits the gap below the last descender if :final_gap => false ' \
|
24
|
+
'is given' do
|
25
|
+
original_y = pdf.y
|
26
|
+
pdf.text('Foo', final_gap: false)
|
27
|
+
new_y = pdf.y
|
28
|
+
expect(pdf.height_of('Foo', final_gap: false))
|
29
|
+
.to be_within(0.0001).of(original_y - new_y)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'raise_errors CannotFit if a too-small width is given' do
|
33
|
+
expect do
|
34
|
+
pdf.height_of('text', width: 1)
|
35
|
+
end.to raise_error(Prawn::Errors::CannotFit)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'raises NotImplementedError if :indent_paragraphs option is provided' do
|
39
|
+
expect do
|
40
|
+
pdf.height_of(
|
41
|
+
'hai',
|
42
|
+
width: 300,
|
43
|
+
indent_paragraphs: 60
|
44
|
+
)
|
45
|
+
end.to raise_error(NotImplementedError)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'does not raise Prawn::Errors::UnknownOption if :final_gap option '\
|
49
|
+
'is provided' do
|
50
|
+
expect do
|
51
|
+
pdf.height_of('hai', width: 300, final_gap: true)
|
52
|
+
end.to_not raise_error
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#text' do
|
57
|
+
let(:pdf) { create_pdf }
|
58
|
+
|
59
|
+
it 'does not fail when @output is nil when '\
|
60
|
+
'PDF::Core::Text::LineWrap#finalize_line is called' do
|
61
|
+
# need a document with margins for these particulars to produce the
|
62
|
+
# condition that was throwing the error
|
63
|
+
pdf = Prawn::Document.new
|
64
|
+
pdf.text 'transparency ' * 150, size: 18
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'allows drawing empty strings to the page' do
|
68
|
+
pdf.text ' '
|
69
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
70
|
+
# If anything is rendered to the page, it should be whitespace.
|
71
|
+
expect(text.strings).to all(match(/\A\s*\z/))
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'ignores call when string is nil' do
|
75
|
+
expect(pdf.text(nil)).to eq false
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'correctlies render empty paragraphs' do
|
79
|
+
pdf.text "text\n\ntext"
|
80
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
81
|
+
expect(pdf.page_count).to eq(1)
|
82
|
+
expect(text.strings.reject(&:empty?)).to eq(%w[text text])
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'correctlies render empty paragraphs with :indent_paragraphs' do
|
86
|
+
pdf.text "text\n\ntext", indent_paragraphs: 5
|
87
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
88
|
+
expect(pdf.page_count).to eq(1)
|
89
|
+
expect(text.strings.reject(&:empty?)).to eq(%w[text text])
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'correctly renders strings ending with empty paragraphs and ' \
|
93
|
+
':inline_format and :indent_paragraphs' do
|
94
|
+
pdf.text "text\n\n", inline_format: true, indent_paragraphs: 5
|
95
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
96
|
+
expect(pdf.page_count).to eq(1)
|
97
|
+
expect(text.strings).to eq(['text'])
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'defaults to use kerning information' do
|
101
|
+
pdf.text 'hello world'
|
102
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
103
|
+
expect(text.kerned[0]).to eq true
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'is able to disable kerning with an option' do
|
107
|
+
pdf.text 'hello world', kerning: false
|
108
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
109
|
+
expect(text.kerned[0]).to eq false
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'is able to disable kerning document-wide' do
|
113
|
+
pdf.default_kerning(false)
|
114
|
+
pdf.default_kerning = false
|
115
|
+
pdf.text 'hello world'
|
116
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
117
|
+
expect(text.kerned[0]).to eq false
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'option should be able to override document-wide kerning disabling' do
|
121
|
+
pdf.default_kerning = false
|
122
|
+
pdf.text 'hello world', kerning: true
|
123
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
124
|
+
expect(text.kerned[0]).to eq true
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'raise_errors ArgumentError if :at option included' do
|
128
|
+
expect { pdf.text('hai', at: [0, 0]) }.to raise_error(ArgumentError)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'advances down the document based on font_height' do
|
132
|
+
position = pdf.y
|
133
|
+
pdf.text 'Foo'
|
134
|
+
|
135
|
+
expect(pdf.y).to be_within(0.0001).of(position - pdf.font.height)
|
136
|
+
|
137
|
+
position = pdf.y
|
138
|
+
pdf.text "Foo\nBar\nBaz"
|
139
|
+
expect(pdf.y).to be_within(0.0001).of(position - 3 * pdf.font.height)
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'advances down the document based on font_height with size option' do
|
143
|
+
position = pdf.y
|
144
|
+
pdf.text 'Foo', size: 15
|
145
|
+
|
146
|
+
pdf.font_size = 15
|
147
|
+
expect(pdf.y).to be_within(0.0001).of(position - pdf.font.height)
|
148
|
+
|
149
|
+
position = pdf.y
|
150
|
+
pdf.text "Foo\nBar\nBaz"
|
151
|
+
expect(pdf.y).to be_within(0.0001).of(position - 3 * pdf.font.height)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'advances down the document based on font_height with leading option' do
|
155
|
+
position = pdf.y
|
156
|
+
leading = 2
|
157
|
+
pdf.text 'Foo', leading: leading
|
158
|
+
|
159
|
+
expect(pdf.y).to be_within(0.0001)
|
160
|
+
.of(position - pdf.font.height - leading)
|
161
|
+
|
162
|
+
position = pdf.y
|
163
|
+
pdf.text "Foo\nBar\nBaz"
|
164
|
+
expect(pdf.y).to be_within(0.0001).of(position - 3 * pdf.font.height)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'advances only to the bottom of the final descender if final_gap '\
|
168
|
+
'is false' do
|
169
|
+
position = pdf.y
|
170
|
+
pdf.text 'Foo', final_gap: false
|
171
|
+
|
172
|
+
expect(pdf.y).to be_within(0.0001)
|
173
|
+
.of(position - pdf.font.ascender - pdf.font.descender)
|
174
|
+
|
175
|
+
position = pdf.y
|
176
|
+
pdf.text "Foo\nBar\nBaz", final_gap: false
|
177
|
+
expect(pdf.y).to be_within(0.0001)
|
178
|
+
.of(
|
179
|
+
position - 2 * pdf.font.height - pdf.font.ascender -
|
180
|
+
pdf.font.descender
|
181
|
+
)
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'is able to print text starting at the last line of a page' do
|
185
|
+
pdf.move_cursor_to(pdf.font.height)
|
186
|
+
pdf.text('hello world')
|
187
|
+
pages = PDF::Inspector::Page.analyze(pdf.render).pages
|
188
|
+
expect(pages.size).to eq(1)
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'defaults to 12 point helvetica' do
|
192
|
+
pdf.text 'Blah'
|
193
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
194
|
+
expect(text.font_settings[0][:name]).to eq(:Helvetica)
|
195
|
+
expect(text.font_settings[0][:size]).to eq(12)
|
196
|
+
expect(text.strings.first).to eq('Blah')
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'allows setting font size' do
|
200
|
+
pdf.text 'Blah', size: 16
|
201
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
202
|
+
expect(text.font_settings[0][:size]).to eq(16)
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'allows setting a default font size' do
|
206
|
+
pdf.font_size = 16
|
207
|
+
pdf.text 'Blah'
|
208
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
209
|
+
expect(text.font_settings[0][:size]).to eq(16)
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'allows overriding default font for a single instance' do
|
213
|
+
pdf.font_size = 16
|
214
|
+
|
215
|
+
pdf.text 'Blah', size: 11
|
216
|
+
pdf.text 'Blaz'
|
217
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
218
|
+
expect(text.font_settings[0][:size]).to eq(11)
|
219
|
+
expect(text.font_settings[1][:size]).to eq(16)
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'allows setting a font size transaction with a block' do
|
223
|
+
pdf.font_size 16 do
|
224
|
+
pdf.text 'Blah'
|
225
|
+
end
|
226
|
+
|
227
|
+
pdf.text 'blah'
|
228
|
+
|
229
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
230
|
+
expect(text.font_settings[0][:size]).to eq(16)
|
231
|
+
expect(text.font_settings[1][:size]).to eq(12)
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'allows manual setting the font size when in a font size block' do
|
235
|
+
pdf.font_size(16) do
|
236
|
+
pdf.text 'Foo'
|
237
|
+
pdf.text 'Blah', size: 11
|
238
|
+
pdf.text 'Blaz'
|
239
|
+
end
|
240
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
241
|
+
expect(text.font_settings[0][:size]).to eq(16)
|
242
|
+
expect(text.font_settings[1][:size]).to eq(11)
|
243
|
+
expect(text.font_settings[2][:size]).to eq(16)
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'allows registering of built-in font_settings on the fly' do
|
247
|
+
pdf.font 'Times-Roman'
|
248
|
+
pdf.text 'Blah'
|
249
|
+
pdf.font 'Courier'
|
250
|
+
pdf.text 'Blaz'
|
251
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
252
|
+
expect(text.font_settings[0][:name]).to eq(:"Times-Roman")
|
253
|
+
expect(text.font_settings[1][:name]).to eq(:Courier)
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'utilises the same default font across multiple pages' do
|
257
|
+
pdf.text 'Blah'
|
258
|
+
pdf.start_new_page
|
259
|
+
pdf.text 'Blaz'
|
260
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
261
|
+
|
262
|
+
expect(text.font_settings.size).to eq(2)
|
263
|
+
expect(text.font_settings[0][:name]).to eq(:Helvetica)
|
264
|
+
expect(text.font_settings[1][:name]).to eq(:Helvetica)
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'raise_errors an exception when an unknown font is used' do
|
268
|
+
expect { pdf.font 'Pao bu' }.to raise_error(Prawn::Errors::UnknownFont)
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'does not raise an exception when providing Pathname instance as font' do
|
272
|
+
pdf.font Pathname.new("#{Prawn::DATADIR}/fonts/DejaVuSans.ttf")
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'correctlies render a utf-8 string when using a built-in font' do
|
276
|
+
str = '©' # copyright symbol
|
277
|
+
pdf.text str
|
278
|
+
|
279
|
+
# grab the text from the rendered PDF and ensure it matches
|
280
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
281
|
+
expect(text.strings.first).to eq(str)
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'correctlies render a utf-8 string when using a TTF font' do
|
285
|
+
str = '©' # copyright symbol
|
286
|
+
pdf.font "#{Prawn::DATADIR}/fonts/DejaVuSans.ttf"
|
287
|
+
pdf.text str
|
288
|
+
|
289
|
+
# grab the text from the rendered PDF and ensure it matches
|
290
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
291
|
+
expect(text.strings.first).to eq(str)
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'subsets mixed low-ASCII and non-ASCII characters when they can '\
|
295
|
+
'be subsetted together' do
|
296
|
+
str = 'It’s super effective!'
|
297
|
+
pdf.font "#{Prawn::DATADIR}/fonts/DejaVuSans.ttf"
|
298
|
+
pdf.text str
|
299
|
+
|
300
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
301
|
+
expect(text.strings.first).to eq(str)
|
302
|
+
end
|
303
|
+
|
304
|
+
it 'correctly renders a string with higher bit characters across a page '\
|
305
|
+
'break when using a built-in font' do
|
306
|
+
str = '©'
|
307
|
+
pdf.move_cursor_to(pdf.font.height)
|
308
|
+
pdf.text(str + "\n" + str)
|
309
|
+
|
310
|
+
pages = PDF::Inspector::Page.analyze(pdf.render).pages
|
311
|
+
expect(pages.size).to eq(2)
|
312
|
+
expect(pages[0][:strings]).to eq([str])
|
313
|
+
expect(pages[1][:strings]).to eq([str])
|
314
|
+
end
|
315
|
+
|
316
|
+
it 'correctly renders a string with higher bit characters across ' \
|
317
|
+
'a page break when using a built-in font and :indent_paragraphs option' do
|
318
|
+
str = '©'
|
319
|
+
pdf.move_cursor_to(pdf.font.height)
|
320
|
+
pdf.text(str + "\n" + str, indent_paragraphs: 20)
|
321
|
+
|
322
|
+
pages = PDF::Inspector::Page.analyze(pdf.render).pages
|
323
|
+
expect(pages.size).to eq(2)
|
324
|
+
expect(pages[0][:strings]).to eq([str])
|
325
|
+
expect(pages[1][:strings]).to eq([str])
|
326
|
+
end
|
327
|
+
|
328
|
+
it 'raises an exception when a utf-8 incompatible string is rendered' do
|
329
|
+
str = "Blah \xDD"
|
330
|
+
expect { pdf.text str }.to raise_error(
|
331
|
+
Prawn::Errors::IncompatibleStringEncoding
|
332
|
+
)
|
333
|
+
end
|
334
|
+
|
335
|
+
it 'does not raise an exception when a shift-jis string is rendered' do
|
336
|
+
datafile = "#{Prawn::DATADIR}/shift_jis_text.txt"
|
337
|
+
sjis_str = File.open(datafile, 'r:shift_jis', &:gets)
|
338
|
+
pdf.font("#{Prawn::DATADIR}/fonts/gkai00mp.ttf")
|
339
|
+
|
340
|
+
# Expect that the call to text will not raise an encoding error
|
341
|
+
pdf.text(sjis_str)
|
342
|
+
end
|
343
|
+
|
344
|
+
it 'calls move_past_bottom when printing more text than can fit' \
|
345
|
+
' between the current document.y and bounds.bottom' do
|
346
|
+
pdf.y = pdf.font.height
|
347
|
+
pdf.text 'Hello'
|
348
|
+
pdf.text 'World'
|
349
|
+
pages = PDF::Inspector::Page.analyze(pdf.render).pages
|
350
|
+
expect(pages.size).to eq(2)
|
351
|
+
expect(pages[0][:strings]).to eq(['Hello'])
|
352
|
+
expect(pages[1][:strings]).to eq(['World'])
|
353
|
+
end
|
354
|
+
|
355
|
+
describe 'with :indent_paragraphs option' do
|
356
|
+
it 'indents the paragraphs' do
|
357
|
+
hello = 'hello ' * 50
|
358
|
+
hello2 = 'hello ' * 50
|
359
|
+
pdf.text(hello + "\n" + hello2, indent_paragraphs: 60)
|
360
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
361
|
+
expect(text.strings[0]).to eq(('hello ' * 19).strip)
|
362
|
+
expect(text.strings[1]).to eq(('hello ' * 21).strip)
|
363
|
+
expect(text.strings[3]).to eq(('hello ' * 19).strip)
|
364
|
+
expect(text.strings[4]).to eq(('hello ' * 21).strip)
|
365
|
+
end
|
366
|
+
|
367
|
+
it 'indents from right side when using :rtl direction' do
|
368
|
+
para1 = 'The rain in spain falls mainly on the plains ' * 3
|
369
|
+
para2 = 'The rain in spain falls mainly on the plains ' * 3
|
370
|
+
|
371
|
+
pdf.text(para1 + "\n" + para2, indent_paragraphs: 60, direction: :rtl)
|
372
|
+
|
373
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
374
|
+
|
375
|
+
lines = text.strings
|
376
|
+
x_positions = text.positions.map { |e| e[0] }
|
377
|
+
|
378
|
+
# NOTE: The code below reflects Prawn's current kerning behavior for RTL
|
379
|
+
# text, which isn't necessarily correct. If we change that behavior,
|
380
|
+
# this test will need to be updated.
|
381
|
+
|
382
|
+
expect(x_positions[0]).to(
|
383
|
+
be_within(0.001).of(pdf.bounds.absolute_right - 60 -
|
384
|
+
pdf.width_of(lines[0].reverse, kerning: true))
|
385
|
+
)
|
386
|
+
|
387
|
+
expect(x_positions[1]).to(
|
388
|
+
be_within(0.001).of(pdf.bounds.absolute_right -
|
389
|
+
pdf.width_of(lines[1].reverse, kerning: true))
|
390
|
+
)
|
391
|
+
|
392
|
+
expect(x_positions[2]).to(
|
393
|
+
be_within(0.001).of(pdf.bounds.absolute_right - 60 -
|
394
|
+
pdf.width_of(lines[2].reverse, kerning: true))
|
395
|
+
)
|
396
|
+
|
397
|
+
expect(x_positions[3]).to(
|
398
|
+
be_within(0.001).of(pdf.bounds.absolute_right -
|
399
|
+
pdf.width_of(lines[3].reverse, kerning: true))
|
400
|
+
)
|
401
|
+
end
|
402
|
+
|
403
|
+
it 'indents from right side when document has :rtl direction' do
|
404
|
+
para1 = 'The rain in spain falls mainly on the plains ' * 3
|
405
|
+
para2 = 'The rain in spain falls mainly on the plains ' * 3
|
406
|
+
|
407
|
+
pdf.text_direction = :rtl
|
408
|
+
pdf.text(para1 + "\n" + para2, indent_paragraphs: 60)
|
409
|
+
|
410
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
411
|
+
|
412
|
+
lines = text.strings
|
413
|
+
x_positions = text.positions.map { |e| e[0] }
|
414
|
+
|
415
|
+
# NOTE: The code below reflects Prawn's current kerning behavior for RTL
|
416
|
+
# text, which isn't necessarily correct. If we change that behavior,
|
417
|
+
# this test will need to be updated.
|
418
|
+
|
419
|
+
expect(x_positions[0]).to(
|
420
|
+
be_within(0.001).of(pdf.bounds.absolute_right - 60 -
|
421
|
+
pdf.width_of(lines[0].reverse, kerning: true))
|
422
|
+
)
|
423
|
+
|
424
|
+
expect(x_positions[1]).to(
|
425
|
+
be_within(0.001).of(pdf.bounds.absolute_right -
|
426
|
+
pdf.width_of(lines[1].reverse, kerning: true))
|
427
|
+
)
|
428
|
+
|
429
|
+
expect(x_positions[2]).to(
|
430
|
+
be_within(0.001).of(pdf.bounds.absolute_right - 60 -
|
431
|
+
pdf.width_of(lines[2].reverse, kerning: true))
|
432
|
+
)
|
433
|
+
|
434
|
+
expect(x_positions[3]).to(
|
435
|
+
be_within(0.001).of(pdf.bounds.absolute_right -
|
436
|
+
pdf.width_of(lines[3].reverse, kerning: true))
|
437
|
+
)
|
438
|
+
end
|
439
|
+
|
440
|
+
it 'indents from left side when using :ltr direction' do
|
441
|
+
para1 = 'The rain in spain falls mainly on the plains ' * 3
|
442
|
+
para2 = 'The rain in spain falls mainly on the plains ' * 3
|
443
|
+
|
444
|
+
pdf.text(para1 + "\n" + para2, indent_paragraphs: 60, direction: :ltr)
|
445
|
+
|
446
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
447
|
+
|
448
|
+
x_positions = text.positions.map { |e| e[0] }
|
449
|
+
|
450
|
+
expect(x_positions[0]).to eq(60)
|
451
|
+
expect(x_positions[1]).to eq(0)
|
452
|
+
|
453
|
+
expect(x_positions[2]).to eq(60)
|
454
|
+
expect(x_positions[3]).to eq(0)
|
455
|
+
end
|
456
|
+
|
457
|
+
it 'indents from left side when document has :ltr direction' do
|
458
|
+
para1 = 'The rain in spain falls mainly on the plains ' * 3
|
459
|
+
para2 = 'The rain in spain falls mainly on the plains ' * 3
|
460
|
+
|
461
|
+
pdf.text_direction = :ltr
|
462
|
+
pdf.text(para1 + "\n" + para2, indent_paragraphs: 60)
|
463
|
+
|
464
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
465
|
+
|
466
|
+
x_positions = text.positions.map { |e| e[0] }
|
467
|
+
|
468
|
+
expect(x_positions[0]).to eq(60)
|
469
|
+
expect(x_positions[1]).to eq(0)
|
470
|
+
|
471
|
+
expect(x_positions[2]).to eq(60)
|
472
|
+
expect(x_positions[3]).to eq(0)
|
473
|
+
end
|
474
|
+
|
475
|
+
describe 'when paragraph has only one line, it should not add ' \
|
476
|
+
'additional leading' do
|
477
|
+
let(:leading) { 100 }
|
478
|
+
|
479
|
+
it 'adds leading only once' do
|
480
|
+
original_y = pdf.y
|
481
|
+
pdf.text('hello', indent_paragraphs: 10, leading: leading)
|
482
|
+
expect(original_y - pdf.y).to be < leading * 2
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
describe 'when wrap to new page, and first line of new page' \
|
487
|
+
' is not the start of a new paragraph, that line should' \
|
488
|
+
' not be indented' do
|
489
|
+
it 'indents the paragraphs' do
|
490
|
+
hello = 'hello ' * 50
|
491
|
+
hello2 = 'hello ' * 50
|
492
|
+
pdf.move_cursor_to(pdf.font.height)
|
493
|
+
pdf.text(hello + "\n" + hello2, indent_paragraphs: 60)
|
494
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
495
|
+
expect(text.strings[0]).to eq(('hello ' * 19).strip)
|
496
|
+
expect(text.strings[1]).to eq(('hello ' * 21).strip)
|
497
|
+
expect(text.strings[3]).to eq(('hello ' * 19).strip)
|
498
|
+
expect(text.strings[4]).to eq(('hello ' * 21).strip)
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
describe 'when wrap to new page, and first line of new page' \
|
503
|
+
' is the start of a new paragraph, that line should' \
|
504
|
+
' be indented' do
|
505
|
+
it 'indents the paragraphs' do
|
506
|
+
hello = 'hello ' * 50
|
507
|
+
hello2 = 'hello ' * 50
|
508
|
+
pdf.move_cursor_to(pdf.font.height * 3)
|
509
|
+
pdf.text(hello + "\n" + hello2, indent_paragraphs: 60)
|
510
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
511
|
+
expect(text.strings[0]).to eq(('hello ' * 19).strip)
|
512
|
+
expect(text.strings[1]).to eq(('hello ' * 21).strip)
|
513
|
+
expect(text.strings[3]).to eq(('hello ' * 19).strip)
|
514
|
+
expect(text.strings[4]).to eq(('hello ' * 21).strip)
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
describe 'kerning' do
|
520
|
+
it 'respects text kerning setting (document default)' do
|
521
|
+
allow(pdf.font).to receive(:compute_width_of)
|
522
|
+
.with('VAT', hash_including(kerning: true))
|
523
|
+
.and_return(10)
|
524
|
+
|
525
|
+
pdf.text 'VAT'
|
526
|
+
|
527
|
+
expect(pdf.font).to have_received(:compute_width_of)
|
528
|
+
.with('VAT', hash_including(kerning: true))
|
529
|
+
end
|
530
|
+
|
531
|
+
it 'respects text kerning setting (kerning=true)' do
|
532
|
+
allow(pdf.font).to receive(:compute_width_of)
|
533
|
+
.with('VAT', hash_including(kerning: true))
|
534
|
+
.at_least(:once)
|
535
|
+
.and_return(10)
|
536
|
+
pdf.text 'VAT', kerning: true
|
537
|
+
|
538
|
+
expect(pdf.font).to have_received(:compute_width_of)
|
539
|
+
.with('VAT', hash_including(kerning: true))
|
540
|
+
.at_least(:once)
|
541
|
+
end
|
542
|
+
|
543
|
+
it 'respects text kerning setting (kerning=false)' do
|
544
|
+
allow(pdf.font).to receive(:compute_width_of)
|
545
|
+
.with('VAT', hash_including(kerning: false))
|
546
|
+
.at_least(:once)
|
547
|
+
.and_return(10)
|
548
|
+
pdf.text 'VAT', kerning: false
|
549
|
+
|
550
|
+
expect(pdf.font).to have_received(:compute_width_of)
|
551
|
+
.with('VAT', hash_including(kerning: false))
|
552
|
+
.at_least(:once)
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
describe '#shrink_to_fit with special utf-8 text' do
|
557
|
+
it 'does not throw an exception', :unresolved, issue: 603 do
|
558
|
+
expect do
|
559
|
+
Prawn::Document.new(page_size: 'A4', margin: [2, 2, 2, 2]) do |pdf|
|
560
|
+
add_unicode_fonts(pdf)
|
561
|
+
pdf.bounding_box([1, 1], width: 90, height: 50) do
|
562
|
+
pdf.text(
|
563
|
+
"Sample Text\nSAMPLE SAMPLE SAMPLEoddělení ZMĚN\nSAMPLE",
|
564
|
+
overflow: :shrink_to_fit
|
565
|
+
)
|
566
|
+
end
|
567
|
+
end
|
568
|
+
end.to_not raise_error
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
def add_unicode_fonts(pdf)
|
573
|
+
dejavu = "#{::Prawn::BASEDIR}/data/fonts/DejaVuSans.ttf"
|
574
|
+
pdf.font_families.update(
|
575
|
+
'dejavu' => {
|
576
|
+
normal: dejavu,
|
577
|
+
italic: dejavu,
|
578
|
+
bold: dejavu,
|
579
|
+
bold_italic: dejavu
|
580
|
+
}
|
581
|
+
)
|
582
|
+
pdf.fallback_fonts = ['dejavu']
|
583
|
+
end
|
584
|
+
|
585
|
+
describe 'fallback_fonts' do
|
586
|
+
it 'preserves font style' do
|
587
|
+
create_pdf
|
588
|
+
|
589
|
+
pdf.fallback_fonts ['Helvetica']
|
590
|
+
pdf.font 'Times-Roman', style: :italic do
|
591
|
+
pdf.text 'hello'
|
592
|
+
end
|
593
|
+
|
594
|
+
text = PDF::Inspector::Text.analyze(pdf.render)
|
595
|
+
fonts_used = text.font_settings.map { |e| e[:name] }
|
596
|
+
|
597
|
+
expect(fonts_used.length).to eq(1)
|
598
|
+
expect(fonts_used[0]).to eq(:"Times-Italic")
|
599
|
+
expect(text.strings[0]).to eq('hello')
|
600
|
+
end
|
601
|
+
end
|
602
|
+
end
|
603
|
+
end
|