Class: HexaPDF::Layout::Style
- Inherits:
-
Object
- Object
- HexaPDF::Layout::Style
- 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
- PROPERTIES =
:nodoc:
[ [:font, "raise HexaPDF::Error, 'No font set'"], [:font_bold, false], [:font_italic, false], [:font_size, 10], [:line_height, nil], [: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 value && superscript? && superscript", valid_values: [true, false]}], [:superscript, false, {setter: "value; subscript(false) if value && subscript? && 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"}], [:text_align, :left, {valid_values: [:left, :center, :right, :justify]}], [:text_valign, :top, {valid_values: [:top, :center, :bottom]}], [:text_indent, 0], [:line_spacing, "LineSpacing.new(type: :single)", {setter: "LineSpacing.new(**(value.kind_of?(Symbol) || value.kind_of?(Numeric) || " \ "value.kind_of?(LineSpacing) ? {type: value, value: extra_arg} : value))", extra_args: ", extra_arg = nil"}], [:last_line_gap, false, {valid_values: [true, false]}], [:fill_horizontal, nil], [:background_color, nil], [:background_alpha, 1], [:padding, "Quad.new(0)", {setter: "value.kind_of?(Hash) && @name ? @name.set(value) : Quad.new(value)"}], [:margin, "Quad.new(0)", {setter: "value.kind_of?(Hash) && @name ? @name.set(value) : 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], [:align, :left, {valid_values: [:left, :center, :right]}], [:valign, :top, {valid_values: [:top, :center, :bottom]}], [:mask_mode, :default, {valid_values: [:default, :none, :box, :fill_horizontal, :fill_frame_horizontal, :fill_vertical, :fill]}], [:overflow, :error], [:box_options, {}], ].each do |name, default, = {}| default = default.inspect unless default.kind_of?(String) setter = .delete(:setter) || "value" extra_args = .delete(:extra_args) || "" valid_values = .delete(:valid_values) raise ArgumentError, "Invalid keywords: #{options.keys.join(', ')}" unless .empty? valid_values_const = "#{name}_valid_values".upcase const_set(valid_values_const, valid_values) module_eval(" def \#{name}(value = UNSET\#{extra_args})\n if value == UNSET\n @\#{name} ||= \#{default}\n elsif \#{valid_values_const} && !\#{valid_values_const}.include?(value)\n raise ArgumentError, \"\\\#{value.inspect} is not a valid \#{name} value \" \\\\\n \"(\\\#{\#{valid_values_const}.map(&:inspect).join(', ')})\"\n else\n @\#{name} = \#{setter}\n self\n end\n end\n def \#{name}?\n defined?(@\#{name})\n end\n EOF\n alias_method(\"\#{name}=\", name)\nend.each_with_object({}) {|arr, hash| hash[:\"@\#{arr.first}\"] = arr.first }\n", __FILE__, __LINE__ + 1)
Class Method Summary collapse
-
.create(style) ⇒ Object
:call-seq: Style.create(style) -> style Style.create(properties_hash) -> style.
Instance Method Summary collapse
-
#calculated_font_size ⇒ Object
The calculated font size, taking superscript and subscript into account.
-
#calculated_strikeout_position ⇒ Object
Returns the correct offset from the baseline for the strikeout line.
-
#calculated_strikeout_thickness ⇒ Object
Returns the correct thickness for the strikeout line.
-
#calculated_text_rise ⇒ Object
The calculated text rise, taking superscript and subscript into account.
-
#calculated_underline_position ⇒ Object
Returns the correct offset from the baseline for the underline.
-
#calculated_underline_thickness ⇒ Object
Returns the correct thickness for the underline.
-
#clear_cache ⇒ Object
Clears all cached values.
-
#each_property ⇒ Object
Yields all set properties.
-
#initialize(**properties) ⇒ Style
constructor
Creates a new Style object.
-
#initialize_copy(other) ⇒ Object
Duplicates the complex properties that can be modified, as well as the cache.
-
#merge(other) ⇒ Object
:call-seq: style.merge(other_style) -> style.
-
#name ⇒ Object
:method: text_line_wrapping_algorithm :call-seq: text_line_wrapping_algorithm(algorithm = nil) {|items, width_block| block }.
-
#scaled_character_spacing ⇒ Object
The character spacing scaled appropriately.
-
#scaled_font_ascender ⇒ Object
The ascender of the font scaled appropriately.
-
#scaled_font_descender ⇒ Object
The descender of the font scaled appropriately.
-
#scaled_font_size ⇒ Object
The font size scaled appropriately.
-
#scaled_horizontal_scaling ⇒ Object
The horizontal scaling scaled appropriately.
-
#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).
-
#scaled_word_spacing ⇒ Object
The word spacing scaled appropriately.
-
#scaled_y_max ⇒ Object
The maximum y-coordinate, calculated using the scaled ascender of the font and the line height or font size.
-
#scaled_y_min ⇒ Object
The minimum y-coordinate, calculated using the scaled descender of the font and the line height or font size.
-
#update(**properties) ⇒ Object
:call-seq: style.update(**properties) -> style.
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, text_align: :center, text_valign: center)
596 597 598 599 |
# File 'lib/hexapdf/layout/style.rb', line 596 def initialize(**properties) update(**properties) @scaled_item_widths = {}.compare_by_identity end |
Class Method Details
.create(style) ⇒ Object
:call-seq:
Style.create(style) -> style
Style.create(properties_hash) -> style
Creates a Style object based on the style
argument and returns it:
-
If
style
is already a Style object, it is just returned. -
If
style
is a hash, a new Style object with the style properties specified by the hash -
is created.
-
If
style
isnil
, a new Style object with only default values is created.
580 581 582 583 584 585 586 587 |
# File 'lib/hexapdf/layout/style.rb', line 580 def self.create(style) case style when self then style when Hash then new(**style) when nil then new else raise ArgumentError, "Invalid argument class #{style.class}" end end |
Instance Method Details
#calculated_font_size ⇒ Object
The calculated font size, taking superscript and subscript into account.
1669 1670 1671 |
# File 'lib/hexapdf/layout/style.rb', line 1669 def calculated_font_size ((superscript? && superscript) || (subscript? && subscript) ? 0.583 : 1) * font_size end |
#calculated_strikeout_position ⇒ Object
Returns the correct offset from the baseline for the strikeout line.
1688 1689 1690 1691 1692 1693 |
# File 'lib/hexapdf/layout/style.rb', line 1688 def calculated_strikeout_position calculated_text_rise + font.wrapped_font.strikeout_position * font.scaling_factor * font.pdf_object.glyph_scaling_factor * calculated_font_size - calculated_strikeout_thickness / 2.0 end |
#calculated_strikeout_thickness ⇒ Object
Returns the correct thickness for the strikeout line.
1696 1697 1698 1699 |
# File 'lib/hexapdf/layout/style.rb', line 1696 def calculated_strikeout_thickness font.wrapped_font.strikeout_thickness * font.scaling_factor * font.pdf_object.glyph_scaling_factor * calculated_font_size end |
#calculated_text_rise ⇒ Object
The calculated text rise, taking superscript and subscript into account.
1658 1659 1660 1661 1662 1663 1664 1665 1666 |
# File 'lib/hexapdf/layout/style.rb', line 1658 def calculated_text_rise if superscript? && superscript text_rise + font_size * 0.33 elsif subscript? && subscript text_rise - font_size * 0.20 else text_rise end end |
#calculated_underline_position ⇒ Object
Returns the correct offset from the baseline for the underline.
1674 1675 1676 1677 1678 1679 |
# File 'lib/hexapdf/layout/style.rb', line 1674 def calculated_underline_position calculated_text_rise + font.wrapped_font.underline_position * font.scaling_factor * font.pdf_object.glyph_scaling_factor * calculated_font_size - calculated_underline_thickness / 2.0 end |
#calculated_underline_thickness ⇒ Object
Returns the correct thickness for the underline.
1682 1683 1684 1685 |
# File 'lib/hexapdf/layout/style.rb', line 1682 def calculated_underline_thickness font.wrapped_font.underline_thickness * font.scaling_factor * font.pdf_object.glyph_scaling_factor * calculated_font_size end |
#clear_cache ⇒ Object
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.
1768 1769 1770 1771 1772 1773 |
# File 'lib/hexapdf/layout/style.rb', line 1768 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 |
#each_property ⇒ Object
Yields all set properties.
627 628 629 630 631 632 |
# File 'lib/hexapdf/layout/style.rb', line 627 def each_property # :yield: property, value return to_enum(__method__) unless block_given? instance_variables.each do |iv| (val = PROPERTIES[iv]) && yield(val, instance_variable_get(iv)) end end |
#initialize_copy(other) ⇒ Object
Duplicates the complex properties that can be modified, as well as the cache.
602 603 604 605 606 607 608 609 610 611 612 613 |
# File 'lib/hexapdf/layout/style.rb', line 602 def initialize_copy(other) super @scaled_item_widths = {}.compare_by_identity 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) = .dup if defined?() @underlays = @underlays.dup if defined?(@underlays) end |
#merge(other) ⇒ Object
:call-seq:
style.merge(other_style) -> style
Merges the set properties of the other_style
object into this one.
Note that merging is done on a per-property basis. So if a complex property is set on other_style
and also on self
, the other_style
value completely overwrites the one from self
.
Also see: #update
644 645 646 647 |
# File 'lib/hexapdf/layout/style.rb', line 644 def merge(other) other.each_property {|property, value| send(property, value) } self end |
#name ⇒ Object
: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.
1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 |
# File 'lib/hexapdf/layout/style.rb', line 1636 [ [:text_segmentation_algorithm, 'TextLayouter::SimpleTextSegmentation'], [:text_line_wrapping_algorithm, 'TextLayouter::SimpleLineWrapping'], ].each do |name, default| default = default.inspect unless default.kind_of?(String) module_eval(" def \#{name}(value = UNSET, &block)\n if value == UNSET && !block\n @\#{name} ||= \#{default}\n else\n @\#{name} = (value != UNSET ? value : block)\n self\n end\n end\n def \#{name}?\n defined?(@\#{name})\n end\n EOF\n alias_method(\"\#{name}=\", name)\nend\n", __FILE__, __LINE__ + 1) |
#scaled_character_spacing ⇒ Object
The character spacing scaled appropriately.
1708 1709 1710 |
# File 'lib/hexapdf/layout/style.rb', line 1708 def scaled_character_spacing @scaled_character_spacing ||= character_spacing * scaled_horizontal_scaling end |
#scaled_font_ascender ⇒ Object
The ascender of the font scaled appropriately.
1723 1724 1725 1726 |
# File 'lib/hexapdf/layout/style.rb', line 1723 def scaled_font_ascender @scaled_font_ascender ||= font.wrapped_font.ascender * font.scaling_factor * font.pdf_object.glyph_scaling_factor * font_size end |
#scaled_font_descender ⇒ Object
The descender of the font scaled appropriately.
1729 1730 1731 1732 |
# File 'lib/hexapdf/layout/style.rb', line 1729 def scaled_font_descender @scaled_font_descender ||= font.wrapped_font.descender * font.scaling_factor * font.pdf_object.glyph_scaling_factor * font_size end |
#scaled_font_size ⇒ Object
The font size scaled appropriately.
1702 1703 1704 1705 |
# File 'lib/hexapdf/layout/style.rb', line 1702 def scaled_font_size @scaled_font_size ||= calculated_font_size * font.pdf_object.glyph_scaling_factor * scaled_horizontal_scaling end |
#scaled_horizontal_scaling ⇒ Object
The horizontal scaling scaled appropriately.
1718 1719 1720 |
# File 'lib/hexapdf/layout/style.rb', line 1718 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.
1753 1754 1755 1756 1757 1758 1759 1760 1761 |
# File 'lib/hexapdf/layout/style.rb', line 1753 def scaled_item_width(item) @scaled_item_widths[item] ||= 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 |
#scaled_word_spacing ⇒ Object
The word spacing scaled appropriately.
1713 1714 1715 |
# File 'lib/hexapdf/layout/style.rb', line 1713 def scaled_word_spacing @scaled_word_spacing ||= word_spacing * scaled_horizontal_scaling end |
#scaled_y_max ⇒ Object
The maximum y-coordinate, calculated using the scaled ascender of the font and the line height or font size.
1743 1744 1745 1746 |
# File 'lib/hexapdf/layout/style.rb', line 1743 def scaled_y_max @scaled_y_max ||= scaled_font_ascender * (line_height || font_size) / font_size.to_f + calculated_text_rise end |
#scaled_y_min ⇒ Object
The minimum y-coordinate, calculated using the scaled descender of the font and the line height or font size.
1736 1737 1738 1739 |
# File 'lib/hexapdf/layout/style.rb', line 1736 def scaled_y_min @scaled_y_min ||= scaled_font_descender * (line_height || font_size) / font_size.to_f + 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.
Also see: #merge
621 622 623 624 |
# File 'lib/hexapdf/layout/style.rb', line 621 def update(**properties) properties.each {|key, value| send(key, value) } self end |