hexapdf 0.5.0 → 0.6.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.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +76 -2
  3. data/CONTRIBUTERS +1 -1
  4. data/Rakefile +1 -1
  5. data/VERSION +1 -1
  6. data/examples/boxes.rb +68 -0
  7. data/examples/graphics.rb +12 -12
  8. data/examples/{text_box_alignment.rb → text_layouter_alignment.rb} +14 -14
  9. data/examples/text_layouter_inline_boxes.rb +66 -0
  10. data/examples/{text_box_line_wrapping.rb → text_layouter_line_wrapping.rb} +9 -10
  11. data/examples/{text_box_shapes.rb → text_layouter_shapes.rb} +58 -54
  12. data/examples/text_layouter_styling.rb +125 -0
  13. data/examples/truetype.rb +5 -7
  14. data/lib/hexapdf/cli/command.rb +1 -0
  15. data/lib/hexapdf/configuration.rb +170 -106
  16. data/lib/hexapdf/content/canvas.rb +41 -36
  17. data/lib/hexapdf/content/graphics_state.rb +15 -0
  18. data/lib/hexapdf/content/operator.rb +1 -1
  19. data/lib/hexapdf/dictionary.rb +20 -8
  20. data/lib/hexapdf/dictionary_fields.rb +8 -6
  21. data/lib/hexapdf/document.rb +25 -26
  22. data/lib/hexapdf/document/fonts.rb +4 -4
  23. data/lib/hexapdf/document/images.rb +2 -2
  24. data/lib/hexapdf/document/pages.rb +16 -16
  25. data/lib/hexapdf/encryption/security_handler.rb +41 -9
  26. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  27. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  28. data/lib/hexapdf/filter/predictor.rb +7 -1
  29. data/lib/hexapdf/font/true_type/font.rb +20 -0
  30. data/lib/hexapdf/font/type1/font.rb +23 -0
  31. data/lib/hexapdf/font_loader.rb +1 -0
  32. data/lib/hexapdf/font_loader/from_configuration.rb +2 -3
  33. data/lib/hexapdf/font_loader/from_file.rb +65 -0
  34. data/lib/hexapdf/image_loader/png.rb +2 -2
  35. data/lib/hexapdf/layout.rb +3 -2
  36. data/lib/hexapdf/layout/box.rb +146 -0
  37. data/lib/hexapdf/layout/inline_box.rb +40 -31
  38. data/lib/hexapdf/layout/{line_fragment.rb → line.rb} +12 -13
  39. data/lib/hexapdf/layout/style.rb +630 -41
  40. data/lib/hexapdf/layout/text_fragment.rb +80 -12
  41. data/lib/hexapdf/layout/{text_box.rb → text_layouter.rb} +164 -109
  42. data/lib/hexapdf/number_tree_node.rb +1 -1
  43. data/lib/hexapdf/parser.rb +4 -1
  44. data/lib/hexapdf/revisions.rb +11 -4
  45. data/lib/hexapdf/stream.rb +8 -9
  46. data/lib/hexapdf/tokenizer.rb +5 -3
  47. data/lib/hexapdf/type.rb +3 -0
  48. data/lib/hexapdf/type/action.rb +56 -0
  49. data/lib/hexapdf/type/actions.rb +52 -0
  50. data/lib/hexapdf/type/actions/go_to.rb +52 -0
  51. data/lib/hexapdf/type/actions/go_to_r.rb +54 -0
  52. data/lib/hexapdf/type/actions/launch.rb +73 -0
  53. data/lib/hexapdf/type/actions/uri.rb +65 -0
  54. data/lib/hexapdf/type/annotation.rb +85 -0
  55. data/lib/hexapdf/type/annotations.rb +51 -0
  56. data/lib/hexapdf/type/annotations/link.rb +70 -0
  57. data/lib/hexapdf/type/annotations/markup_annotation.rb +70 -0
  58. data/lib/hexapdf/type/annotations/text.rb +81 -0
  59. data/lib/hexapdf/type/catalog.rb +3 -1
  60. data/lib/hexapdf/type/embedded_file.rb +6 -11
  61. data/lib/hexapdf/type/file_specification.rb +4 -6
  62. data/lib/hexapdf/type/font.rb +3 -1
  63. data/lib/hexapdf/type/font_descriptor.rb +18 -16
  64. data/lib/hexapdf/type/form.rb +3 -1
  65. data/lib/hexapdf/type/graphics_state_parameter.rb +3 -1
  66. data/lib/hexapdf/type/image.rb +4 -2
  67. data/lib/hexapdf/type/info.rb +2 -5
  68. data/lib/hexapdf/type/names.rb +2 -5
  69. data/lib/hexapdf/type/object_stream.rb +2 -1
  70. data/lib/hexapdf/type/page.rb +14 -1
  71. data/lib/hexapdf/type/page_tree_node.rb +9 -6
  72. data/lib/hexapdf/type/resources.rb +2 -5
  73. data/lib/hexapdf/type/trailer.rb +2 -5
  74. data/lib/hexapdf/type/viewer_preferences.rb +2 -5
  75. data/lib/hexapdf/type/xref_stream.rb +3 -1
  76. data/lib/hexapdf/version.rb +1 -1
  77. data/test/hexapdf/common_tokenizer_tests.rb +3 -1
  78. data/test/hexapdf/content/test_canvas.rb +29 -3
  79. data/test/hexapdf/content/test_graphics_state.rb +11 -0
  80. data/test/hexapdf/content/test_operator.rb +3 -2
  81. data/test/hexapdf/document/test_fonts.rb +8 -8
  82. data/test/hexapdf/document/test_images.rb +4 -12
  83. data/test/hexapdf/document/test_pages.rb +7 -7
  84. data/test/hexapdf/encryption/test_security_handler.rb +1 -5
  85. data/test/hexapdf/filter/test_predictor.rb +40 -12
  86. data/test/hexapdf/font/true_type/test_font.rb +16 -0
  87. data/test/hexapdf/font/type1/test_font.rb +30 -0
  88. data/test/hexapdf/font_loader/test_from_file.rb +29 -0
  89. data/test/hexapdf/font_loader/test_standard14.rb +4 -3
  90. data/test/hexapdf/layout/test_box.rb +104 -0
  91. data/test/hexapdf/layout/test_inline_box.rb +24 -10
  92. data/test/hexapdf/layout/{test_line_fragment.rb → test_line.rb} +9 -9
  93. data/test/hexapdf/layout/test_style.rb +519 -31
  94. data/test/hexapdf/layout/test_text_fragment.rb +136 -15
  95. data/test/hexapdf/layout/{test_text_box.rb → test_text_layouter.rb} +224 -144
  96. data/test/hexapdf/layout/test_text_shaper.rb +1 -1
  97. data/test/hexapdf/test_configuration.rb +12 -6
  98. data/test/hexapdf/test_dictionary.rb +27 -2
  99. data/test/hexapdf/test_dictionary_fields.rb +10 -1
  100. data/test/hexapdf/test_document.rb +14 -13
  101. data/test/hexapdf/test_parser.rb +12 -0
  102. data/test/hexapdf/test_revisions.rb +34 -0
  103. data/test/hexapdf/test_stream.rb +1 -1
  104. data/test/hexapdf/test_type.rb +18 -0
  105. data/test/hexapdf/test_writer.rb +2 -2
  106. data/test/hexapdf/type/actions/test_launch.rb +24 -0
  107. data/test/hexapdf/type/actions/test_uri.rb +23 -0
  108. data/test/hexapdf/type/annotations/test_link.rb +19 -0
  109. data/test/hexapdf/type/annotations/test_markup_annotation.rb +22 -0
  110. data/test/hexapdf/type/annotations/test_text.rb +38 -0
  111. data/test/hexapdf/type/test_annotation.rb +38 -0
  112. data/test/hexapdf/type/test_file_specification.rb +0 -7
  113. data/test/hexapdf/type/test_info.rb +0 -5
  114. data/test/hexapdf/type/test_page.rb +14 -0
  115. data/test/hexapdf/type/test_page_tree_node.rb +4 -1
  116. data/test/hexapdf/type/test_trailer.rb +0 -4
  117. data/test/test_helper.rb +6 -3
  118. metadata +36 -15
  119. data/examples/text_box_inline_boxes.rb +0 -56
  120. data/examples/text_box_styling.rb +0 -72
  121. data/test/hexapdf/type/test_embedded_file.rb +0 -16
  122. data/test/hexapdf/type/test_names.rb +0 -9
@@ -18,11 +18,7 @@ describe HexaPDF::Document::Images do
18
18
  s = HexaPDF::StreamData.new(s) if s.kind_of?(IO)
19
19
  doc.add({Subtype: :Image}, stream: s)
20
20
  end
21
- HexaPDF::GlobalConfiguration['image_loader'].unshift(@loader)
22
- end
23
-
24
- after do
25
- HexaPDF::GlobalConfiguration['image_loader'].delete(@loader)
21
+ @doc.config['image_loader'].unshift(@loader)
26
22
  end
27
23
 
28
24
  it "adds an image using a filename" do
@@ -49,13 +45,9 @@ describe HexaPDF::Document::Images do
49
45
  end
50
46
 
51
47
  it "fails if the needed image loader can't be resolved" do
52
- begin
53
- HexaPDF::GlobalConfiguration['image_loader'].unshift('SomeUnknownConstantHere')
54
- exp = assert_raises(HexaPDF::Error) { @doc.images.add(StringIO.new('test')) }
55
- assert_match(/image loader from configuration/, exp.message)
56
- ensure
57
- HexaPDF::GlobalConfiguration['image_loader'].shift
58
- end
48
+ @doc.config['image_loader'].unshift('SomeUnknownConstantHere')
49
+ exp = assert_raises(HexaPDF::Error) { @doc.images.add(StringIO.new('test')) }
50
+ assert_match(/image loader from configuration/, exp.message)
59
51
  end
60
52
 
61
53
  it "fails if no image loader is found" do
@@ -27,21 +27,21 @@ describe HexaPDF::Document::Pages do
27
27
  end
28
28
 
29
29
  it "adds a new empty page with the given page format" do
30
- page = @doc.pages.add(:A4)
30
+ page = @doc.pages.add(:A4, orientation: :landscape)
31
31
  assert_same(page, @doc.pages[0])
32
- assert_equal([0, 0, 595, 842], @doc.pages[0].box(:media).value)
32
+ assert_equal([0, 0, 842, 595], @doc.pages[0].box(:media).value)
33
33
  end
34
34
 
35
- it "fails if an unknown page format is given" do
36
- assert_raises(HexaPDF::Error) { @doc.pages.add(:A953) }
37
- end
38
-
39
- it "adds a given page to the end" do
35
+ it "adds the given page to the end" do
40
36
  page = @doc.pages.add
41
37
  new_page = @doc.add(Type: :Page)
42
38
  assert_same(new_page, @doc.pages.add(new_page))
43
39
  assert_equal([page, new_page], @doc.pages.root[:Kids])
44
40
  end
41
+
42
+ it "fails if an unknown page format is given" do
43
+ assert_raises(HexaPDF::Error) { @doc.pages.add(:A953) }
44
+ end
45
45
  end
46
46
 
47
47
  describe "<<" do
@@ -67,11 +67,7 @@ describe HexaPDF::Encryption::SecurityHandler do
67
67
 
68
68
  describe "class methods" do
69
69
  before do
70
- HexaPDF::GlobalConfiguration['encryption.filter_map'][:Test] = TestHandler
71
- end
72
-
73
- after do
74
- HexaPDF::GlobalConfiguration['encryption.filter_map'].delete(:Test)
70
+ @document.config['encryption.filter_map'][:Test] = TestHandler
75
71
  end
76
72
 
77
73
  describe "class set_up_encryption" do
@@ -88,12 +88,26 @@ describe HexaPDF::Filter::Predictor do
88
88
  end
89
89
  end
90
90
 
91
- it "fails if data is missing" do
92
- assert_raises(HexaPDF::FilterError) do
93
- data = @testcases['up']
94
- encoder = @obj.png_execute(:encoder, feeder(data[:source][0..-2], 1), data[:Predictor],
95
- data[:Colors], data[:BitsPerComponent], data[:Columns])
96
- collector(encoder)
91
+ it "handles a short last row if 'filter.predictor.strict' is false" do
92
+ data = @testcases['up']
93
+ encoder = @obj.png_execute(:encoder, feeder(data[:source][0..-3], 1), data[:Predictor],
94
+ data[:Colors], data[:BitsPerComponent], data[:Columns])
95
+ result = collector(encoder)
96
+ assert_equal(1 + 5 + 1 + 3, result.length)
97
+ assert_equal(data[:result][0..-3], result)
98
+ end
99
+
100
+ it "fails if the last row is missing data and 'filter.predictor.strict' is true " do
101
+ begin
102
+ HexaPDF::GlobalConfiguration['filter.predictor.strict'] = true
103
+ assert_raises(HexaPDF::FilterError) do
104
+ data = @testcases['up']
105
+ encoder = @obj.png_execute(:encoder, feeder(data[:source][0..-2], 1), data[:Predictor],
106
+ data[:Colors], data[:BitsPerComponent], data[:Columns])
107
+ collector(encoder)
108
+ end
109
+ ensure
110
+ HexaPDF::GlobalConfiguration['filter.predictor.strict'] = false
97
111
  end
98
112
  end
99
113
  end
@@ -107,12 +121,26 @@ describe HexaPDF::Filter::Predictor do
107
121
  end
108
122
  end
109
123
 
110
- it "fails if data is missing" do
111
- assert_raises(HexaPDF::FilterError) do
112
- data = @testcases['up']
113
- encoder = @obj.png_execute(:decoder, feeder(data[:result][0..-2], 1), data[:Predictor], data[:Colors],
114
- data[:BitsPerComponent], data[:Columns])
115
- collector(encoder)
124
+ it "handles a short last row if 'filter.predictor.strict' is false" do
125
+ data = @testcases['up']
126
+ encoder = @obj.png_execute(:decoder, feeder(data[:result][0..-3], 1), data[:Predictor],
127
+ data[:Colors], data[:BitsPerComponent], data[:Columns])
128
+ result = collector(encoder)
129
+ assert_equal(5 + 3, result.length)
130
+ assert_equal(data[:source][0..-3], result)
131
+ end
132
+
133
+ it "fails if the last row is missing data and 'filter.predictor.strict' is true " do
134
+ begin
135
+ HexaPDF::GlobalConfiguration['filter.predictor.strict'] = true
136
+ assert_raises(HexaPDF::FilterError) do
137
+ data = @testcases['up']
138
+ encoder = @obj.png_execute(:decoder, feeder(data[:result][0..-2], 1), data[:Predictor],
139
+ data[:Colors], data[:BitsPerComponent], data[:Columns])
140
+ collector(encoder)
141
+ end
142
+ ensure
143
+ HexaPDF::GlobalConfiguration['filter.predictor.strict'] = false
116
144
  end
117
145
  end
118
146
  end
@@ -88,6 +88,22 @@ describe HexaPDF::Font::TrueType::Font do
88
88
  it "returns the font's dominant vertical stem width" do
89
89
  assert_equal(80, @font.dominant_vertical_stem_width)
90
90
  end
91
+
92
+ it "returns the underline position" do
93
+ assert_equal(-125, @font.underline_position)
94
+ end
95
+
96
+ it "returns the underline thickness" do
97
+ assert_equal(50, @font.underline_thickness)
98
+ end
99
+
100
+ it "returns the strikeout position" do
101
+ assert_equal(256, @font.strikeout_position)
102
+ end
103
+
104
+ it "returns the strikeout thickness" do
105
+ assert_equal(48, @font.strikeout_thickness)
106
+ end
91
107
  end
92
108
 
93
109
  it "is able to return the ID of the missing glyph" do
@@ -71,4 +71,34 @@ describe HexaPDF::Font::Type1::Font do
71
71
  assert_equal([:kern, :liga].to_set, FONT_TIMES.features)
72
72
  assert(FONT_SYMBOL.features.empty?)
73
73
  end
74
+
75
+ describe "underline properties" do
76
+ before do
77
+ @font.metrics.underline_position = -100
78
+ @font.metrics.underline_thickness = 50
79
+ end
80
+
81
+ it "returns the underline position" do
82
+ assert_equal(-75, @font.underline_position)
83
+ end
84
+
85
+ it "returns the underline thickness" do
86
+ assert_equal(50, @font.underline_thickness)
87
+ end
88
+ end
89
+
90
+ describe "strikeout properties" do
91
+ it "returns the strikeout position" do
92
+ assert_equal(225, @font.strikeout_position)
93
+ end
94
+
95
+ it "returns the strikeout thickness" do
96
+ assert_equal(50, @font.strikeout_thickness)
97
+
98
+ emdash = HexaPDF::Font::Type1::CharacterMetrics.new
99
+ emdash.bbox = [0, 200, 1000, 240]
100
+ @font.metrics.character_metrics[:emdash] = emdash
101
+ assert_equal(40, @font.strikeout_thickness)
102
+ end
103
+ end
74
104
  end
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/font_loader'
5
+ require 'hexapdf/document'
6
+
7
+ describe HexaPDF::FontLoader::FromFile do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @font_file = File.join(TEST_DATA_DIR, "fonts", "Ubuntu-Title.ttf")
11
+ @klass = HexaPDF::FontLoader::FromFile
12
+ end
13
+
14
+ it "loads the specified font file" do
15
+ wrapper = @klass.call(@doc, @font_file)
16
+ assert_equal("Ubuntu-Title", wrapper.wrapped_font.font_name)
17
+ end
18
+
19
+ it "passes the subset value to the wrapper" do
20
+ wrapper = @klass.call(@doc, @font_file)
21
+ assert(wrapper.subset?)
22
+ wrapper = @klass.call(@doc, @font_file, subset: false)
23
+ refute(wrapper.subset?)
24
+ end
25
+
26
+ it "returns nil if the given name doesn't represent a file" do
27
+ assert_nil(@klass.call(@doc, "Unknown"))
28
+ end
29
+ end
@@ -7,16 +7,17 @@ require 'hexapdf/document'
7
7
  describe HexaPDF::FontLoader::Standard14 do
8
8
  before do
9
9
  @doc = HexaPDF::Document.new
10
+ @obj = HexaPDF::FontLoader::Standard14
10
11
  end
11
12
 
12
13
  it "loads the font if it is a standard PDF built-in font" do
13
- wrapper = @doc.fonts.load("Times")
14
+ wrapper = @obj.call(@doc, "Times")
14
15
  assert_equal("Times-Roman", wrapper.wrapped_font.font_name)
15
- wrapper = @doc.fonts.load("Helvetica", variant: :bold)
16
+ wrapper = @obj.call(@doc, "Helvetica", variant: :bold)
16
17
  assert_equal("Helvetica-Bold", wrapper.wrapped_font.font_name)
17
18
  end
18
19
 
19
20
  it "returns nil for unknown fonts" do
20
- assert_nil(HexaPDF::FontLoader::Standard14.call(@doc, "Unknown"))
21
+ assert_nil(@obj.call(@doc, "Unknown"))
21
22
  end
22
23
  end
@@ -0,0 +1,104 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require_relative '../content/common'
5
+ require 'hexapdf/document'
6
+ require 'hexapdf/layout/box'
7
+
8
+ describe HexaPDF::Layout::Box do
9
+ def create_box(*args, &block)
10
+ HexaPDF::Layout::Box.new(*args, &block)
11
+ end
12
+
13
+ describe "initialize" do
14
+ it "takes content width and height" do
15
+ box = create_box(content_width: 100, content_height: 200)
16
+ assert_equal(100, box.content_width)
17
+ assert_equal(200, box.content_height)
18
+ end
19
+
20
+ it "takes box width and height" do
21
+ box = create_box(width: 100, height: 200)
22
+ assert_equal(100, box.content_width)
23
+ assert_equal(200, box.content_height)
24
+
25
+ box = create_box(width: 100, height: 200, style: {padding: [20, 10], border: {width: [10, 5]}})
26
+ assert_equal(70, box.content_width)
27
+ assert_equal(140, box.content_height)
28
+ end
29
+
30
+ it "allows passing a Style object or a hash" do
31
+ box = create_box(style: {padding: 20})
32
+ assert_equal(20, box.style.padding.top)
33
+
34
+ box = create_box(style: HexaPDF::Layout::Style.new(padding: 20))
35
+ assert_equal(20, box.style.padding.top)
36
+ end
37
+ end
38
+
39
+ it "returns the full width and height of the box" do
40
+ box = create_box(content_width: 100, content_height: 200,
41
+ style: {padding: [20, 10], border: {width: [10, 5]}})
42
+ assert_equal(130, box.width)
43
+ assert_equal(260, box.height)
44
+ end
45
+
46
+ describe "draw" do
47
+ it "draws the box onto the canvas" do
48
+ box = create_box(content_width: 100, content_height: 100) do |canvas, _|
49
+ canvas.line_width(15)
50
+ end
51
+ box.style.background_color = 0.5
52
+ box.style.border(width: 5)
53
+ box.style.padding([10, 20])
54
+ box.style.underlays.add {|canvas, _| canvas.line_width(10) }
55
+ box.style.overlays.add {|canvas, _| canvas.line_width(20) }
56
+
57
+ @canvas = HexaPDF::Document.new.pages.add.canvas
58
+ box.draw(@canvas, 5, 5)
59
+ assert_operators(@canvas.contents, [[:save_graphics_state],
60
+ [:set_device_gray_non_stroking_color, [0.5]],
61
+ [:append_rectangle, [5, 5, 150, 130]],
62
+ [:fill_path_non_zero],
63
+ [:restore_graphics_state],
64
+ [:save_graphics_state],
65
+ [:concatenate_matrix, [1, 0, 0, 1, 5, 5]],
66
+ [:save_graphics_state],
67
+ [:set_line_width, [10]],
68
+ [:restore_graphics_state],
69
+ [:restore_graphics_state],
70
+ [:save_graphics_state],
71
+ [:set_line_width, [5]],
72
+ [:append_rectangle, [7.5, 7.5, 145, 125]],
73
+ [:stroke_path],
74
+ [:restore_graphics_state],
75
+ [:save_graphics_state],
76
+ [:concatenate_matrix, [1, 0, 0, 1, 30, 20]],
77
+ [:set_line_width, [15]],
78
+ [:restore_graphics_state],
79
+ [:save_graphics_state],
80
+ [:concatenate_matrix, [1, 0, 0, 1, 5, 5]],
81
+ [:save_graphics_state],
82
+ [:set_line_width, [20]],
83
+ [:restore_graphics_state],
84
+ [:restore_graphics_state]])
85
+ end
86
+
87
+ it "draws nothing onto the canvas if the box is empty" do
88
+ @canvas = HexaPDF::Document.new.pages.add.canvas
89
+ create_box.draw(@canvas, 5, 5)
90
+ assert_operators(@canvas.contents, [])
91
+ end
92
+ end
93
+
94
+ describe "empty?" do
95
+ it "is only empty when no drawing operation is specified" do
96
+ assert(create_box.empty?)
97
+ refute(create_box {}.empty?)
98
+ refute(create_box(style: {background_color: [5]}).empty?)
99
+ refute(create_box(style: {border: {width: 1}}).empty?)
100
+ refute(create_box(style: {underlays: [proc {}]}).empty?)
101
+ refute(create_box(style: {overlays: [proc {}]}).empty?)
102
+ end
103
+ end
104
+ end
@@ -5,36 +5,50 @@ require 'hexapdf/layout/inline_box'
5
5
 
6
6
  describe HexaPDF::Layout::InlineBox do
7
7
  before do
8
- @box = HexaPDF::Layout::InlineBox.new(10, 15) {|box, canvas| [box, canvas]}
8
+ @box = HexaPDF::Layout::InlineBox.create(width: 10, height: 15, style: {margin: [15, 10]})
9
9
  end
10
10
 
11
- describe "draw" do
12
- before do
13
- @canvas = Object.new
14
- @canvas.define_singleton_method(:translate) {|x, y, &block| [x, y, block.call] }
11
+ it "draws the wrapped box at the correct position" do
12
+ canvas = Object.new
13
+ block = ->(c, x, y) do
14
+ assert_equal(canvas, c)
15
+ assert_equal(10, x)
16
+ assert_equal(15, y)
15
17
  end
16
-
17
- it "returns the value of the drawing block" do
18
- assert_equal([1, 2, [@box, @canvas]], @box.draw(@canvas, 1, 2))
18
+ @box.box.stub(:draw, block) do
19
+ @box.draw(canvas, 0, 0)
19
20
  end
20
21
  end
21
22
 
23
+ it "returns true if the inline box is empty with no drawing operations" do
24
+ assert(@box.empty?)
25
+ refute(HexaPDF::Layout::InlineBox.create(width: 10, height: 15) {}.empty?)
26
+ end
27
+
22
28
  describe "valign" do
23
29
  it "has a default value of :baseline" do
24
30
  assert_equal(:baseline, @box.valign)
25
31
  end
26
32
 
27
33
  it "can be changed on creation" do
28
- box = HexaPDF::Layout::InlineBox.new(10, 15, valign: :test) {}
34
+ box = HexaPDF::Layout::InlineBox.create(width: 10, height: 15, valign: :test)
29
35
  assert_equal(:test, box.valign)
30
36
  end
31
37
  end
32
38
 
39
+ it "returns the width including margins" do
40
+ assert_equal(30, @box.width)
41
+ end
42
+
43
+ it "returns the height including margins" do
44
+ assert_equal(45, @box.height)
45
+ end
46
+
33
47
  it "returns 0 for x_min" do
34
48
  assert_equal(0, @box.x_min)
35
49
  end
36
50
 
37
51
  it "returns width for x_max" do
38
- assert_equal(10, @box.x_max)
52
+ assert_equal(@box.width, @box.x_max)
39
53
  end
40
54
  end
@@ -3,25 +3,25 @@
3
3
  require 'test_helper'
4
4
  require 'hexapdf/document'
5
5
 
6
- describe HexaPDF::Layout::LineFragment::HeightCalculator do
6
+ describe HexaPDF::Layout::Line::HeightCalculator do
7
7
  before do
8
- @calc = HexaPDF::Layout::LineFragment::HeightCalculator.new
8
+ @calc = HexaPDF::Layout::Line::HeightCalculator.new
9
9
  end
10
10
 
11
11
  it "simulate the height as if an item was added" do
12
- @calc << HexaPDF::Layout::InlineBox.new(10, 20, valign: :baseline) {}
12
+ @calc << HexaPDF::Layout::InlineBox.create(width: 10, height: 20, valign: :baseline) {}
13
13
  assert_equal([0, 20, 0, 0], @calc.result)
14
- new_item = HexaPDF::Layout::InlineBox.new(10, 30, valign: :top) {}
14
+ new_item = HexaPDF::Layout::InlineBox.create(width: 10, height: 30, valign: :top) {}
15
15
  assert_equal(30, @calc.simulate_height(new_item))
16
16
  assert_equal([0, 20, 0, 0], @calc.result)
17
17
  end
18
18
  end
19
19
 
20
- describe HexaPDF::Layout::LineFragment do
20
+ describe HexaPDF::Layout::Line do
21
21
  before do
22
22
  @doc = HexaPDF::Document.new
23
- @font = @doc.fonts.load("Times", custom_encoding: true)
24
- @line = HexaPDF::Layout::LineFragment.new
23
+ @font = @doc.fonts.add("Times", custom_encoding: true)
24
+ @line = HexaPDF::Layout::Line.new
25
25
  end
26
26
 
27
27
  def setup_fragment(text)
@@ -29,14 +29,14 @@ describe HexaPDF::Layout::LineFragment do
29
29
  end
30
30
 
31
31
  def setup_box(width, height, valign = :baseline)
32
- HexaPDF::Layout::InlineBox.new(width, height, valign: valign) {}
32
+ HexaPDF::Layout::InlineBox.create(width: width, height: height, valign: valign) {}
33
33
  end
34
34
 
35
35
  describe "initialize" do
36
36
  it "allows setting the items of the line fragment" do
37
37
  frag1 = setup_fragment("Hello")
38
38
  frag2 = HexaPDF::Layout::TextFragment.new(items: frag1.items.slice!(3, 2), style: frag1.style)
39
- line = HexaPDF::Layout::LineFragment.new([frag1, frag2])
39
+ line = HexaPDF::Layout::Line.new([frag1, frag2])
40
40
  assert_equal(1, line.items.count)
41
41
  assert_equal(5, line.items[0].items.count)
42
42
  end