Class: HexaPDF::Layout::Style

Inherits:
Object
  • Object
show all
Defined in:
lib/hexapdf/layout/style.rb

Overview

A Style is a container for properties that describe the appearance of text or graphics.

Each property except #font has a default value, so only the desired properties need to be changed.

Each property has three associated methods:

property_name

Getter method.

property_name(*args) and property_name=

Setter method.

property_name?

Tester method to see if a value has been set or if the default value has already been used.

Defined Under Namespace

Classes: Border, Layers, LineSpacing, LinkLayer, Quad

Constant Summary collapse

UNSET =

:nodoc:

::Object.new

Instance Method Summary collapse

Constructor Details

#initialize(**properties) ⇒ Style

Creates a new Style object.

The properties hash may be used to set the initial values of properties by using keys equivalent to the property names.

Example:

Style.new(font_size: 15, align: :center, valign: center)


525
526
527
528
# File 'lib/hexapdf/layout/style.rb', line 525

def initialize(**properties)
  update(**properties)
  @scaled_item_widths = {}.compare_by_identity
end

Instance Method Details

#calculated_font_sizeObject

The calculated font size, taking superscript and subscript into account.



1004
1005
1006
# File 'lib/hexapdf/layout/style.rb', line 1004

def calculated_font_size
  (superscript || subscript ? 0.583 : 1) * font_size
end

#calculated_strikeout_positionObject

Returns the correct offset from the baseline for the strikeout line.



1021
1022
1023
1024
1025
# File 'lib/hexapdf/layout/style.rb', line 1021

def calculated_strikeout_position
  calculated_text_rise +
    calculated_font_size / 1000.0 * font.wrapped_font.strikeout_position *
    font.scaling_factor - calculated_strikeout_thickness / 2.0
end

#calculated_strikeout_thicknessObject

Returns the correct thickness for the strikeout line.



1028
1029
1030
# File 'lib/hexapdf/layout/style.rb', line 1028

def calculated_strikeout_thickness
  calculated_font_size / 1000.0 * font.wrapped_font.strikeout_thickness * font.scaling_factor
end

#calculated_text_riseObject

The calculated text rise, taking superscript and subscript into account.



993
994
995
996
997
998
999
1000
1001
# File 'lib/hexapdf/layout/style.rb', line 993

def calculated_text_rise
  if superscript
    text_rise + font_size * 0.33
  elsif subscript
    text_rise - font_size * 0.20
  else
    text_rise
  end
end

#calculated_underline_positionObject

Returns the correct offset from the baseline for the underline.



1009
1010
1011
1012
1013
# File 'lib/hexapdf/layout/style.rb', line 1009

def calculated_underline_position
  calculated_text_rise +
    calculated_font_size / 1000.0 * font.wrapped_font.underline_position *
    font.scaling_factor - calculated_underline_thickness / 2.0
end

#calculated_underline_thicknessObject

Returns the correct thickness for the underline.



1016
1017
1018
# File 'lib/hexapdf/layout/style.rb', line 1016

def calculated_underline_thickness
  calculated_font_size / 1000.0 * font.wrapped_font.underline_thickness * font.scaling_factor
end

#clear_cacheObject

Clears all cached values.

This method needs to be called if the following style properties are changed and values were already cached: font, font_size, character_spacing, word_spacing, horizontal_scaling, ascender, descender.



1094
1095
1096
1097
1098
1099
# File 'lib/hexapdf/layout/style.rb', line 1094

def clear_cache
  @scaled_font_size = @scaled_character_spacing = @scaled_word_spacing = nil
  @scaled_horizontal_scaling = @scaled_font_ascender = @scaled_font_descender = nil
  @scaled_y_min = @scaled_y_max = nil
  @scaled_item_widths.clear
end

#initialize_copy(other) ⇒ Object

Duplicates the complex properties that can be modified, as well as the cache.



531
532
533
534
535
536
537
538
539
540
541
542
# File 'lib/hexapdf/layout/style.rb', line 531

def initialize_copy(other)
  super
  @scaled_item_widths = {}
  clear_cache

  @font_features = @font_features.dup if defined?(@font_features)
  @padding = @padding.dup if defined?(@padding)
  @margin = @margin.dup if defined?(@margin)
  @border = @border.dup if defined?(@border)
  @overlays = @overlays.dup if defined?(@overlays)
  @underlays = @underlays.dup if defined?(@underlays)
end

#nameObject

:method: text_line_wrapping_algorithm :call-seq:

text_line_wrapping_algorithm(algorithm = nil) {|items, width_block| block }

The line wrapping algorithm that should be used, defaults to TextLayouter::SimpleLineWrapping.

When setting the algorithm, either an object that responds to #call or a block can be used. See TextLayouter::SimpleLineWrapping#call for the needed method signature.



877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
# File 'lib/hexapdf/layout/style.rb', line 877

[
  [:font, "raise HexaPDF::Error, 'No font set'"],
  [:font_size, 10],
  [:character_spacing, 0],
  [:word_spacing, 0],
  [:horizontal_scaling, 100],
  [:text_rise, 0],
  [:font_features, {}],
  [:text_rendering_mode, "Content::TextRenderingMode::FILL",
   {setter: "Content::TextRenderingMode.normalize(value)"}],
  [:subscript, false,
   {setter: "value; superscript(false) if superscript",
    valid_values: [true, false]}],
  [:superscript, false,
   {setter: "value; subscript(false) if subscript",
    valid_values: [true, false]}],
  [:underline, false, {valid_values: [true, false]}],
  [:strikeout, false, {valid_values: [true, false]}],
  [:fill_color, "default_color"],
  [:fill_alpha, 1],
  [:stroke_color, "default_color"],
  [:stroke_alpha, 1],
  [:stroke_width, 1],
  [:stroke_cap_style, "Content::LineCapStyle::BUTT_CAP",
   {setter: "Content::LineCapStyle.normalize(value)"}],
  [:stroke_join_style, "Content::LineJoinStyle::MITER_JOIN",
   {setter: "Content::LineJoinStyle.normalize(value)"}],
  [:stroke_miter_limit, 10.0],
  [:stroke_dash_pattern, "Content::LineDashPattern.new",
   {setter: "Content::LineDashPattern.normalize(value, phase)", extra_args: ", phase = 0"}],
  [:align, :left, {valid_values: [:left, :center, :right, :justify]}],
  [:valign, :top, {valid_values: [:top, :center, :bottom]}],
  [:text_indent, 0],
  [:line_spacing, "LineSpacing.new(type: :single)",
   {setter: "LineSpacing.new(**(value.kind_of?(Symbol) ? {type: value, value: extra_arg} : value))",
    extra_args: ", extra_arg = nil"}],
  [:last_line_gap, false, {valid_values: [true, false]}],
  [:background_color, nil],
  [:padding, "Quad.new(0)", {setter: "Quad.new(value)"}],
  [:margin, "Quad.new(0)", {setter: "Quad.new(value)"}],
  [:border, "Border.new", {setter: "Border.new(**value)"}],
  [:overlays, "Layers.new", {setter: "Layers.new(value)"}],
  [:underlays, "Layers.new", {setter: "Layers.new(value)"}],
  [:position, :default, {valid_values: [:default, :float, :flow, :absolute]}],
  [:position_hint, nil],
].each do |name, default, options = {}|
  default = default.inspect unless default.kind_of?(String)
  setter = options.delete(:setter) || "value"
  extra_args = options.delete(:extra_args) || ""
  valid_values = options.delete(:valid_values)
  raise ArgumentError, "Invalid keywords: #{options.keys.join(', ')}" unless options.empty?
  valid_values_const = "#{name}_valid_values".upcase
  const_set(valid_values_const, valid_values)
  module_eval(<<-EOF, __FILE__, __LINE__ + 1)
    def #{name}(value = UNSET#{extra_args})
      if value == UNSET
        @#{name} ||= #{default}
      elsif #{valid_values_const} && !#{valid_values_const}.include?(value)
        raise ArgumentError, "\#{value.inspect} is not a valid #{name} value " \\
          "(\#{#{valid_values_const}.map(&:inspect).join(', ')})"
      else
        @#{name} = #{setter}
        self
      end
    end
    def #{name}?
      defined?(@#{name})
    end
  EOF
  alias_method("#{name}=", name)
end

#scaled_character_spacingObject

The character spacing scaled appropriately.



1038
1039
1040
# File 'lib/hexapdf/layout/style.rb', line 1038

def scaled_character_spacing
  @scaled_character_spacing ||= character_spacing * scaled_horizontal_scaling
end

#scaled_font_ascenderObject

The ascender of the font scaled appropriately.



1053
1054
1055
# File 'lib/hexapdf/layout/style.rb', line 1053

def scaled_font_ascender
  @scaled_font_ascender ||= font.wrapped_font.ascender * font.scaling_factor * font_size / 1000
end

#scaled_font_descenderObject

The descender of the font scaled appropriately.



1058
1059
1060
# File 'lib/hexapdf/layout/style.rb', line 1058

def scaled_font_descender
  @scaled_font_descender ||= font.wrapped_font.descender * font.scaling_factor * font_size / 1000
end

#scaled_font_sizeObject

The font size scaled appropriately.



1033
1034
1035
# File 'lib/hexapdf/layout/style.rb', line 1033

def scaled_font_size
  @scaled_font_size ||= calculated_font_size / 1000.0 * scaled_horizontal_scaling
end

#scaled_horizontal_scalingObject

The horizontal scaling scaled appropriately.



1048
1049
1050
# File 'lib/hexapdf/layout/style.rb', line 1048

def scaled_horizontal_scaling
  @scaled_horizontal_scaling ||= horizontal_scaling / 100.0
end

#scaled_item_width(item) ⇒ Object

Returns the width of the item scaled appropriately (by taking font size, characters spacing, word spacing and horizontal scaling into account).

The item may be a (singleton) glyph object or an integer/float, i.e. items that can appear inside a TextFragment.



1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
# File 'lib/hexapdf/layout/style.rb', line 1077

def scaled_item_width(item)
  @scaled_item_widths[item] ||=
    begin
      if item.kind_of?(Numeric)
        -item * scaled_font_size
      else
        item.width * scaled_font_size + scaled_character_spacing +
          (item.apply_word_spacing? ? scaled_word_spacing : 0)
      end
    end
end

#scaled_word_spacingObject

The word spacing scaled appropriately.



1043
1044
1045
# File 'lib/hexapdf/layout/style.rb', line 1043

def scaled_word_spacing
  @scaled_word_spacing ||= word_spacing * scaled_horizontal_scaling
end

#scaled_y_maxObject

The maximum y-coordinate, calculated using the scaled descender of the font.



1068
1069
1070
# File 'lib/hexapdf/layout/style.rb', line 1068

def scaled_y_max
  @scaled_y_max ||= scaled_font_ascender + calculated_text_rise
end

#scaled_y_minObject

The minimum y-coordinate, calculated using the scaled descender of the font.



1063
1064
1065
# File 'lib/hexapdf/layout/style.rb', line 1063

def scaled_y_min
  @scaled_y_min ||= scaled_font_descender + calculated_text_rise
end

#update(**properties) ⇒ Object

:call-seq:

style.update(**properties)    -> style

Updates the style’s properties using the key-value pairs specified by the properties hash.



548
549
550
551
# File 'lib/hexapdf/layout/style.rb', line 548

def update(**properties)
  properties.each {|key, value| send(key, value) }
  self
end