hexapdf 0.22.0 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -0
  3. data/lib/hexapdf/cli/form.rb +26 -3
  4. data/lib/hexapdf/cli/inspect.rb +12 -3
  5. data/lib/hexapdf/cli/modify.rb +23 -3
  6. data/lib/hexapdf/composer.rb +24 -2
  7. data/lib/hexapdf/document/destinations.rb +396 -0
  8. data/lib/hexapdf/document.rb +38 -89
  9. data/lib/hexapdf/layout/frame.rb +8 -9
  10. data/lib/hexapdf/layout/style.rb +280 -7
  11. data/lib/hexapdf/layout/text_box.rb +10 -2
  12. data/lib/hexapdf/layout/text_layouter.rb +6 -1
  13. data/lib/hexapdf/revision.rb +8 -1
  14. data/lib/hexapdf/revisions.rb +151 -50
  15. data/lib/hexapdf/task/optimize.rb +21 -11
  16. data/lib/hexapdf/type/acro_form/text_field.rb +8 -0
  17. data/lib/hexapdf/type/catalog.rb +9 -1
  18. data/lib/hexapdf/type/names.rb +13 -0
  19. data/lib/hexapdf/type/xref_stream.rb +2 -1
  20. data/lib/hexapdf/utils/sorted_tree_node.rb +3 -1
  21. data/lib/hexapdf/version.rb +1 -1
  22. data/lib/hexapdf/writer.rb +15 -2
  23. data/test/hexapdf/document/test_destinations.rb +338 -0
  24. data/test/hexapdf/encryption/test_security_handler.rb +2 -2
  25. data/test/hexapdf/layout/test_frame.rb +15 -1
  26. data/test/hexapdf/layout/test_text_box.rb +16 -0
  27. data/test/hexapdf/layout/test_text_layouter.rb +7 -0
  28. data/test/hexapdf/task/test_optimize.rb +17 -4
  29. data/test/hexapdf/test_composer.rb +24 -1
  30. data/test/hexapdf/test_document.rb +30 -133
  31. data/test/hexapdf/test_parser.rb +1 -1
  32. data/test/hexapdf/test_revision.rb +14 -0
  33. data/test/hexapdf/test_revisions.rb +137 -29
  34. data/test/hexapdf/test_writer.rb +43 -14
  35. data/test/hexapdf/type/acro_form/test_text_field.rb +17 -0
  36. data/test/hexapdf/type/test_catalog.rb +8 -0
  37. data/test/hexapdf/type/test_names.rb +20 -0
  38. data/test/hexapdf/type/test_xref_stream.rb +2 -1
  39. data/test/hexapdf/utils/test_sorted_tree_node.rb +11 -1
  40. metadata +5 -2
@@ -581,9 +581,22 @@ module HexaPDF
581
581
  #
582
582
  # The font to be used, must be set to a valid font wrapper object before it can be used.
583
583
  #
584
+ # HexaPDF::Composer handles this property specially in that it resolves a set string or array
585
+ # to a font wrapper object before doing else with the style object.
586
+ #
584
587
  # This is the only style property without a default value!
585
588
  #
586
589
  # See: HexaPDF::Content::Canvas#font
590
+ #
591
+ # Examples:
592
+ #
593
+ # #>pdf-composer100
594
+ # composer.text("Helvetica", font: composer.document.fonts.add("Helvetica"))
595
+ # composer.text("Courier", font: "Courier") # works only with composer
596
+ #
597
+ # helvetica_bold = composer.document.fonts.add("Helvetica", variant: :bold)
598
+ # composer.text("Helvetica Bold", font: helvetica_bold)
599
+ # composer.text("Courier Bold", font: ["Courier", variant: :bold]) # only composer
587
600
 
588
601
  ##
589
602
  # :method: font_size
@@ -593,6 +606,12 @@ module HexaPDF
593
606
  # The font size, defaults to 10.
594
607
  #
595
608
  # See: HexaPDF::Content::Canvas#font_size
609
+ #
610
+ # Examples:
611
+ #
612
+ # #>pdf-composer100
613
+ # composer.text("Default size")
614
+ # composer.text("Larger size", font_size: 20)
596
615
 
597
616
  ##
598
617
  # :method: character_spacing
@@ -602,6 +621,11 @@ module HexaPDF
602
621
  # The character spacing, defaults to 0 (i.e. no additional character spacing).
603
622
  #
604
623
  # See: HexaPDF::Content::Canvas#character_spacing
624
+ #
625
+ # Examples:
626
+ #
627
+ # #>pdf-composer100
628
+ # composer.text("More spacing between characters", character_spacing: 1)
605
629
 
606
630
  ##
607
631
  # :method: word_spacing
@@ -611,6 +635,11 @@ module HexaPDF
611
635
  # The word spacing, defaults to 0 (i.e. no additional word spacing).
612
636
  #
613
637
  # See: HexaPDF::Content::Canvas#word_spacing
638
+ #
639
+ # Examples:
640
+ #
641
+ # #>pdf-composer100
642
+ # composer.text("More word spacing", word_spacing: 20)
614
643
 
615
644
  ##
616
645
  # :method: horizontal_scaling
@@ -620,6 +649,11 @@ module HexaPDF
620
649
  # The horizontal scaling, defaults to 100 (in percent, i.e. normal scaling).
621
650
  #
622
651
  # See: HexaPDF::Content::Canvas#horizontal_scaling
652
+ #
653
+ # Examples:
654
+ #
655
+ # #>pdf-composer100
656
+ # composer.text("Horizontal scaling", horizontal_scaling: 150)
623
657
 
624
658
  ##
625
659
  # :method: text_rise
@@ -629,6 +663,11 @@ module HexaPDF
629
663
  # The text rise, i.e. the vertical offset from the baseline, defaults to 0.
630
664
  #
631
665
  # See: HexaPDF::Content::Canvas#text_rise
666
+ #
667
+ # Examples:
668
+ #
669
+ # #>pdf-composer100
670
+ # composer.formatted_text(["Normal", {text: "Up in the air", text_rise: 5}])
632
671
 
633
672
  ##
634
673
  # :method: font_features
@@ -641,6 +680,13 @@ module HexaPDF
641
680
  # Each feature to be applied is indicated by a key with a truthy value.
642
681
  #
643
682
  # See: HexaPDF::Layout::TextShaper#shape_text for available features.
683
+ #
684
+ # Examples:
685
+ #
686
+ # #>pdf-composer100
687
+ # composer.style(:base, font: ["Times", custom_encoding: true], font_size: 30)
688
+ # composer.text("Test flight")
689
+ # composer.text("Test flight", font_features: {kern: true, liga: true})
644
690
 
645
691
  ##
646
692
  # :method: text_rendering_mode
@@ -652,6 +698,11 @@ module HexaPDF
652
698
  # rendering mode value.
653
699
  #
654
700
  # See: HexaPDF::Content::Canvas#text_rendering_mode
701
+ #
702
+ # Examples:
703
+ #
704
+ # #>pdf-composer100
705
+ # composer.text("Test flight", font_size: 40, text_rendering_mode: :stroke)
655
706
 
656
707
  ##
657
708
  # :method: subscript
@@ -661,6 +712,11 @@ module HexaPDF
661
712
  # Render the text as subscript, i.e. lower and in a smaller font size; defaults to false.
662
713
  #
663
714
  # If superscript is set, it will be deactivated.
715
+ #
716
+ # Examples:
717
+ #
718
+ # #>pdf-composer100
719
+ # composer.formatted_text(["Some ", {text: "subscript text", subscript: true}])
664
720
 
665
721
  ##
666
722
  # :method: superscript
@@ -670,6 +726,11 @@ module HexaPDF
670
726
  # Render the text as superscript, i.e. higher and in a smaller font size; defaults to false.
671
727
  #
672
728
  # If subscript is set, it will be deactivated.
729
+ #
730
+ # Examples:
731
+ #
732
+ # #>pdf-composer100
733
+ # composer.formatted_text(["Some ", {text: "superscript text", superscript: true}])
673
734
 
674
735
  ##
675
736
  # :method: underline
@@ -677,6 +738,11 @@ module HexaPDF
677
738
  # underline(enable = false)
678
739
  #
679
740
  # Renders a line underneath the text; defaults to false.
741
+ #
742
+ # Examples:
743
+ #
744
+ # #>pdf-composer100
745
+ # composer.text("Underlined text", underline: true)
680
746
 
681
747
  ##
682
748
  # :method: strikeout
@@ -684,6 +750,11 @@ module HexaPDF
684
750
  # strikeout(enable = false)
685
751
  #
686
752
  # Renders a line through the text; defaults to false.
753
+ #
754
+ # Examples:
755
+ #
756
+ # #>pdf-composer100
757
+ # composer.text("Strikeout text", strikeout: true)
687
758
 
688
759
  ##
689
760
  # :method: fill_color
@@ -693,6 +764,11 @@ module HexaPDF
693
764
  # The color used for filling (e.g. text), defaults to black.
694
765
  #
695
766
  # See: HexaPDF::Content::Canvas#fill_color
767
+ #
768
+ # Examples:
769
+ #
770
+ # #>pdf-composer100
771
+ # composer.text("This is some red text", fill_color: "red")
696
772
 
697
773
  ##
698
774
  # :method: fill_alpha
@@ -703,6 +779,11 @@ module HexaPDF
703
779
  # opaque).
704
780
  #
705
781
  # See: HexaPDF::Content::Canvas#opacity
782
+ #
783
+ # Examples:
784
+ #
785
+ # #>pdf-composer100
786
+ # composer.text("This is some semi-transparent text", fill_alpha: 0.5)
706
787
 
707
788
  ##
708
789
  # :method: stroke_color
@@ -712,6 +793,12 @@ module HexaPDF
712
793
  # The color used for stroking (e.g. text outlines), defaults to black.
713
794
  #
714
795
  # See: HexaPDF::Content::Canvas#stroke_color
796
+ #
797
+ # Examples:
798
+ #
799
+ # #>pdf-composer100
800
+ # composer.text("Stroked text", font_size: 40, stroke_color: "red",
801
+ # text_rendering_mode: :stroke)
715
802
 
716
803
  ##
717
804
  # :method: stroke_alpha
@@ -722,6 +809,12 @@ module HexaPDF
722
809
  # 100% opaque).
723
810
  #
724
811
  # See: HexaPDF::Content::Canvas#opacity
812
+ #
813
+ # Examples:
814
+ #
815
+ # #>pdf-composer100
816
+ # composer.text("Stroked text", font_size: 40, stroke_alpha: 0.5,
817
+ # text_rendering_mode: :stroke)
725
818
 
726
819
  ##
727
820
  # :method: stroke_width
@@ -731,6 +824,12 @@ module HexaPDF
731
824
  # The line width used for stroking operations (e.g. text outlines), defaults to 1.
732
825
  #
733
826
  # See: HexaPDF::Content::Canvas#line_width
827
+ #
828
+ # Examples:
829
+ #
830
+ # #>pdf-composer100
831
+ # composer.text("Stroked text", font_size: 40, stroke_width: 2,
832
+ # text_rendering_mode: :stroke)
734
833
 
735
834
  ##
736
835
  # :method: stroke_cap_style
@@ -741,6 +840,12 @@ module HexaPDF
741
840
  # returned values is always a normalized line cap style value.
742
841
  #
743
842
  # See: HexaPDF::Content::Canvas#line_cap_style
843
+ #
844
+ # Examples:
845
+ #
846
+ # #>pdf-composer100
847
+ # composer.text("Stroked text", font_size: 40, stroke_cap_style: :round,
848
+ # text_rendering_mode: :stroke)
744
849
 
745
850
  ##
746
851
  # :method: stroke_join_style
@@ -751,6 +856,12 @@ module HexaPDF
751
856
  # The returned values is always a normalized line joine style value.
752
857
  #
753
858
  # See: HexaPDF::Content::Canvas#line_join_style
859
+ #
860
+ # Examples:
861
+ #
862
+ # #>pdf-composer100
863
+ # composer.text("Stroked text", font_size: 40, stroke_join_style: :bevel,
864
+ # text_rendering_mode: :stroke)
754
865
 
755
866
  ##
756
867
  # :method: stroke_miter_limit
@@ -761,6 +872,12 @@ module HexaPDF
761
872
  # :miter, defaults to 10.0.
762
873
  #
763
874
  # See: HexaPDF::Content::Canvas#miter_limit
875
+ #
876
+ # Examples:
877
+ #
878
+ # #>pdf-composer100
879
+ # composer.text("Stroked text", font_size: 40, stroke_join_style: :bevel,
880
+ # stroke_miter_limit: 1, text_rendering_mode: :stroke)
764
881
 
765
882
  ##
766
883
  # :method: stroke_dash_pattern
@@ -771,6 +888,12 @@ module HexaPDF
771
888
  # line.
772
889
  #
773
890
  # See: HexaPDF::Content::Canvas#line_dash_pattern
891
+ #
892
+ # Examples:
893
+ #
894
+ # #>pdf-composer100
895
+ # composer.text("Stroked text", font_size: 40, stroke_dash_pattern: [4, 2],
896
+ # text_rendering_mode: :stroke)
774
897
 
775
898
  ##
776
899
  # :method: align
@@ -785,19 +908,42 @@ module HexaPDF
785
908
  # :center:: Center the text horizontally.
786
909
  # :right:: Right-align the text, i.e. the left side is rugged.
787
910
  # :justify:: Justify the text, except for those lines that end in a hard line break.
911
+ #
912
+ # Examples:
913
+ #
914
+ # #>pdf-composer100
915
+ # text = "Lorem ipsum dolor sit amet. " * 2
916
+ # composer.style(:base, border: {width: 1})
917
+ # composer.text(text, align: :left)
918
+ # composer.text(text, align: :center)
919
+ # composer.text(text, align: :right)
920
+ # composer.text(text, align: :justify)
788
921
 
789
922
  ##
790
923
  # :method: valign
791
924
  # :call-seq:
792
925
  # valign(direction = nil)
793
926
  #
794
- # The vertical alignment of items (normally text) inside a box, defaults to :top.
927
+ # The vertical alignment of items (normally text) inside a text box, defaults to :top.
928
+ #
929
+ # For :center and :bottom alignment the box will fill the whole available height. If this is
930
+ # not wanted, an explicit height will need to be set for the box.
931
+ #
932
+ # This property is ignored when using position :flow for a text box.
795
933
  #
796
934
  # Possible values:
797
935
  #
798
936
  # :top:: Vertically align the items to the top of the box.
799
937
  # :center:: Vertically align the items in the center of the box.
800
938
  # :bottom:: Vertically align the items to the bottom of the box.
939
+ #
940
+ # Examples:
941
+ #
942
+ # #>pdf-composer100
943
+ # composer.style(:base, border: {width: 1})
944
+ # composer.text("Top aligned", height: 20, valign: :top)
945
+ # composer.text("Center aligned", height: 20, valign: :center)
946
+ # composer.text("Bottom aligned", valign: :bottom)
801
947
 
802
948
  ##
803
949
  # :method: text_indent
@@ -805,6 +951,12 @@ module HexaPDF
805
951
  # text_indent(amount = nil)
806
952
  #
807
953
  # The indentation to be used for the first line of a sequence of text lines, defaults to 0.
954
+ #
955
+ # Examples:
956
+ #
957
+ # #>pdf-composer100
958
+ # composer.text("This is some longer text that wraps around in two lines.",
959
+ # text_indent: 10)
808
960
 
809
961
  ##
810
962
  # :method: line_spacing
@@ -819,7 +971,20 @@ module HexaPDF
819
971
  # * Using two positional arguments +type+ and +value+.
820
972
  # * Or a hash with the keys +type+ and +value+.
821
973
  #
974
+ # Note that the last line has no additional spacing after it by default. Set #last_line_gap
975
+ # for adding such a spacing.
976
+ #
822
977
  # See LineSpacing for supported types of line spacing.
978
+ #
979
+ # Examples:
980
+ #
981
+ # #>pdf-composer100
982
+ # composer.text("This is some longer text that wraps around in two lines.",
983
+ # line_spacing: 1.5)
984
+ # composer.text("This is some longer text that wraps around in two lines.",
985
+ # line_spacing: :double)
986
+ # composer.text("This is some longer text that wraps around in two lines.",
987
+ # line_spacing: {type: :proportional, value: 1.2})
823
988
 
824
989
  ##
825
990
  # :method: last_line_gap
@@ -827,6 +992,13 @@ module HexaPDF
827
992
  # last_line_gap(enable = false)
828
993
  #
829
994
  # Add an appropriately sized gap after the last line of text if enabled, defaults to false.
995
+ #
996
+ # Examples:
997
+ #
998
+ # #>pdf-composer100
999
+ # composer.text("This is some longer text that wraps around in two lines.",
1000
+ # line_spacing: 1.5, last_line_gap: true)
1001
+ # composer.text("There is spacing above this line due to last_line_gap.")
830
1002
 
831
1003
  ##
832
1004
  # :method: background_color
@@ -834,6 +1006,11 @@ module HexaPDF
834
1006
  # background_color(color = nil)
835
1007
  #
836
1008
  # The color used for backgrounds, defaults to +nil+ (i.e. no background).
1009
+ #
1010
+ # Examples:
1011
+ #
1012
+ # #>pdf-composer100
1013
+ # composer.text("Some text here", background_color: "lightgrey")
837
1014
 
838
1015
  ##
839
1016
  # :method: background_alpha
@@ -844,6 +1021,11 @@ module HexaPDF
844
1021
  # opaque).
845
1022
  #
846
1023
  # See: HexaPDF::Content::Canvas#opacity
1024
+ #
1025
+ # Examples:
1026
+ #
1027
+ # #>pdf-composer100
1028
+ # composer.text("Some text here", background_color: "red", background_alpha: 0.5)
847
1029
 
848
1030
  ##
849
1031
  # :method: padding
@@ -851,6 +1033,13 @@ module HexaPDF
851
1033
  # padding(value = nil)
852
1034
  #
853
1035
  # The padding between the border and the contents, defaults to 0 for all four sides.
1036
+ #
1037
+ # See Style::Quad#set for information on how to set the values.
1038
+ #
1039
+ # Examples:
1040
+ #
1041
+ # #>pdf-composer100
1042
+ # composer.text("Some text here", padding: 10, border: {width: 1})
854
1043
 
855
1044
  ##
856
1045
  # :method: margin
@@ -858,29 +1047,83 @@ module HexaPDF
858
1047
  # margin(value = nil)
859
1048
  #
860
1049
  # The margin around a box, defaults to 0 for all four sides.
1050
+ #
1051
+ # See Style::Quad#set for information on how to set the values.
1052
+ #
1053
+ # Examples:
1054
+ #
1055
+ # #>pdf-composer100
1056
+ # composer.text("Some text here", margin: [5, 10], position: :float,
1057
+ # border: {width: 1})
1058
+ # composer.text("Text starts after floating box and continues below it, " \
1059
+ # "respecting the margin.", position: :flow)
861
1060
 
862
1061
  ##
863
1062
  # :method: border
864
1063
  # :call-seq:
865
1064
  # border(value = nil)
866
1065
  #
867
- # The border around the contents, defaults to no border.
1066
+ # The border around the contents, defaults to no border for all four sides.
1067
+ #
1068
+ # The value has to be a hash containing any of the keys :width, :color and :style. The width,
1069
+ # color and style of the border can be set independently for each side (see Style::Quad#set).
1070
+ #
1071
+ # See Border for more details.
1072
+ #
1073
+ # Examples:
1074
+ #
1075
+ # #>pdf-composer100
1076
+ # composer.text("Some text here", border: {
1077
+ # width: [6, 3],
1078
+ # color: ["green", "blue", "orange"],
1079
+ # style: [:solid, :dashed]
1080
+ # })
868
1081
 
869
1082
  ##
870
1083
  # :method: overlays
871
1084
  # :call-seq:
872
1085
  # overlays(layers = nil)
873
1086
  #
874
- # A Layers object containing all the layers that should be drawn over the box; defaults to no
875
- # layers being drawn.
1087
+ # A Style::Layers object containing all the layers that should be drawn over the box; defaults
1088
+ # to no layers being drawn.
1089
+ #
1090
+ # The +layers+ argument needs to be an array of layer objects. To define a layer either use a
1091
+ # callable object taking the canvas and the box as arguments; or use a pre-defined layer using
1092
+ # an array of the form [:layer_name, **options]. See Style::Layers for details.
1093
+ #
1094
+ # Examples:
1095
+ #
1096
+ # #>pdf-composer100
1097
+ # composer.text("Some text here", overlays: [
1098
+ # lambda do |canvas, box|
1099
+ # canvas.stroke_color("red").opacity(stroke_alpha: 0.5).
1100
+ # line_width(5).line(0, 0, box.width, box.height).stroke
1101
+ # end,
1102
+ # [:link, uri: "https://hexapdf.gettalong.org"]
1103
+ # ])
876
1104
 
877
1105
  ##
878
1106
  # :method: underlays
879
1107
  # :call-seq:
880
1108
  # underlays(layers = nil)
881
1109
  #
882
- # A Layers object containing all the layers that should be drawn under the box; defaults to no
883
- # layers being drawn.
1110
+ # A Style::Layers object containing all the layers that should be drawn under the box;
1111
+ # defaults to no layers being drawn.
1112
+ #
1113
+ # The +layers+ argument needs to be an array of layer objects. To define a layer either use a
1114
+ # callable object taking the canvas and the box as arguments; or use a pre-defined layer using
1115
+ # an array of the form [:layer_name, **options]. See Style::Layers for details.
1116
+ #
1117
+ # Examples:
1118
+ #
1119
+ # #>pdf-composer100
1120
+ # composer.text("Some text here", underlays: [
1121
+ # lambda do |canvas, box|
1122
+ # canvas.stroke_color("red").opacity(stroke_alpha: 0.5).
1123
+ # line_width(5).line(0, 0, box.width, box.height).stroke
1124
+ # end,
1125
+ # [:link, uri: "https://hexapdf.gettalong.org"]
1126
+ # ])
884
1127
 
885
1128
  ##
886
1129
  # :method: position
@@ -904,6 +1147,8 @@ module HexaPDF
904
1147
  #
905
1148
  # :absolute:: Position the box at an absolute position relative to the frame. The coordinates
906
1149
  # are given via the position hint.
1150
+ #
1151
+ # See #position_hint for examples
907
1152
 
908
1153
  ##
909
1154
  # :method: position_hint
@@ -918,19 +1163,47 @@ module HexaPDF
918
1163
  # :default::
919
1164
  #
920
1165
  # :left:: (default) Align the box to the left side of the available region.
921
- # :right:: Align the box to the right side of the available region.
922
1166
  # :center:: Horizontally center the box in the available region.
1167
+ # :right:: Align the box to the right side of the available region.
1168
+ #
1169
+ # Examples:
1170
+ #
1171
+ # #>pdf-composer100
1172
+ # composer.text("Left", border: {width: 1})
1173
+ # draw_current_frame_shape("red")
1174
+ # composer.text("Center", position_hint: :center, border: {width: 1})
1175
+ # draw_current_frame_shape("blue")
1176
+ # composer.text("Right", position_hint: :right, border: {width: 1})
1177
+ # draw_current_frame_shape("green")
923
1178
  #
924
1179
  # :float::
925
1180
  #
926
1181
  # :left:: (default) Float the box to the left side of the available region.
1182
+ # :center:: Float the box to the center of the available region.
927
1183
  # :right:: Float the box to the right side of the available region.
928
1184
  #
1185
+ # Examples:
1186
+ #
1187
+ # #>pdf-composer100
1188
+ # composer.style(:base, position: :float, border: {width: 1})
1189
+ # composer.text("Left", position_hint: :left)
1190
+ # draw_current_frame_shape("red")
1191
+ # composer.text("Center", position_hint: :center)
1192
+ # draw_current_frame_shape("blue")
1193
+ # composer.text("Right", position_hint: :right)
1194
+ # draw_current_frame_shape("green")
1195
+ #
929
1196
  # :absolute::
930
1197
  #
931
1198
  # An array with the x- and y-coordinates of the bottom left corner of the absolutely
932
1199
  # positioned box. The coordinates are taken as being relative to the bottom left corner of
933
1200
  # the frame into which the box is drawn.
1201
+ #
1202
+ # Examples:
1203
+ #
1204
+ # #>pdf-composer100
1205
+ # composer.text("Absolute", position: :absolute, position_hint: [30, 40])
1206
+ # draw_current_frame_shape("red")
934
1207
 
935
1208
  [
936
1209
  [:font, "raise HexaPDF::Error, 'No font set'"],
@@ -77,8 +77,16 @@ module HexaPDF
77
77
  height = (@initial_height > 0 ? @initial_height : available_height) - @height
78
78
  @tl.fit(@items, width, height)
79
79
  end
80
- @width += (@initial_width > 0 ? width : @result.lines.max_by(&:width)&.width || 0)
81
- @height += (@initial_height > 0 ? height : @result.height)
80
+ @width += if @initial_width > 0 || style.align == :center || style.align == :right
81
+ width
82
+ else
83
+ @result.lines.max_by(&:width)&.width || 0
84
+ end
85
+ @height += if @initial_height > 0 || style.valign == :center || style.valign == :bottom
86
+ height
87
+ else
88
+ @result.height
89
+ end
82
90
  if style.last_line_gap && @result.lines.last
83
91
  @height += style.line_spacing.gap(@result.lines.last, @result.lines.last)
84
92
  end
@@ -825,7 +825,12 @@ module HexaPDF
825
825
  end
826
826
 
827
827
  unless lines.empty?
828
- lines.first.y_offset += initial_baseline_offset(lines, height, actual_height)
828
+ # Apply baseline offset only for non-variable width text
829
+ lines.first.y_offset += if width_block.arity == 1
830
+ lines.first.y_max
831
+ else
832
+ initial_baseline_offset(lines, height, actual_height)
833
+ end
829
834
  end
830
835
 
831
836
  Result.new(status, lines, rest)
@@ -82,6 +82,7 @@ module HexaPDF
82
82
  @loader = xref_section && (block || loader)
83
83
  @xref_section = xref_section || XRefSection.new
84
84
  @objects = HexaPDF::Utils::ObjectHash.new
85
+ @all_objects_loaded = false
85
86
  end
86
87
 
87
88
  # Returns the next free object number for adding an object to this revision.
@@ -209,7 +210,7 @@ module HexaPDF
209
210
  def each(only_loaded: false)
210
211
  return to_enum(__method__, only_loaded: only_loaded) unless block_given?
211
212
 
212
- if defined?(@all_objects_loaded) || only_loaded
213
+ if @all_objects_loaded || only_loaded
213
214
  @objects.each {|_oid, _gen, data| yield(data) }
214
215
  else
215
216
  seen = {}
@@ -256,6 +257,12 @@ module HexaPDF
256
257
  self
257
258
  end
258
259
 
260
+ # Resets the revision by deleting all loaded and added objects from it.
261
+ def reset_objects
262
+ @objects = HexaPDF::Utils::ObjectHash.new
263
+ @all_objects_loaded = false
264
+ end
265
+
259
266
  private
260
267
 
261
268
  # Loads a single object from the associated cross-reference section.