hexapdf 0.44.0 → 0.46.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +106 -47
- data/examples/019-acro_form.rb +5 -0
- data/examples/027-composer_optional_content.rb +6 -4
- data/examples/030-pdfa.rb +12 -11
- data/lib/hexapdf/cli/inspect.rb +5 -0
- data/lib/hexapdf/composer.rb +23 -1
- data/lib/hexapdf/configuration.rb +8 -0
- data/lib/hexapdf/content/canvas.rb +3 -3
- data/lib/hexapdf/content/canvas_composer.rb +1 -0
- data/lib/hexapdf/digital_signature/cms_handler.rb +31 -3
- data/lib/hexapdf/digital_signature/signing/default_handler.rb +9 -1
- data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +5 -1
- data/lib/hexapdf/document/layout.rb +63 -30
- data/lib/hexapdf/document.rb +24 -2
- data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
- data/lib/hexapdf/importer.rb +15 -5
- data/lib/hexapdf/layout/box.rb +48 -36
- data/lib/hexapdf/layout/column_box.rb +3 -11
- data/lib/hexapdf/layout/container_box.rb +4 -4
- data/lib/hexapdf/layout/frame.rb +7 -6
- data/lib/hexapdf/layout/inline_box.rb +17 -23
- data/lib/hexapdf/layout/list_box.rb +27 -42
- data/lib/hexapdf/layout/page_style.rb +23 -16
- data/lib/hexapdf/layout/style.rb +5 -5
- data/lib/hexapdf/layout/table_box.rb +14 -10
- data/lib/hexapdf/layout/text_box.rb +60 -36
- data/lib/hexapdf/layout/text_fragment.rb +1 -1
- data/lib/hexapdf/layout/text_layouter.rb +7 -8
- data/lib/hexapdf/parser.rb +5 -1
- data/lib/hexapdf/rectangle.rb +4 -4
- data/lib/hexapdf/revisions.rb +1 -1
- data/lib/hexapdf/stream.rb +3 -3
- data/lib/hexapdf/tokenizer.rb +3 -2
- data/lib/hexapdf/type/acro_form/button_field.rb +2 -0
- data/lib/hexapdf/type/acro_form/choice_field.rb +2 -0
- data/lib/hexapdf/type/acro_form/field.rb +8 -0
- data/lib/hexapdf/type/acro_form/form.rb +2 -1
- data/lib/hexapdf/type/acro_form/text_field.rb +2 -0
- data/lib/hexapdf/type/form.rb +2 -2
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/content/test_canvas_composer.rb +13 -8
- data/test/hexapdf/digital_signature/common.rb +66 -84
- data/test/hexapdf/digital_signature/signing/test_default_handler.rb +7 -0
- data/test/hexapdf/digital_signature/signing/test_signed_data_creator.rb +9 -0
- data/test/hexapdf/digital_signature/test_cms_handler.rb +41 -1
- data/test/hexapdf/digital_signature/test_handler.rb +2 -1
- data/test/hexapdf/document/test_layout.rb +44 -5
- data/test/hexapdf/layout/test_box.rb +23 -5
- data/test/hexapdf/layout/test_frame.rb +21 -2
- data/test/hexapdf/layout/test_inline_box.rb +17 -28
- data/test/hexapdf/layout/test_list_box.rb +8 -8
- data/test/hexapdf/layout/test_page_style.rb +7 -2
- data/test/hexapdf/layout/test_table_box.rb +8 -1
- data/test/hexapdf/layout/test_text_box.rb +51 -29
- data/test/hexapdf/layout/test_text_layouter.rb +0 -3
- data/test/hexapdf/test_composer.rb +14 -5
- data/test/hexapdf/test_document.rb +27 -0
- data/test/hexapdf/test_importer.rb +17 -0
- data/test/hexapdf/test_revisions.rb +54 -41
- data/test/hexapdf/test_serializer.rb +1 -0
- data/test/hexapdf/type/acro_form/test_form.rb +9 -0
- metadata +2 -2
@@ -77,9 +77,9 @@ module HexaPDF
|
|
77
77
|
#
|
78
78
|
# One style property, Layout::Style#font, is handled specially:
|
79
79
|
#
|
80
|
-
# * If no font is set on a style, the font
|
81
|
-
#
|
82
|
-
# valid default value).
|
80
|
+
# * If no font is set on a style, the default font specified via the configuration option
|
81
|
+
# 'font.default' is automatically set because otherwise there would be problems with text
|
82
|
+
# drawing operations (font is the only style property that has no valid default value).
|
83
83
|
#
|
84
84
|
# * Standard style objects only allow font wrapper objects to be set via the Layout::Style#font
|
85
85
|
# method. This class makes usage easier by allowing strings or an array [name, options_hash]
|
@@ -151,7 +151,9 @@ module HexaPDF
|
|
151
151
|
# :nodoc:
|
152
152
|
def method_missing(name, *args, **kwargs, &block)
|
153
153
|
if @layout.box_creation_method?(name)
|
154
|
-
|
154
|
+
box = @layout.send(name, *args, **kwargs, &block)
|
155
|
+
@children << box
|
156
|
+
box
|
155
157
|
else
|
156
158
|
super
|
157
159
|
end
|
@@ -175,9 +177,6 @@ module HexaPDF
|
|
175
177
|
|
176
178
|
end
|
177
179
|
|
178
|
-
# The mapping of style name (a Symbol) to Layout::Style instance.
|
179
|
-
attr_reader :styles
|
180
|
-
|
181
180
|
# Creates a new Layout object for the given PDF document.
|
182
181
|
def initialize(document)
|
183
182
|
@document = document
|
@@ -219,6 +218,21 @@ module HexaPDF
|
|
219
218
|
style
|
220
219
|
end
|
221
220
|
|
221
|
+
# :call-seq:
|
222
|
+
# layout.styles -> styles
|
223
|
+
# layout.styles(**mapping) -> styles
|
224
|
+
#
|
225
|
+
# Returns the mapping of style names to Layout::Style instances. If +mapping+ is provided,
|
226
|
+
# also defines the given styles using #style.
|
227
|
+
#
|
228
|
+
# The argument +mapping+ needs to be a hash mapping a style name (a Symbol) to style
|
229
|
+
# properties. The special key +:base+ can be used to define the base style. For details see
|
230
|
+
# #style.
|
231
|
+
def styles(**mapping)
|
232
|
+
mapping.each {|name, properties| style(name, **properties) } unless mapping.empty?
|
233
|
+
@styles
|
234
|
+
end
|
235
|
+
|
222
236
|
# Creates an inline box for use together with text fragments.
|
223
237
|
#
|
224
238
|
# The +valign+ argument ist used to specify the vertical alignment of the box within the text
|
@@ -342,6 +356,7 @@ module HexaPDF
|
|
342
356
|
width: width, height: height, properties: properties,
|
343
357
|
style: box_style)
|
344
358
|
end
|
359
|
+
alias text text_box
|
345
360
|
|
346
361
|
# Creates a HexaPDF::Layout::TextBox like #text_box but allows parts of the text to be
|
347
362
|
# formatted differently.
|
@@ -444,6 +459,7 @@ module HexaPDF
|
|
444
459
|
box_class_for_name(:text).new(items: data, width: width, height: height,
|
445
460
|
properties: properties, style: box_style)
|
446
461
|
end
|
462
|
+
alias formatted_text formatted_text_box
|
447
463
|
|
448
464
|
# Creates a HexaPDF::Layout::ImageBox for the given image.
|
449
465
|
#
|
@@ -465,6 +481,7 @@ module HexaPDF
|
|
465
481
|
box_class_for_name(:image).new(image: image, width: width, height: height,
|
466
482
|
properties: properties, style: style)
|
467
483
|
end
|
484
|
+
alias image image_box
|
468
485
|
|
469
486
|
# This helper class is used by Layout#table_box to allow specifying the keyword arguments used
|
470
487
|
# when converting cell data to box instances.
|
@@ -483,8 +500,25 @@ module HexaPDF
|
|
483
500
|
@number_of_columns = number_of_columns
|
484
501
|
end
|
485
502
|
|
486
|
-
# Stores the
|
487
|
-
#
|
503
|
+
# Stores the hash +args+ containing styling properties for the cells specified via the given
|
504
|
+
# 0-based rows and columns.
|
505
|
+
#
|
506
|
+
# Rows and columns can either be single numbers, ranges of numbers or stepped ranges (i.e.
|
507
|
+
# Enumerator::ArithmeticSequence instances).
|
508
|
+
#
|
509
|
+
# Examples:
|
510
|
+
#
|
511
|
+
# # Gray background for all cells
|
512
|
+
# args[] = {cell: {background_color: "gray"}}
|
513
|
+
#
|
514
|
+
# # Cell at (2, 3) gets a bigger font size
|
515
|
+
# args[2, 3] = {font_size: 50}
|
516
|
+
#
|
517
|
+
# # First column of every row has bold font
|
518
|
+
# args[0..-1, 0] = {font: 'Helvetica bold'}
|
519
|
+
#
|
520
|
+
# # Every second row has a blue background
|
521
|
+
# args[(0..-1).step(2)] = {cell: {background_color: "blue"}}
|
488
522
|
def []=(rows = 0..-1, cols = 0..-1, args)
|
489
523
|
rows = adjust_range(rows.kind_of?(Integer) ? rows..rows : rows, @number_of_rows)
|
490
524
|
cols = adjust_range(cols.kind_of?(Integer) ? cols..cols : cols, @number_of_columns)
|
@@ -497,7 +531,7 @@ module HexaPDF
|
|
497
531
|
# is merged.
|
498
532
|
def retrieve_arguments_for(row, col)
|
499
533
|
@argument_infos.each_with_object({}) do |arg_info, result|
|
500
|
-
next unless arg_info.rows.
|
534
|
+
next unless arg_info.rows.include?(row) && arg_info.cols.include?(col)
|
501
535
|
if arg_info.args[:cell]
|
502
536
|
arg_info.args[:cell] = (result[:cell] || {}).merge(arg_info.args[:cell])
|
503
537
|
end
|
@@ -510,7 +544,8 @@ module HexaPDF
|
|
510
544
|
# Adjusts the +range+ so that both the begin and the end of the range are zero or positive
|
511
545
|
# integers smaller than +max+.
|
512
546
|
def adjust_range(range, max)
|
513
|
-
(range.begin % max)..(range.end % max)
|
547
|
+
r = (range.begin % max)..(range.end % max)
|
548
|
+
range.kind_of?(Range) ? r : r.step(range.step)
|
514
549
|
end
|
515
550
|
|
516
551
|
end
|
@@ -528,7 +563,8 @@ module HexaPDF
|
|
528
563
|
# Additional arguments for the #text_box invocations can be specified using the optional block
|
529
564
|
# that yields a CellArgumentCollector instance. This allows customization of the text boxes.
|
530
565
|
# By specifying the special key +:cell+ it is also possible to assign style properties to the
|
531
|
-
# cells themselves.
|
566
|
+
# cells themselves, irrespective of the type of content of the cells. See
|
567
|
+
# CellArgumentCollector#[]= for details.
|
532
568
|
#
|
533
569
|
# See HexaPDF::Layout::TableBox::new for details on +column_widths+, +header+, +footer+, and
|
534
570
|
# +cell_style+.
|
@@ -574,6 +610,7 @@ module HexaPDF
|
|
574
610
|
footer: footer, cell_style: cell_style, width: width,
|
575
611
|
height: height, properties: properties, style: style)
|
576
612
|
end
|
613
|
+
alias table table_box
|
577
614
|
|
578
615
|
LOREM_IPSUM = [ # :nodoc:
|
579
616
|
"Lorem ipsum dolor sit amet, con\u{00AD}sectetur adipis\u{00AD}cing elit, sed " \
|
@@ -593,22 +630,13 @@ module HexaPDF
|
|
593
630
|
def lorem_ipsum_box(sentences: 4, count: 1, **text_box_properties)
|
594
631
|
text_box(([LOREM_IPSUM[0, sentences].join(" ")] * count).join("\n\n"), **text_box_properties)
|
595
632
|
end
|
633
|
+
alias lorem_ipsum lorem_ipsum_box
|
596
634
|
|
597
|
-
|
598
|
-
|
599
|
-
# Allows creating boxes using more convenient method names:
|
600
|
-
#
|
601
|
-
# * #text for #text_box
|
602
|
-
# * #formatted_text for #formatted_text_box
|
603
|
-
# * #image for #image_box
|
604
|
-
# * #lorem_ipsum for #lorem_ipsum_box
|
605
|
-
# * The name of a pre-defined box class like #column will invoke #box appropriately. Same if
|
606
|
-
# used with a '_box' suffix.
|
635
|
+
# Allows creating boxes using more convenient method names: The name of a pre-defined box
|
636
|
+
# class like #column will invoke #box appropriately. Same if used with a '_box' suffix.
|
607
637
|
def method_missing(name, *args, **kwargs, &block)
|
608
638
|
name_without_box = name.to_s.sub(/_box$/, '').intern
|
609
|
-
if
|
610
|
-
send("#{name}_box", *args, **kwargs, &block)
|
611
|
-
elsif @document.config['layout.boxes.map'].key?(name_without_box)
|
639
|
+
if @document.config['layout.boxes.map'].key?(name_without_box)
|
612
640
|
box(name_without_box, *args, **kwargs, &block)
|
613
641
|
else
|
614
642
|
super
|
@@ -620,6 +648,8 @@ module HexaPDF
|
|
620
648
|
box_creation_method?(name) || super
|
621
649
|
end
|
622
650
|
|
651
|
+
BOX_METHOD_NAMES = [:text, :formatted_text, :image, :table, :lorem_ipsum] #:nodoc:
|
652
|
+
|
623
653
|
# :nodoc:
|
624
654
|
def box_creation_method?(name)
|
625
655
|
name = name.to_s.sub(/_box$/, '').intern
|
@@ -636,8 +666,8 @@ module HexaPDF
|
|
636
666
|
end
|
637
667
|
end
|
638
668
|
|
639
|
-
# Retrieves the appropriate HexaPDF::Layout::Style object based on the +style+ and
|
640
|
-
# arguments.
|
669
|
+
# Retrieves the appropriate HexaPDF::Layout::Style object based on the +style+ and
|
670
|
+
# +properties+ arguments.
|
641
671
|
#
|
642
672
|
# The +style+ argument specifies the style to retrieve. It can either be a registered style
|
643
673
|
# name (see #style), a hash with style properties or +nil+. In the latter case the registered
|
@@ -646,15 +676,18 @@ module HexaPDF
|
|
646
676
|
# If the +properties+ hash is not empty, the retrieved style is duplicated and the properties
|
647
677
|
# hash is applied to it.
|
648
678
|
#
|
649
|
-
# Finally, a default font (the one from the :base style or otherwise
|
650
|
-
# necessary to ensure that the style object
|
679
|
+
# Finally, a default font (the one from the :base style or otherwise the one set using the
|
680
|
+
# configuration option 'font.default') is set if necessary to ensure that the style object
|
681
|
+
# works in all cases.
|
651
682
|
def retrieve_style(style, properties = nil)
|
652
683
|
if style.kind_of?(Symbol) && !@styles.key?(style)
|
653
684
|
raise HexaPDF::Error, "Style #{style} not defined"
|
654
685
|
end
|
655
686
|
style = HexaPDF::Layout::Style.create(@styles[style] || style || @styles[:base])
|
656
687
|
style = style.dup.update(**properties) unless properties.nil? || properties.empty?
|
657
|
-
|
688
|
+
unless style.font?
|
689
|
+
style.font(@styles[:base].font? && @styles[:base].font || @document.config['font.default'])
|
690
|
+
end
|
658
691
|
unless style.font.respond_to?(:pdf_object)
|
659
692
|
name, options = *style.font
|
660
693
|
style.font(@document.fonts.add(name, **(options || {})))
|
data/lib/hexapdf/document.rb
CHANGED
@@ -278,8 +278,9 @@ module HexaPDF
|
|
278
278
|
# If the same argument is provided in multiple invocations, the import is done only once and
|
279
279
|
# the previously imported object is returned.
|
280
280
|
#
|
281
|
-
# Note: If you first create a PDF document from scratch
|
282
|
-
# into another PDF document, you need to run the
|
281
|
+
# Note: If you first create a PDF document from scratch or if you modify an existing document,
|
282
|
+
# and then want to import objects from it into another PDF document, you need to run the
|
283
|
+
# following on the source document:
|
283
284
|
#
|
284
285
|
# doc.dispatch_message(:complete_objects)
|
285
286
|
# doc.validate
|
@@ -701,6 +702,27 @@ module HexaPDF
|
|
701
702
|
result
|
702
703
|
end
|
703
704
|
|
705
|
+
# Returns an in-memory copy of the PDF document.
|
706
|
+
#
|
707
|
+
# In the context of this method this means that the returned PDF document contains the same PDF
|
708
|
+
# object tree as this document, starting at the trailer. A possibly set encryption is not
|
709
|
+
# transferred to the returned document.
|
710
|
+
#
|
711
|
+
# Note: If this PDF document was created from scratch or if it is an existing document that was
|
712
|
+
# modified, the following commands need to be run on this document beforehand:
|
713
|
+
#
|
714
|
+
# doc.dispatch_message(:complete_objects)
|
715
|
+
# doc.validate
|
716
|
+
#
|
717
|
+
# This ensures that all the necessary PDF structures set-up correctly.
|
718
|
+
def duplicate
|
719
|
+
dest = HexaPDF::Document.new
|
720
|
+
dupped_trailer = HexaPDF::Importer.copy(dest, trailer, allow_all: true)
|
721
|
+
dest.revisions.current.trailer.value.replace(dupped_trailer.value)
|
722
|
+
dest.trailer.delete(:Encrypt)
|
723
|
+
dest
|
724
|
+
end
|
725
|
+
|
704
726
|
# :call-seq:
|
705
727
|
# doc.write(filename, incremental: false, validate: true, update_fields: true, optimize: false)
|
706
728
|
# doc.write(io, incremental: false, validate: true, update_fields: true, optimize: false)
|
@@ -51,7 +51,7 @@ module HexaPDF
|
|
51
51
|
attr_accessor :name
|
52
52
|
|
53
53
|
# Character bounding box as array of four numbers, specifying the x- and y-coordinates of
|
54
|
-
# the bottom
|
54
|
+
# the bottom-left corner and the x- and y-coordinates of the top-right corner.
|
55
55
|
attr_accessor :bbox
|
56
56
|
|
57
57
|
end
|
@@ -63,7 +63,7 @@ module HexaPDF
|
|
63
63
|
attr_accessor :weight
|
64
64
|
|
65
65
|
# The font bounding box as array of four numbers, specifying the x- and y-coordinates of the
|
66
|
-
# bottom
|
66
|
+
# bottom-left corner and the x- and y-coordinates of the top-right corner.
|
67
67
|
attr_accessor :bounding_box
|
68
68
|
|
69
69
|
# The y-value of the top of the capital H (or 0 or nil if the font doesn't contain a capital
|
data/lib/hexapdf/importer.rb
CHANGED
@@ -71,14 +71,18 @@ module HexaPDF
|
|
71
71
|
# Imports the given +object+ (belonging to the +source+ document) by completely copying it and
|
72
72
|
# all referenced objects into the +destination+ object.
|
73
73
|
#
|
74
|
+
# If the +allow_all+ argument is set to +true+, then the usually omitted catalog and page tree
|
75
|
+
# node objects (see the class description for details) are also copied which allows one to make
|
76
|
+
# an in-memory duplicate of a HexaPDF::Document object.
|
77
|
+
#
|
74
78
|
# Specifying +source+ is optionial if it can be determined through +object+.
|
75
79
|
#
|
76
80
|
# After the operation is finished, all state is discarded. This means that another call to this
|
77
81
|
# method for the same object will yield a new - and different - object. This is in contrast to
|
78
82
|
# using ::for together with #import which remembers and returns already imported objects (which
|
79
83
|
# is generally what one wants).
|
80
|
-
def self.copy(destination, object, source: nil)
|
81
|
-
new(NullableWeakRef.new(destination)).import(object, source: source)
|
84
|
+
def self.copy(destination, object, allow_all: false, source: nil)
|
85
|
+
new(NullableWeakRef.new(destination), allow_all: allow_all).import(object, source: source)
|
82
86
|
end
|
83
87
|
|
84
88
|
private_class_method :new
|
@@ -86,9 +90,10 @@ module HexaPDF
|
|
86
90
|
attr_reader :destination #:nodoc:
|
87
91
|
|
88
92
|
# Initializes a new importer that can import objects to the +destination+ document.
|
89
|
-
def initialize(destination)
|
93
|
+
def initialize(destination, allow_all: false)
|
90
94
|
@destination = destination
|
91
95
|
@mapper = {}
|
96
|
+
@allow_all = allow_all
|
92
97
|
end
|
93
98
|
|
94
99
|
SourceWrapper = Struct.new(:source) #:nodoc:
|
@@ -136,7 +141,7 @@ module HexaPDF
|
|
136
141
|
internal_import(wrapper.source.object(object), wrapper)
|
137
142
|
when HexaPDF::Object
|
138
143
|
wrapper.source ||= object.document
|
139
|
-
if object.type == :Catalog || object.type == :Pages
|
144
|
+
if !@allow_all && (object.type == :Catalog || object.type == :Pages)
|
140
145
|
@mapper[object.data] = nil
|
141
146
|
elsif (mapped_object = @mapper[object.data]&.__getobj__) && !mapped_object.null?
|
142
147
|
mapped_object
|
@@ -149,7 +154,12 @@ module HexaPDF
|
|
149
154
|
obj.data.gen = 0
|
150
155
|
@destination.add(obj) if object.indirect?
|
151
156
|
|
152
|
-
|
157
|
+
stream = obj.data.stream
|
158
|
+
if stream.kind_of?(String)
|
159
|
+
obj.data.stream = stream.dup
|
160
|
+
elsif stream&.source.kind_of?(FiberDoubleForString)
|
161
|
+
obj.data.stream = stream.fiber.resume.dup
|
162
|
+
end
|
153
163
|
obj.data.value = duplicate(obj.data.value, wrapper)
|
154
164
|
obj.data.value.update(duplicate(object.copy_inherited_values, wrapper)) if object.type == :Page
|
155
165
|
obj
|
data/lib/hexapdf/layout/box.rb
CHANGED
@@ -69,6 +69,10 @@ module HexaPDF
|
|
69
69
|
# If the subclass supports the value :flow of the 'position' style property, this method
|
70
70
|
# needs to be overridden to return +true+.
|
71
71
|
#
|
72
|
+
# Additionally, if a box object uses flow positioning, #fit_result.x should be set to the
|
73
|
+
# correct value since Frame#fit can't determine this and uses Frame#left in the absence of a
|
74
|
+
# set value.
|
75
|
+
#
|
72
76
|
# #empty?::
|
73
77
|
# This method should return +true+ if the subclass won't draw anything when #draw is called.
|
74
78
|
#
|
@@ -89,28 +93,13 @@ module HexaPDF
|
|
89
93
|
# This method draws the box specific content and is called from #draw which already handles
|
90
94
|
# things like drawing the border and background. So #draw should usually not be overridden.
|
91
95
|
#
|
92
|
-
# This base class provides various
|
93
|
-
#
|
94
|
-
# +reserved_width+, +reserved_height+::
|
95
|
-
# Returns the width respectively the height of the reserved space inside the box that is
|
96
|
-
# used for the border and padding.
|
97
|
-
#
|
98
|
-
# +reserved_width_left+, +reserved_width_right+, +reserved_height_top+,
|
99
|
-
# +reserved_height_bottom+::
|
100
|
-
# Returns the reserved space inside the box at the specified edge (left, right, top,
|
101
|
-
# bottom).
|
102
|
-
#
|
103
|
-
# +update_content_width+, +update_content_height+::
|
104
|
-
# Takes a block that should return the content width respectively height and sets the box's
|
105
|
-
# width respectively height accordingly.
|
106
|
-
#
|
107
|
-
# +create_split_box+::
|
108
|
-
# Creates a new box based on this one and resets the internal data back to their original
|
109
|
-
# values.
|
96
|
+
# This base class also provides various protected helper methods for use in the above methods:
|
110
97
|
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
98
|
+
# * #reserved_width, #reserved_height
|
99
|
+
# * #reserved_width_left, #reserved_width_right, #reserved_height_top,
|
100
|
+
# #reserved_height_bottom
|
101
|
+
# * #update_content_width, #update_content_height
|
102
|
+
# * #create_split_box
|
114
103
|
class Box
|
115
104
|
|
116
105
|
include HexaPDF::Utils
|
@@ -323,10 +312,12 @@ module HexaPDF
|
|
323
312
|
# current region of the frame, adjusted for this box. The frame itself is provided as third
|
324
313
|
# argument.
|
325
314
|
#
|
326
|
-
#
|
327
|
-
#
|
328
|
-
#
|
329
|
-
#
|
315
|
+
# If the box uses flow positioning, the width is set to the frame's width and the height to
|
316
|
+
# the remaining height in the frame. Otherwise the given available width and height are used
|
317
|
+
# for the width and height if they were initially set to 0. Otherwise the intially specified
|
318
|
+
# dimensions are used. The method returns early if the thus configured box already doesn't
|
319
|
+
# fit. Otherwise, the #fit_content method is called which allows sub-classes to fit their
|
320
|
+
# content.
|
330
321
|
#
|
331
322
|
# The following variables are set that may later be used during splitting or drawing:
|
332
323
|
#
|
@@ -334,10 +325,25 @@ module HexaPDF
|
|
334
325
|
# used to adjust the drawing position in #draw_content if necessary.
|
335
326
|
def fit(available_width, available_height, frame)
|
336
327
|
@fit_result.reset(frame)
|
337
|
-
|
338
|
-
@
|
339
|
-
|
340
|
-
|
328
|
+
position_flow = supports_position_flow? && style.position == :flow
|
329
|
+
@width = if @initial_width > 0
|
330
|
+
@initial_width
|
331
|
+
elsif position_flow
|
332
|
+
frame.width
|
333
|
+
else
|
334
|
+
available_width
|
335
|
+
end
|
336
|
+
@height = if @initial_height > 0
|
337
|
+
@initial_height
|
338
|
+
elsif position_flow
|
339
|
+
frame.y - frame.bottom
|
340
|
+
else
|
341
|
+
available_height
|
342
|
+
end
|
343
|
+
return @fit_result if !position_flow && (float_compare(@width, available_width) > 0 ||
|
344
|
+
float_compare(@height, available_height) > 0 ||
|
345
|
+
@width - reserved_width < 0 ||
|
346
|
+
@height - reserved_height < 0)
|
341
347
|
|
342
348
|
fit_content(available_width, available_height, frame)
|
343
349
|
|
@@ -379,7 +385,7 @@ module HexaPDF
|
|
379
385
|
# system is translated so that the origin is at the bottom left corner of the **content box**.
|
380
386
|
#
|
381
387
|
# Subclasses should not rely on the +@draw_block+ but implement the #draw_content method. The
|
382
|
-
# coordinates passed to it are also modified to represent the bottom
|
388
|
+
# coordinates passed to it are also modified to represent the bottom-left corner of the
|
383
389
|
# content box but the coordinate system is not translated.
|
384
390
|
def draw(canvas, x, y)
|
385
391
|
if @fit_result.overflow? && @initial_height > 0 && style.overflow == :error
|
@@ -417,7 +423,7 @@ module HexaPDF
|
|
417
423
|
(style.overlays? && !style.overlays.none?))
|
418
424
|
end
|
419
425
|
|
420
|
-
|
426
|
+
protected
|
421
427
|
|
422
428
|
# Returns the width that is reserved by the padding and border style properties.
|
423
429
|
def reserved_width
|
@@ -465,12 +471,18 @@ module HexaPDF
|
|
465
471
|
result
|
466
472
|
end
|
467
473
|
|
474
|
+
# :call-seq:
|
475
|
+
# update_content_width { block }
|
476
|
+
#
|
468
477
|
# Updates the width of the box using the content width returned by the block.
|
469
478
|
def update_content_width
|
470
479
|
return if @initial_width > 0
|
471
480
|
@width = yield + reserved_width
|
472
481
|
end
|
473
482
|
|
483
|
+
# :call-seq:
|
484
|
+
# update_content_height { block }
|
485
|
+
#
|
474
486
|
# Updates the height of the box using the content height returned by the block.
|
475
487
|
def update_content_height
|
476
488
|
return if @initial_height > 0
|
@@ -479,13 +491,12 @@ module HexaPDF
|
|
479
491
|
|
480
492
|
# Fits the content of the box and returns whether fitting was successful.
|
481
493
|
#
|
482
|
-
# This is just a stub implementation that sets the #fit_result status to success
|
483
|
-
#
|
484
|
-
# specific behaviour.
|
494
|
+
# This is just a stub implementation that sets the #fit_result status to success. Subclasses
|
495
|
+
# should override it to provide the box specific behaviour.
|
485
496
|
#
|
486
497
|
# See #fit for details.
|
487
498
|
def fit_content(_available_width, _available_height, _frame)
|
488
|
-
fit_result.success!
|
499
|
+
fit_result.success!
|
489
500
|
end
|
490
501
|
|
491
502
|
# Splits the content of the box.
|
@@ -510,7 +521,8 @@ module HexaPDF
|
|
510
521
|
end
|
511
522
|
end
|
512
523
|
|
513
|
-
# Creates a new box based on this one and resets the data back to their original
|
524
|
+
# Creates a new box based on this one and resets the internal data back to their original
|
525
|
+
# values.
|
514
526
|
#
|
515
527
|
# The variable +@split_box+ is set to +split_box_value+ (defaults to +true+) to make the new
|
516
528
|
# box aware that it is a split box. If needed, subclasses can set the variable to other truthy
|
@@ -142,19 +142,11 @@ module HexaPDF
|
|
142
142
|
|
143
143
|
# Fits the column box into the current region of the frame.
|
144
144
|
#
|
145
|
-
def fit_content(
|
145
|
+
def fit_content(_available_width, _available_height, frame)
|
146
146
|
initial_fit_successful = (@equal_height && @columns.size > 1 ? nil : false)
|
147
147
|
tries = 0
|
148
|
-
width =
|
149
|
-
|
150
|
-
else
|
151
|
-
(@initial_width > 0 ? @initial_width : available_width) - reserved_width
|
152
|
-
end
|
153
|
-
height = if style.position == :flow
|
154
|
-
(@initial_height > 0 ? @initial_height : frame.y - frame.bottom) - reserved_height
|
155
|
-
else
|
156
|
-
(@initial_height > 0 ? @initial_height : available_height) - reserved_height
|
157
|
-
end
|
148
|
+
width = @width - reserved_width
|
149
|
+
height = @height - reserved_height
|
158
150
|
|
159
151
|
columns = calculate_columns(width)
|
160
152
|
return if columns.empty?
|
@@ -52,7 +52,7 @@ module HexaPDF
|
|
52
52
|
# setting the style properties 'mask_mode', 'align' and 'valign', it is possible to lay out the
|
53
53
|
# children bottom to top, left to right, or right to left:
|
54
54
|
#
|
55
|
-
# * The standard top
|
55
|
+
# * The standard top-to-bottom layout:
|
56
56
|
#
|
57
57
|
# #>pdf-composer100
|
58
58
|
# composer.container do |container|
|
@@ -61,7 +61,7 @@ module HexaPDF
|
|
61
61
|
# container.box(:base, height: 20, style: {background_color: "hp-blue-light"})
|
62
62
|
# end
|
63
63
|
#
|
64
|
-
# * The bottom
|
64
|
+
# * The bottom-to-top layout (using valign = :bottom to fill up from the bottom and mask_mode =
|
65
65
|
# :fill_horizontal to only remove the area to the left and right of the box):
|
66
66
|
#
|
67
67
|
# #>pdf-composer100
|
@@ -74,7 +74,7 @@ module HexaPDF
|
|
74
74
|
# mask_mode: :fill_horizontal, valign: :bottom})
|
75
75
|
# end
|
76
76
|
#
|
77
|
-
# * The left
|
77
|
+
# * The left-to-right layout (using mask_mode = :fill_vertical to fill the area to the top and
|
78
78
|
# bottom of the box):
|
79
79
|
#
|
80
80
|
# #>pdf-composer100
|
@@ -87,7 +87,7 @@ module HexaPDF
|
|
87
87
|
# mask_mode: :fill_vertical})
|
88
88
|
# end
|
89
89
|
#
|
90
|
-
# * The right
|
90
|
+
# * The right-to-left layout (using align = :right to fill up from the right and mask_mode =
|
91
91
|
# :fill_vertical to fill the area to the top and bottom of the box):
|
92
92
|
#
|
93
93
|
# #>pdf-composer100
|
data/lib/hexapdf/layout/frame.rb
CHANGED
@@ -54,7 +54,7 @@ module HexaPDF
|
|
54
54
|
#
|
55
55
|
# The method #fit is also called for absolutely positioned boxes but since these boxes are not
|
56
56
|
# subject to the normal constraints, the provided available width and height are the width and
|
57
|
-
# height inside the frame to the right and top of the bottom
|
57
|
+
# height inside the frame to the right and top of the bottom-left corner of the box.
|
58
58
|
#
|
59
59
|
# * If the box didn't fit, call #find_next_region to determine the next region for placing the
|
60
60
|
# box. If a new region was found, start over with #fit. Otherwise the frame has no more space
|
@@ -84,10 +84,10 @@ module HexaPDF
|
|
84
84
|
|
85
85
|
include HexaPDF::Utils
|
86
86
|
|
87
|
-
# The x-coordinate of the bottom
|
87
|
+
# The x-coordinate of the bottom-left corner.
|
88
88
|
attr_reader :left
|
89
89
|
|
90
|
-
# The y-coordinate of the bottom
|
90
|
+
# The y-coordinate of the bottom-left corner.
|
91
91
|
attr_reader :bottom
|
92
92
|
|
93
93
|
# The width of the frame.
|
@@ -127,7 +127,7 @@ module HexaPDF
|
|
127
127
|
|
128
128
|
# An array of box objects representing the parent boxes.
|
129
129
|
#
|
130
|
-
# The immediate parent is the last array entry, the top
|
130
|
+
# The immediate parent is the last array entry, the top-most parent the first one. All boxes
|
131
131
|
# that are fitted into this frame have to be child boxes of the immediate parent box.
|
132
132
|
attr_reader :parent_boxes
|
133
133
|
|
@@ -216,6 +216,7 @@ module HexaPDF
|
|
216
216
|
end
|
217
217
|
|
218
218
|
fit_result = box.fit(aw, ah, self)
|
219
|
+
return fit_result if fit_result.failure?
|
219
220
|
|
220
221
|
width = box.width
|
221
222
|
height = box.height
|
@@ -251,7 +252,7 @@ module HexaPDF
|
|
251
252
|
end
|
252
253
|
end
|
253
254
|
when :flow
|
254
|
-
x =
|
255
|
+
x = fit_result.x || left
|
255
256
|
y = @y - height
|
256
257
|
else
|
257
258
|
raise HexaPDF::Error, "Invalid value '#{position}' for style property position"
|
@@ -382,7 +383,7 @@ module HexaPDF
|
|
382
383
|
# Since not all text may start at the top of the frame, the offset argument can be used to
|
383
384
|
# specify a vertical offset from the top of the frame where layouting should start.
|
384
385
|
#
|
385
|
-
# To be compatible with TextLayouter, the top
|
386
|
+
# To be compatible with TextLayouter, the top-left corner of the bounding box of the frame's
|
386
387
|
# shape is the origin of the coordinate system for the width specification, with positive
|
387
388
|
# x-values to the right and positive y-values downwards.
|
388
389
|
#
|