Module: Asciidoctor::Prawn::Extensions
- Includes:
- Asciidoctor::PDF::Measurements, Asciidoctor::PDF::Sanitizer, Asciidoctor::PDF::TextTransformer
- Included in:
- Asciidoctor::PDF::Converter
- Defined in:
- lib/asciidoctor/pdf/ext/prawn/extensions.rb
Defined Under Namespace
Classes: Extent, LineMetrics, Position, ScratchExtent
Constant Summary collapse
- ColumnBox =
::Prawn::Document::ColumnBox
- FontAwesomeIconSets =
%w(fab far fas)
- IconSets =
%w(fab far fas fi pf).to_set
- IconSetPrefixes =
IconSets.map {|it| it + '-' }
- InitialPageContent =
%(q\n)
- PlaceholderChar =
NOTE: must use a visible char for placeholder or else Prawn won’t reserve space for the fragment
?\u2063
- NewPageRequiredError =
::Class.new ::StopIteration
- InhibitNewPageProc =
proc do |pdf| pdf.delete_current_page raise NewPageRequiredError end
- DetectEmptyFirstPage =
::Module.new
- DetectEmptyFirstPageProc =
proc do |delegate, pdf| if pdf.state.pages[pdf.page_number - 2].empty? pdf.delete_current_page raise NewPageRequiredError end delegate.call pdf if (pdf.state.on_page_create_callback = delegate) end
Constants included from Asciidoctor::PDF::TextTransformer
Asciidoctor::PDF::TextTransformer::BareClassRx, Asciidoctor::PDF::TextTransformer::ContiguousCharsRx, Asciidoctor::PDF::TextTransformer::Hyphen, Asciidoctor::PDF::TextTransformer::LowerAlphaChars, Asciidoctor::PDF::TextTransformer::PCDATAFilterRx, Asciidoctor::PDF::TextTransformer::SmallCapsChars, Asciidoctor::PDF::TextTransformer::SoftHyphen, Asciidoctor::PDF::TextTransformer::TagFilterRx, Asciidoctor::PDF::TextTransformer::WordRx, Asciidoctor::PDF::TextTransformer::XMLMarkupRx
Constants included from Asciidoctor::PDF::Sanitizer
Asciidoctor::PDF::Sanitizer::CharRefRx, Asciidoctor::PDF::Sanitizer::InverseXMLSpecialChars, Asciidoctor::PDF::Sanitizer::InverseXMLSpecialCharsRx, Asciidoctor::PDF::Sanitizer::SanitizeXMLRx, Asciidoctor::PDF::Sanitizer::UnescapedAmpersandRx, Asciidoctor::PDF::Sanitizer::XMLSpecialChars, Asciidoctor::PDF::Sanitizer::XMLSpecialCharsRx
Constants included from Asciidoctor::PDF::Measurements
Asciidoctor::PDF::Measurements::InsetMeasurementValueRx, Asciidoctor::PDF::Measurements::MeasurementValueHintRx, Asciidoctor::PDF::Measurements::MeasurementValueRx
Instance Method Summary collapse
-
#advance_page(options = {}) ⇒ Object
This method is a smarter version of start_new_page.
-
#allocate_scratch_prototype ⇒ Object
Scratch.
-
#arrange_block(node, &block) ⇒ Object
Yields to the specified block multiple times, first to determine where to render the content so it fits properly, then once more, this time providing access to the content’s extent, to ink the content in the primary document.
-
#at_page_top? ⇒ Boolean
Returns whether the cursor is at the top of the page (i.e., margin box).
-
#bounds_margin_left ⇒ Object
Returns the total left margin (to the page edge) for the current bounds.
-
#bounds_margin_right ⇒ Object
Returns the total right margin (to the page edge) for the current bounds.
- #calc_line_metrics(line_height, font = self.font, font_size = self.font_size) ⇒ Object
-
#catalog ⇒ Object
Retrieves the catalog reference data for the PDF.
-
#column_box(point, options, &block) ⇒ Object
Wraps the column_box method and automatically sets the height unless the :height option is specified.
-
#conceal_page_top ⇒ Object
Prevents at_page_top? from returning true while yielding to the specified block.
-
#delete_current_page ⇒ Object
Deletes the current page and move the cursor to the previous page.
-
#dest_top(page_num = nil) ⇒ Object
Generates a destination object that resolves to the top of the page specified by the page_num parameter or the current page if no page number is provided.
-
#draw_indented_formatted_line(string, options) ⇒ Object
NOTE: override built-in draw_indented_formatted_line to set first_line flag.
-
#dry_run(keep_together: nil, pages_advanced: 0, single_page: nil, onto: nil, &block) ⇒ Object
Yields to the specified block within the context of a scratch document up to three times to acertain the extent of the content block.
-
#effective_page_height ⇒ Object
Returns the effective (writable) height of the page.
- #expand_grid_values(shorthand, default = nil) ⇒ Object
- #expand_indent_value(value) ⇒ Object
- #expand_padding_value(shorthand) ⇒ Object (also: #expand_margin_value)
- #expand_rect_values(shorthand, default = nil) ⇒ Object
-
#fill_absolute_bounds(f_color) ⇒ Object
Fills the absolute bounding box with the specified fill color.
-
#fill_and_stroke_bounds(f_color = fill_color, s_color = stroke_color, options = {}) ⇒ Object
Fills the current bounds using the specified fill color and strokes the bounds using the specified stroke color.
-
#fill_bounds(f_color) ⇒ Object
Fills the current bounding box with the specified fill color.
-
#fill_formatted_text_box(text, options) ⇒ Object
NOTE: override built-in fill_formatted_text_box to insert leading before second line when :first_line is true.
-
#float ⇒ Object
Override the built-in float method to add support for restoring the current column of a ColumnBox.
-
#flow_bounding_box(options = {}) ⇒ Object
A flowing version of bounding_box.
-
#font(name = nil, options = {}) ⇒ Object
Enhances the built-in font method to allow the font size to be specified as the second option and to lazily load font-based icons.
-
#font_family ⇒ Object
(also: #font_name)
Retrieves the current font name (i.e., family).
-
#font_info ⇒ Object
Retrieves the current font info (family, style, size) as a Hash.
-
#font_size(points = nil) ⇒ Object
Applies points as a scale factor of the current font if the value provided is less than or equal to 1 or it’s a string (e.g., 1.1em), then delegates to the super implementation to carry out the built-in functionality.
-
#font_style(style = nil) ⇒ Object
Set the font style on the document, if a style is given, otherwise return the current font style.
-
#font_styles(style = font_style) ⇒ Object
Retreives the collection of font styles from the given font style key, which defaults to the current font style.
-
#generate_margin_box ⇒ Object
remove once fixed upstream; see github.com/prawnpdf/prawn/pull/1122.
-
#get_dest(name, node = dests.data) ⇒ Object
Gets the destination registered for the specified name.
- #hyphenate_text(text, hyphenator) ⇒ Object
- #icon_font_data(family) ⇒ Object
-
#image_page(file, options = {}) ⇒ Object
Create a new page for the specified image.
-
#import_page(file, options = {}) ⇒ Object
Import the specified page into the current document.
-
#last_page? ⇒ Boolean
Returns whether the current page is the last page in the document.
-
#min_version ⇒ Object
Retrieves the compatiblity version of the PDF.
-
#move_down(n) ⇒ Object
Short-circuits the call to the built-in move_down operation when n is 0.
-
#move_text_position(h) ⇒ Object
Override built-in move_text_position method to prevent Prawn from advancing to next page if image doesn’t fit before rendering image.
-
#move_up(n) ⇒ Object
Short-circuits the call to the built-in move_up operation when n is 0.
-
#pad_box(padding, node = nil) ⇒ Object
Augments the built-in pad method by adding support for specifying padding on all four sizes.
-
#page_height ⇒ Object
Returns the height of the current page from edge-to-edge.
-
#page_margin ⇒ Object
Returns the margins for the current page as a 4 element array (top, right, bottom, left).
-
#page_margin_bottom ⇒ Object
Returns the width of the bottom margin for the current page.
-
#page_margin_left ⇒ Object
Returns the width of the left margin for the current page.
-
#page_margin_right ⇒ Object
Returns the width of the right margin for the current page.
-
#page_margin_top ⇒ Object
Returns the width of the top margin for the current page.
-
#page_side(pgnum = nil, invert = nil) ⇒ Object
Returns the side the current page is facing, :recto or :verso.
-
#page_width ⇒ Object
Returns the width of the current page from edge-to-edge.
-
#parse_text(string, options = {}) ⇒ Object
Parse the text into an array of fragments using the text formatter.
-
#perform_discretely ⇒ Object
Perform an operation (such as creating a new page) without triggering the on_page_create callback.
-
#perform_on_single_page ⇒ Object
This method installs an on_page_create_callback that stops processing if the first page is exceeded while yielding to the specified block.
-
#recto_page?(pgnum = nil) ⇒ Boolean
Returns whether the page is a recto page.
-
#register_font(data) ⇒ Object
Registers a new custom font described in the data parameter after converting the font name to a String.
- #resolve_font_style(styles) ⇒ Object
- #resolve_legacy_icon_name(name) ⇒ Object
- #scratch ⇒ Object
- #scratch? ⇒ Boolean
- #set_font(font, size = nil) ⇒ Object
-
#set_page_margin(margin) ⇒ Object
Set the margins for the current page.
-
#span_page_width_if(verdict) ⇒ Object
Stretch the current bounds to the left and right edges of the current page while yielding the specified block if the verdict argument is true.
-
#start_new_page_discretely(options = {}) ⇒ Object
Start a new page without triggering the on_page_create callback.
-
#stop_if_first_page_empty ⇒ Object
This method installs an on_page_create_callback that stops processing if a new page is created without writing content to the first page while yielding to the specified block.
-
#stroke_horizontal_rule(rule_color = stroke_color, options = {}) ⇒ Object
Strokes a horizontal line using the current bounds.
-
#stroke_vertical_rule(rule_color = stroke_color, options = {}) ⇒ Object
A compliment to the stroke_horizontal_rule method, strokes a vertical line using the current bounds.
-
#tare_first_page_content_stream ⇒ Object
This method delegates to the provided block, then tares (i.e., resets) the content stream of the initial page.
-
#text_with_formatted_first_line(string, first_line_options, options) ⇒ Object
Performs the same work as Prawn::Text.text except that the first_line_options are applied to the first line of text renderered.
-
#verso_page?(pgnum = nil) ⇒ Boolean
Returns whether the page is a verso page.
-
#width_of_string(string, options) ⇒ Object
Override width of string to check for placeholder char, which uses character spacing to control width.
- #with_dry_run {|dry_run(&block).position_onto self, cursor| ... } ⇒ Object
Methods included from Asciidoctor::PDF::TextTransformer
#capitalize_words, #capitalize_words_pcdata, #hyphenate_words, #hyphenate_words_pcdata, #lowercase_pcdata, #smallcaps, #smallcaps_pcdata, #transform_text, #uppercase_pcdata
Methods included from Asciidoctor::PDF::Sanitizer
#encode_quotes, #escape_amp, #escape_xml, #sanitize, #unescape_xml
Methods included from Asciidoctor::PDF::Measurements
#resolve_measurement_values, #str_to_pt, #to_pt
Instance Method Details
#advance_page(options = {}) ⇒ Object
This method is a smarter version of start_new_page. It only calls start_new_page options are specified and the current page is the last page in the document. Otherwise, it advances the cursor to the next page (or column) using Bounds#move_past_bottom.
955 956 957 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 955 def advance_page = {} .empty? || !last_page? ? bounds.move_past_bottom : (start_new_page ) end |
#allocate_scratch_prototype ⇒ Object
Scratch
967 968 969 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 967 def allocate_scratch_prototype @scratch_prototype = create_scratch_prototype { ::Marshal.load ::Marshal.dump self } end |
#arrange_block(node, &block) ⇒ Object
Yields to the specified block multiple times, first to determine where to render the content so it fits properly, then once more, this time providing access to the content’s extent, to ink the content in the primary document.
This method yields to the specified block in a scratch document by calling dry_run to determine where the content should start in the primary document. In the process, it also computes the extent of the content. It then returns to the primary document and yields to the block again, this time passing in the extent of the content. The extent can be used to draw a border and/or background under the content before inking it.
This method is intended to enclose the conversion of a single content block, such as a sidebar or example block. The arrange logic attempts to keep unbreakable content on the same page, keeps the top caption pinned to the top of the content, computes the extent of the content for the purpose of drawing a border and/or background underneath it, and ensures that the extent does not begin near the bottom of a page if the first line of content doesn’t fit. If unbreakable content does not fit on a single page, the content is treated as breakable.
The block passed to this method should use advance_page to move to the next page rather than start_new_page. Using start_new_page can mangle the calculation of content block’s extent.
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 1004 def arrange_block node, &block if at_page_top? at_top = true else at_top = true if node.first_child? && (node.parent.attr? 'pdf-at-top') keep_together = true if node.option? 'unbreakable' end node.set_attr 'pdf-at-top', '' if at_top doc = node.document block_for_scratch = proc do at_top = node.set_attr 'pdf-at-top', '' if !at_top && at_page_top? push_scratch doc instance_exec(&block) ensure pop_scratch doc end extent = dry_run keep_together: keep_together, onto: [self, keep_together], &block_for_scratch scratch? ? block_for_scratch.call : (yield extent) ensure node.remove_attr 'pdf-at-top' if at_top end |
#at_page_top? ⇒ Boolean
Returns whether the cursor is at the top of the page (i.e., margin box).
254 255 256 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 254 def at_page_top? @y == (ColumnBox === bounds ? bounds : @margin_box).absolute_top end |
#bounds_margin_left ⇒ Object
Returns the total left margin (to the page edge) for the current bounds.
220 221 222 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 220 def bounds_margin_left bounds.absolute_left end |
#bounds_margin_right ⇒ Object
Returns the total right margin (to the page edge) for the current bounds.
226 227 228 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 226 def bounds_margin_right page.dimensions[2] - bounds.absolute_right end |
#calc_line_metrics(line_height, font = self.font, font_size = self.font_size) ⇒ Object
415 416 417 418 419 420 421 422 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 415 def calc_line_metrics line_height, font = self.font, font_size = self.font_size line_height_length = line_height * font_size leading = line_height_length - font_size half_leading = leading / 2 padding_top = half_leading + font.line_gap padding_bottom = half_leading LineMetrics.new line_height_length, leading, padding_top, padding_bottom, false end |
#catalog ⇒ Object
Retrieves the catalog reference data for the PDF.
127 128 129 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 127 def catalog state.store.root end |
#column_box(point, options, &block) ⇒ Object
Wraps the column_box method and automatically sets the height unless the :height option is specified.
697 698 699 700 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 697 def column_box point, , &block [:height] = cursor unless .key? :height super end |
#conceal_page_top ⇒ Object
Prevents at_page_top? from returning true while yielding to the specified block.
260 261 262 263 264 265 266 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 260 def conceal_page_top old_top = (outer_bounds = ColumnBox === bounds ? bounds : @margin_box).absolute_top outer_bounds.instance_variable_set :@y, old_top + 0.0001 yield ensure outer_bounds.instance_variable_set :@y, old_top end |
#delete_current_page ⇒ Object
Deletes the current page and move the cursor to the previous page.
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 865 def delete_current_page pg = page_number pdf_store = state.store content_id = page.content.identifier page_ref = page.dictionary (prune_dests = proc do |node| node.children.delete_if {|it| ::PDF::Core::NameTree::Node === it ? prune_dests[it] : it.value.data[0] == page_ref } false end)[dests.data] # NOTE: cannot delete objects and IDs, otherwise references get corrupted; so just reset the value (pdf_store.instance_variable_get :@objects)[content_id] = ::PDF::Core::Reference.new content_id, {} pdf_store.pages.data[:Kids].pop pdf_store.pages.data[:Count] -= 1 state.pages.pop if pg > 1 go_to_page pg - 1 else @page_number = 0 state.page = nil end end |
#dest_top(page_num = nil) ⇒ Object
Generates a destination object that resolves to the top of the page specified by the page_num parameter or the current page if no page number is provided. The destination preserves the user’s zoom level unlike the destinations generated by the outline builder.
281 282 283 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 281 def dest_top page_num = nil dest_xyz 0, page_height, nil, (page_num ? state.pages[page_num - 1] : page) end |
#draw_indented_formatted_line(string, options) ⇒ Object
NOTE: override built-in draw_indented_formatted_line to set first_line flag
462 463 464 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 462 def draw_indented_formatted_line string, super string, (.merge first_line: true) end |
#dry_run(keep_together: nil, pages_advanced: 0, single_page: nil, onto: nil, &block) ⇒ Object
Yields to the specified block within the context of a scratch document up to three times to acertain the extent of the content block.
The purpose of this method is two-fold. First, it works out the position where the rendered content should start in the calling document. Then, it precomputes the extent of the content starting from that position.
This method returns the content’s extent (the range from the start page and cursor to the end page and cursor) as a ScratchExtent object or, if the onto keyword parameter is specified, an Extent object. A ScratchExtent always starts the page range at 1. When the ScratchExtent is positioned onto the primary document using ScratchExtent#position_onto, that’s when the cursor may be advanced to the next page.
This method performs all work in a scratch document (or documents). It begins by starting a new page in the scratch document, first creating the scratch document if necessary. It then applies all the settings from the main document to the scratch document that impact rendering. This includes the bounds, the cursor position, and the font settings. This method assumes that the content area remains constant when content flows from one page to the next.
From this point, the number of attempts the method makes is determined by the value of the keep_together keyword parameter. If the value is true (or the parent document is inhibiting page creation), it starts from the top of the page, yields to the block, and tries to fit the content on the current page. If the content fits, it computes and returns the ScratchExtent (or Extent). If the content does not fit, it first checks if this scenario should stop the operation. If the parent document is inhibiting page creation, it bubbles the error. If the single_page keyword argument is :enforce, it raises a CannotFit error. If the single_page keyword argument is true, it returns a ScratchExtent (or Extent) that represents a full page. If none of those conditions are met, it restarts with the keep_together parameter unset.
If the keep_together parameter is not true, the method tries to render the content in the scratch document from the location of the cursor in the main document. If the cursor is at the top of the page, no special conditions are applied (this is the last attempt). The content is rendered and the extent is computed based on where the content ended up (minus a trailing empty page). If the cursor is not at the top of the page, the method renders the content while listening for a page creation event before any content is written. If a new page is created, and no content is written on the first page, the method restarts with the cursor at the top of the page.
Note that if the block has content that itself requires a dry run, that nested dry run will be performed in a separate scratch document.
The block passed to dry run should take steps to avoid leaving the document state modified. This can be done by calling ‘push_scratch doc` at the start of the block and `pop_scratch` in the ensure clause of the block.
options - A Hash of options that configure the dry run computation:
:keep_together - A Boolean indicating whether an attempt should be made to keep
the content on the same page (optional, default: false).
:single_page - A Boolean indicating whether the operation should stop if the
content exceeds the height of a single page.
:onto - The document onto which to position the scratch extent. If this option is
set, the method returns an Extent instance (optional, default: false)
:pages_advanced - The number of pages the content has been advanced during this
operation (internal only) (optional, default: 0)
Returns an Extent or ScratchExtent object that describes the bounds of the content block.
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 1141 def dry_run keep_together: nil, pages_advanced: 0, single_page: nil, onto: nil, &block (scratch_pdf = scratch).start_new_page layout: page.layout, margin: page_margin saved_bounds = scratch_pdf.bounds scratch_pdf.bounds = bounds.dup.tap do |bounds_copy| bounds_copy.instance_variable_set :@document, scratch_pdf bounds_copy.instance_variable_set :@parent, saved_bounds bounds_copy.single_file if ColumnBox === bounds_copy end scratch_pdf.move_cursor_to cursor unless (scratch_start_at_top = keep_together || pages_advanced > 0 || at_page_top?) scratch_start_cursor = scratch_pdf.cursor scratch_start_page = scratch_pdf.page_number inhibit_new_page = state.on_page_create_callback == InhibitNewPageProc restart = nil scratch_pdf.font font_family, size: font_size, style: font_style do prev_font_scale, scratch_pdf.font_scale = scratch_pdf.font_scale, font_scale if keep_together || inhibit_new_page if (restart = scratch_pdf.perform_on_single_page { scratch_pdf.instance_exec(&block) }) # NOTE: propogate NewPageRequiredError from nested block, which is rendered in separate scratch document raise NewPageRequiredError if inhibit_new_page if single_page raise ::Prawn::Errors::CannotFit if single_page == :enforce # single_page and onto are mutually exclusive return ScratchExtent.new scratch_start_page, scratch_start_cursor, scratch_start_page, 0 end end elsif scratch_start_at_top scratch_pdf.instance_exec(&block) elsif (restart = scratch_pdf.stop_if_first_page_empty { scratch_pdf.instance_exec(&block) }) pages_advanced += 1 end ensure scratch_pdf.font_scale = prev_font_scale end return dry_run pages_advanced: pages_advanced, onto: onto, &block if restart scratch_end_page = scratch_pdf.page_number - scratch_start_page + (scratch_start_page = 1) if pages_advanced > 0 scratch_start_page += pages_advanced scratch_end_page += pages_advanced end scratch_end_cursor = scratch_pdf.cursor # NOTE: drop trailing blank page and move cursor to end of previous page if scratch_end_page > scratch_start_page && scratch_pdf.at_page_top? scratch_end_page -= 1 scratch_end_cursor = 0 end extent = ScratchExtent.new scratch_start_page, scratch_start_cursor, scratch_end_page, scratch_end_cursor onto ? extent.position_onto(*onto) : extent ensure scratch_pdf.bounds = saved_bounds end |
#effective_page_height ⇒ Object
Returns the effective (writable) height of the page
If inside a fixed-height bounding box, returns height of box.
155 156 157 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 155 def effective_page_height reference_bounds.height end |
#expand_grid_values(shorthand, default = nil) ⇒ Object
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 638 def shorthand, default = nil if ::Array === shorthand case shorthand.size when 1 [(value0 = shorthand[0] || default), value0] when 2 shorthand.map {|it| it || default } when 4 if Asciidoctor::PDF::ThemeLoader::CMYKColorValue === shorthand [shorthand, shorthand] else (shorthand.slice 0, 2).map {|it| it || default } end else (shorthand.slice 0, 2).map {|it| it || default } end else [(value0 = shorthand || default), value0] end end |
#expand_indent_value(value) ⇒ Object
610 611 612 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 610 def value (::Array === value ? (value.slice 0, 2) : (::Array.new 2, value)).map(&:to_f) end |
#expand_padding_value(shorthand) ⇒ Object Also known as: expand_margin_value
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 614 def shorthand (@edge_shorthand_cache ||= ::Hash.new do |store, key| if ::Array === key case key.size when 1 value = [(value0 = key[0] || 0), value0, value0, value0] when 2 value = [(value0 = key[0] || 0), (value1 = key[1] || 0), value0, value1] when 3 value = [key[0] || 0, (value1 = key[1] || 0), key[2] || 0, value1] when 4 value = key.map {|it| it || 0 } else value = (key.slice 0, 4).map {|it| it || 0 } end else value = [(value0 = key || 0), value0, value0, value0] end store[key] = value end)[shorthand] end |
#expand_rect_values(shorthand, default = nil) ⇒ Object
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 659 def shorthand, default = nil if ::Array === shorthand case shorthand.size when 1 [(value0 = shorthand[0] || default), value0, value0, value0] when 2 [(value0 = shorthand[0] || default), (value1 = shorthand[1] || default), value0, value1] when 3 [shorthand[0] || default, (value1 = shorthand[1] || default), shorthand[2] || default, value1] when 4 if Asciidoctor::PDF::ThemeLoader::CMYKColorValue === shorthand [shorthand, shorthand, shorthand, shorthand] else shorthand.map {|it| it || default } end else (shorthand.slice 0, 4).map {|it| it || default } end else [(value0 = shorthand || default), value0, value0, value0] end end |
#fill_absolute_bounds(f_color) ⇒ Object
Fills the absolute bounding box with the specified fill color. Before returning from this method, the original fill color on the document is restored.
732 733 734 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 732 def fill_absolute_bounds f_color canvas { fill_bounds f_color } end |
#fill_and_stroke_bounds(f_color = fill_color, s_color = stroke_color, options = {}) ⇒ Object
Fills the current bounds using the specified fill color and strokes the bounds using the specified stroke color. Sets the line with if specified in the options. Before returning from this method, the original fill color, stroke color and line width on the document are restored.
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 741 def fill_and_stroke_bounds f_color = fill_color, s_color = stroke_color, = {} no_fill = !f_color || f_color == 'transparent' if ::Array === (s_width = [:line_width] || 0) s_width = [s_width[0], s_width[1], s_width[0], s_width[1]] if s_width.size == 2 s_width_max = (s_width = s_width.map {|it| it || 0 }).max radius = 0 else radius = [:radius] || 0 end no_stroke = !s_color || s_color == 'transparent' || (s_width_max || s_width) == 0 return if no_fill && no_stroke save_graphics_state do # fill unless no_fill fill_color f_color fill_rounded_rectangle bounds.top_left, bounds.width, bounds.height, radius end next if no_stroke # stroke if s_width_max s_width_top, s_width_right, s_width_bottom, s_width_left = s_width projection_top, projection_right, projection_bottom, projection_left = s_width.map {|it| it * 0.5 } if s_width_top > 0 stroke_horizontal_rule s_color, line_width: s_width_top, line_style: [:line_style], left_projection: projection_left, right_projection: projection_right end if s_width_right > 0 stroke_vertical_rule s_color, line_width: s_width_right, line_style: [:line_style], at: bounds.width, top_projection: projection_top, bottom_projection: projection_bottom end if s_width_bottom > 0 stroke_horizontal_rule s_color, line_width: s_width_bottom, line_style: [:line_style], at: bounds.height, left_projection: projection_left, right_projection: projection_right end if s_width_left > 0 stroke_vertical_rule s_color, line_width: s_width_left, line_style: [:line_style], top_projection: projection_top, bottom_projection: projection_bottom end else stroke_color s_color case [:line_style] when :dashed line_width s_width dash s_width * 4 when :dotted line_width s_width dash s_width when :double single_line_width = s_width / 3.0 line_width single_line_width inner_line_offset = single_line_width * 2 inner_top_left = [bounds.left + inner_line_offset, bounds.top - inner_line_offset] stroke_rounded_rectangle bounds.top_left, bounds.width, bounds.height, radius stroke_rounded_rectangle inner_top_left, bounds.width - (inner_line_offset * 2), bounds.height - (inner_line_offset * 2), radius next else # :solid line_width s_width end stroke_rounded_rectangle bounds.top_left, bounds.width, bounds.height, radius end end end |
#fill_bounds(f_color) ⇒ Object
Fills the current bounding box with the specified fill color. Before returning from this method, the original fill color on the document is restored.
722 723 724 725 726 727 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 722 def fill_bounds f_color prev_fill_color = fill_color fill_color f_color fill_rectangle bounds.top_left, bounds.width, bounds.height fill_color prev_fill_color end |
#fill_formatted_text_box(text, options) ⇒ Object
NOTE: override built-in fill_formatted_text_box to insert leading before second line when :first_line is true
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 437 def fill_formatted_text_box text, if (initial_gap = [:initial_gap]) && !text.empty? && text[0][:from_page] != page_number self.y -= initial_gap end box = ::Prawn::Text::Formatted::Box.new text, remaining_fragments = box.render @no_text_printed = box.nothing_printed? @all_text_printed = box.everything_printed? unless remaining_fragments.empty? || (remaining_fragments[0][:from_page] ||= page_number) == page_number log :error, %(cannot fit formatted text on page: #{remaining_fragments.map {|it| it[:image_path] || it[:text] }.join}) page.tare_content_stream remaining_fragments = {} end if @final_gap || ([:first_line] && !(@no_text_printed || @all_text_printed)) self.y -= box.height + box.line_gap + box.leading else self.y -= box.height end remaining_fragments end |
#float ⇒ Object
Override the built-in float method to add support for restoring the current column of a ColumnBox
532 533 534 535 536 537 538 539 540 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 532 def float original_page_number = page_number original_y = y original_column = bounds.current_column if ColumnBox === bounds yield go_to_page original_page_number unless page_number == original_page_number self.y = original_y bounds.current_column = original_column if original_column end |
#flow_bounding_box(options = {}) ⇒ Object
A flowing version of bounding_box. If the content runs to another page, the cursor starts at the top of the page instead of from the original cursor position. Similar to span, except the :position option is limited to a numeric value and additional options are passed through to bounding_box.
707 708 709 710 711 712 713 714 715 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 707 def flow_bounding_box = {} original_y, original_x = y, bounds.absolute_left canvas do bounding_box [original_x + (.delete :position).to_f, @margin_box.absolute_top], do self.y = original_y yield end end end |
#font(name = nil, options = {}) ⇒ Object
Enhances the built-in font method to allow the font size to be specified as the second option and to lazily load font-based icons.
321 322 323 324 325 326 327 328 329 330 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 321 def font name = nil, = {} if name = { size: } if ::Numeric === if IconSets.include? name ::Prawn::Icon::FontData.load self, name = .reject {|k| k == :style } if .key? :style end end super end |
#font_family ⇒ Object Also known as: font_name
Retrieves the current font name (i.e., family).
334 335 336 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 334 def font_family font.[:family] end |
#font_info ⇒ Object
Retrieves the current font info (family, style, size) as a Hash
342 343 344 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 342 def font_info { family: font.[:family], style: (font.[:style] || :normal), size: @font_size } end |
#font_size(points = nil) ⇒ Object
Applies points as a scale factor of the current font if the value provided is less than or equal to 1 or it’s a string (e.g., 1.1em), then delegates to the super implementation to carry out the built-in functionality.
– QUESTION: should we round the result?
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 362 def font_size points = nil return @font_size unless points if ::String === points if points.end_with? 'rem' super @root_font_size * points.to_f elsif points.end_with? 'em' super @font_size * points.to_f elsif points.end_with? '%' super @font_size * (points.to_f / 100) else super points.to_f end else super points end end |
#font_style(style = nil) ⇒ Object
Set the font style on the document, if a style is given, otherwise return the current font style.
348 349 350 351 352 353 354 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 348 def font_style style = nil if style font font.[:family], style: style else font.[:style] || :normal end end |
#font_styles(style = font_style) ⇒ Object
Retreives the collection of font styles from the given font style key, which defaults to the current font style.
397 398 399 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 397 def font_styles style = font_style FontStyleToSet[style].dup end |
#generate_margin_box ⇒ Object
remove once fixed upstream; see github.com/prawnpdf/prawn/pull/1122
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 160 def generate_margin_box page_w, page_h = (page = state.page).dimensions.slice 2, 2 page_m = page.margins prev_margin_box, @margin_box = @margin_box, (::Prawn::Document::BoundingBox.new self, nil, [page_m[:left], page_h - page_m[:top]], width: page_w - page_m[:left] - page_m[:right], height: page_h - page_m[:top] - page_m[:bottom]) # update bounding box if not flowing from the previous page unless @bounding_box&.parent prev_margin_box = @bounding_box @bounding_box = @margin_box end # maintains indentation settings across page breaks if prev_margin_box @margin_box.add_left_padding prev_margin_box.total_left_padding @margin_box.add_right_padding prev_margin_box.total_right_padding end nil end |
#get_dest(name, node = dests.data) ⇒ Object
Gets the destination registered for the specified name. The return value matches that which was passed to the add_dest method.
288 289 290 291 292 293 294 295 296 297 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 288 def get_dest name, node = dests.data node.children.each do |child| if ::PDF::Core::NameTree::Value === child return child.value.data if child.name == name elsif (found = get_dest name, child) return found end end nil end |
#hyphenate_text(text, hyphenator) ⇒ Object
524 525 526 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 524 def hyphenate_text text, hyphenator hyphenate_words_pcdata text, hyphenator end |
#icon_font_data(family) ⇒ Object
407 408 409 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 407 def icon_font_data family ::Prawn::Icon::FontData.load self, family end |
#image_page(file, options = {}) ⇒ Object
Create a new page for the specified image.
The image is positioned relative to the boundaries of the page.
929 930 931 932 933 934 935 936 937 938 939 940 941 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 929 def image_page file, = {} start_new_page_discretely ex = nil float do canvas do image file, ({ position: :center, vposition: :center }.merge ) rescue ex = $! end end raise ex if ex nil end |
#import_page(file, options = {}) ⇒ Object
Import the specified page into the current document.
By default, advance to the next page afterwards, creating it if necessary. This behavior can be disabled by passing the option ‘advance: false`. However, due to how page creation works in Prawn, understand that advancing to the next page is necessary to prevent the size & layout of the imported page from affecting a newly created page.
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 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 894 def import_page file, = {} prev_page_layout = page.layout prev_page_size = page.size prev_page_margin = page_margin prev_bounds = bounds state.compress = false if state.compress # can't use compression if using template prev_text_rendering_mode = (defined? @text_rendering_mode) ? @text_rendering_mode : nil delete_current_page if [:replace] # NOTE: use functionality provided by prawn-templates start_new_page_discretely template: file, template_page: [:page] # prawn-templates sets text_rendering_mode to :unknown, which breaks running content; revert @text_rendering_mode = prev_text_rendering_mode if page.imported_page? yield if block_given? # NOTE: set page size & layout explicitly in case imported page differs # I'm not sure it's right to start a new page here, but unfortunately there's no other # way atm to prevent the size & layout of the imported page from affecting subsequent pages if .fetch :advance, true advance_page layout: prev_page_layout, margin: prev_page_margin, size: prev_page_size (@bounding_box = prev_bounds).reset_top if ColumnBox === prev_bounds end elsif .fetch :advance_if_missing, true delete_current_page # NOTE: see previous comment advance_page layout: prev_page_layout, margin: prev_page_margin, size: prev_page_size @y = (@bounding_box = prev_bounds).reset_top if ColumnBox === prev_bounds else delete_current_page end nil end |
#last_page? ⇒ Boolean
Returns whether the current page is the last page in the document.
270 271 272 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 270 def last_page? page_number == page_count end |
#min_version ⇒ Object
Retrieves the compatiblity version of the PDF.
133 134 135 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 133 def min_version state.version end |
#move_down(n) ⇒ Object
Short-circuits the call to the built-in move_down operation when n is 0.
558 559 560 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 558 def move_down n super unless n == 0 end |
#move_text_position(h) ⇒ Object
Override built-in move_text_position method to prevent Prawn from advancing to next page if image doesn’t fit before rendering image. – NOTE: could use :at option when calling image/embed_image instead
553 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 553 def move_text_position h; end |
#move_up(n) ⇒ Object
Short-circuits the call to the built-in move_up operation when n is 0.
545 546 547 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 545 def move_up n super unless n == 0 end |
#pad_box(padding, node = nil) ⇒ Object
Augments the built-in pad method by adding support for specifying padding on all four sizes.
Padding may be specified as an array of four values, or as a single value. The single value is used as the padding around all four sides of the box.
If padding is nil, this method simply yields to the block and returns.
Example:
pad_box 20 do
text 'A paragraph inside a blox with even padding from all edges.'
end
pad_box [10, 5] do
text 'A paragraph inside a box with different padding from ends and sides.'
end
pad_box [5, 10, 15, 20] do
text 'A paragraph inside a box with different padding from each edge.'
end
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 585 def pad_box padding, node = nil if padding p_top, p_right, p_bottom, p_left = padding # logic is intentionally inlined begin if node && ((last_block = node).content_model != :compound || (last_block = node.last_child)&.context == :paragraph) @bottom_gutters << { last_block => p_bottom } else @bottom_gutters << {} end move_down p_top bounds.add_left_padding p_left bounds.add_right_padding p_right yield ensure cursor > p_bottom ? (move_down p_bottom) : bounds.move_past_bottom unless at_page_top? @bottom_gutters.pop bounds.subtract_left_padding p_left bounds.subtract_right_padding p_right end else yield end end |
#page_height ⇒ Object
Returns the height of the current page from edge-to-edge
147 148 149 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 147 def page_height page.dimensions[3] end |
#page_margin ⇒ Object
Returns the margins for the current page as a 4 element array (top, right, bottom, left)
190 191 192 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 190 def page_margin [page_margin_top, page_margin_right, page_margin_bottom, page_margin_left] end |
#page_margin_bottom ⇒ Object
Returns the width of the bottom margin for the current page
214 215 216 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 214 def page_margin_bottom page.margins[:bottom] end |
#page_margin_left ⇒ Object
Returns the width of the left margin for the current page
196 197 198 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 196 def page_margin_left page.margins[:left] end |
#page_margin_right ⇒ Object
Returns the width of the right margin for the current page
202 203 204 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 202 def page_margin_right page.margins[:right] end |
#page_margin_top ⇒ Object
Returns the width of the top margin for the current page
208 209 210 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 208 def page_margin_top page.margins[:top] end |
#page_side(pgnum = nil, invert = nil) ⇒ Object
Returns the side the current page is facing, :recto or :verso.
232 233 234 235 236 237 238 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 232 def page_side pgnum = nil, invert = nil if invert (recto_page? pgnum) ? :verso : :recto else (verso_page? pgnum) ? :verso : :recto end end |
#page_width ⇒ Object
Returns the width of the current page from edge-to-edge
141 142 143 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 141 def page_width page.dimensions[2] end |
#parse_text(string, options = {}) ⇒ Object
Parse the text into an array of fragments using the text formatter.
425 426 427 428 429 430 431 432 433 434 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 425 def parse_text string, = {} return [] if string.nil? if (format_option = [:inline_format]) format_option = [] unless ::Array === format_option text_formatter.format string, *format_option else [text: string] end end |
#perform_discretely ⇒ Object
Perform an operation (such as creating a new page) without triggering the on_page_create callback
945 946 947 948 949 950 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 945 def perform_discretely state.on_page_create_callback = nil if (saved_callback = state.on_page_create_callback) != InhibitNewPageProc yield ensure state.on_page_create_callback = saved_callback end |
#perform_on_single_page ⇒ Object
This method installs an on_page_create_callback that stops processing if the first page is exceeded while yielding to the specified block. If the content fits on a single page, the processing is not stopped. The purpose of this method is to determine if the content fits on a single page.
Returns a Boolean indicating whether the content fits on a single page.
1032 1033 1034 1035 1036 1037 1038 1039 1040 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 1032 def perform_on_single_page saved_callback, state.on_page_create_callback = state.on_page_create_callback, InhibitNewPageProc yield false rescue NewPageRequiredError true ensure state.on_page_create_callback = saved_callback end |
#recto_page?(pgnum = nil) ⇒ Boolean
Returns whether the page is a recto page.
242 243 244 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 242 def recto_page? pgnum = nil (pgnum || page_number).odd? end |
#register_font(data) ⇒ Object
Registers a new custom font described in the data parameter after converting the font name to a String.
Example:
register_font Roboto: {
normal: 'fonts/roboto-normal.ttf',
italic: 'fonts/roboto-italic.ttf',
bold: 'fonts/roboto-bold.ttf',
bold_italic: 'fonts/roboto-bold_italic.ttf'
}
313 314 315 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 313 def register_font data font_families.update data.transform_keys(&:to_s) end |
#resolve_font_style(styles) ⇒ Object
384 385 386 387 388 389 390 391 392 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 384 def resolve_font_style styles if styles.include? :bold (styles.include? :italic) ? :bold_italic : :bold elsif styles.include? :italic :italic else :normal end end |
#resolve_legacy_icon_name(name) ⇒ Object
411 412 413 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 411 def resolve_legacy_icon_name name ::Prawn::Icon::Compatibility::SHIMS[%(fa-#{name})] end |
#scratch ⇒ Object
971 972 973 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 971 def scratch @scratch ||= ((Marshal.load Marshal.dump @scratch_prototype).send :init_scratch, self) end |
#scratch? ⇒ Boolean
975 976 977 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 975 def scratch? @label == :scratch end |
#set_font(font, size = nil) ⇒ Object
379 380 381 382 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 379 def set_font font, size = nil @font = font font_size size if size end |
#set_page_margin(margin) ⇒ Object
Set the margins for the current page.
182 183 184 185 186 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 182 def set_page_margin margin # FIXME: is there a cleaner way to set margins? does it make sense to override create_new_page? margin: margin generate_margin_box end |
#span_page_width_if(verdict) ⇒ Object
Stretch the current bounds to the left and right edges of the current page while yielding the specified block if the verdict argument is true. Otherwise, simply yield the specified block.
686 687 688 689 690 691 692 693 694 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 686 def span_page_width_if verdict if verdict indent(-bounds_margin_left, -bounds_margin_right) do yield end else yield end end |
#start_new_page_discretely(options = {}) ⇒ Object
Start a new page without triggering the on_page_create callback
961 962 963 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 961 def start_new_page_discretely = {} perform_discretely { start_new_page } end |
#stop_if_first_page_empty ⇒ Object
This method installs an on_page_create_callback that stops processing if a new page is created without writing content to the first page while yielding to the specified block. If any content is written to the first page, processing is not stopped. The purpose of this method is to check whether any content fits on the remaining space on the current page.
Returns a Boolean indicating whether any content is written on the first page.
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 1048 def stop_if_first_page_empty delegate = state.on_page_create_callback state.on_page_create_callback = DetectEmptyFirstPageProc.curry[delegate].extend DetectEmptyFirstPage yield false rescue NewPageRequiredError true ensure state.on_page_create_callback = delegate end |
#stroke_horizontal_rule(rule_color = stroke_color, options = {}) ⇒ Object
Strokes a horizontal line using the current bounds. The width of the line can be specified using the line_width option. The offset from the cursor can be set using the at option.
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 806 def stroke_horizontal_rule rule_color = stroke_color, = {} rule_y = cursor - ([:at] || 0) rule_style = [:line_style] rule_width = [:line_width] || 0.5 rule_x_start = bounds.left - ([:left_projection] || 0) rule_x_end = bounds.right - ([:right_projection] || 0) save_graphics_state do stroke_color rule_color case rule_style when :dashed line_width rule_width dash rule_width * 4 when :dotted line_width rule_width dash rule_width when :double single_rule_width = rule_width / 3.0 line_width single_rule_width stroke_horizontal_line rule_x_start, rule_x_end, at: (rule_y + single_rule_width) stroke_horizontal_line rule_x_start, rule_x_end, at: (rule_y - single_rule_width) next else # :solid line_width rule_width end stroke_horizontal_line rule_x_start, rule_x_end, at: rule_y end end |
#stroke_vertical_rule(rule_color = stroke_color, options = {}) ⇒ Object
A compliment to the stroke_horizontal_rule method, strokes a vertical line using the current bounds. The width of the line can be specified using the line_width option. The horizontal (x) position can be specified using the at option.
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 839 def stroke_vertical_rule rule_color = stroke_color, = {} rule_x = [:at] || 0 rule_y_from = bounds.top + ([:top_projection] || 0) rule_y_to = bounds.bottom - ([:bottom_projection] || 0) rule_style = [:line_style] rule_width = [:line_width] || 0.5 save_graphics_state do line_width rule_width stroke_color rule_color case rule_style when :dashed dash rule_width * 4 when :dotted dash rule_width when :double stroke_vertical_line rule_y_from, rule_y_to, at: (rule_x - rule_width) rule_x += rule_width end if rule_style stroke_vertical_line rule_y_from, rule_y_to, at: rule_x end end |
#tare_first_page_content_stream ⇒ Object
This method delegates to the provided block, then tares (i.e., resets) the content stream of the initial page.
The purpose of this method is to ink content while making it appear as though the page is empty. This technique allows the caller to detect whether any subsequent content was written to the page following the content inked by the block. It’s often used to keep the title of a content block with the block’s first child.
NOTE: this method should only used inside dry_run since that’s when DetectEmptyFirstPage is active
1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 1068 def tare_first_page_content_stream return yield unless DetectEmptyFirstPage === (delegate = state.on_page_create_callback) on_page_create_called = nil state.on_page_create_callback = proc do |pdf| on_page_create_called = true pdf.state.pages[pdf.page_number - 2].tare_content_stream delegate.call pdf end begin yield ensure page.tare_content_stream unless on_page_create_called state.on_page_create_callback = delegate end end |
#text_with_formatted_first_line(string, first_line_options, options) ⇒ Object
Performs the same work as Prawn::Text.text except that the first_line_options are applied to the first line of text renderered. It’s necessary to use low-level APIs in this method so we only style the first line and not the remaining lines (which is the default behavior in Prawn).
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 469 def text_with_formatted_first_line string, , if (first_line_font_color = .delete :color) remaining_lines_font_color, [:color] = [:color], first_line_font_color end fragments = parse_text string, # NOTE: the low-level APIs we're using don't recognize the :styles option, so we must resolve # NOTE: disabled until we have a need for it; currently handled in convert_abstract #if (styles = options.delete :styles) # options[:style] = resolve_font_style styles #end if (first_line_styles = .delete :styles) [:style] = resolve_font_style first_line_styles end first_line_text_transform = .delete :text_transform = .merge document: self @final_gap = final_gap = .delete :final_gap text_indent = .delete :indent_paragraphs # QUESTION: should we merge more carefully here? (hand-select keys?) = (.merge ).merge single_line: true, first_line: true box = ::Prawn::Text::Formatted::Box.new fragments, if text_indent remaining_fragments = indent(text_indent) { box.render dry_run: true } else remaining_fragments = box.render dry_run: true end if remaining_fragments.empty? remaining_fragments = nil elsif (remaining_fragments[0][:from_page] ||= page_number) != page_number log :error, %(cannot fit formatted text on page: #{remaining_fragments.map {|it| it[:image_path] || it[:text] }.join}) page.tare_content_stream remaining_fragments = nil end if first_line_text_transform # NOTE: applying text transform here could alter the wrapping, so isolate first line and shrink it to fit first_line_fragments = (box.instance_variable_get :@arranger).consumed fragments = first_line_fragments.map {|fragment| fragment.merge text: (transform_text fragment[:text], first_line_text_transform) } [:overflow] = :shrink_to_fit if remaining_fragments @final_gap = true [:force_justify] = true if [:align] == :justify && first_line_fragments[-1][:text] != ?\n end end if text_indent indent(text_indent) { fill_formatted_text_box fragments, } else fill_formatted_text_box fragments, end if remaining_fragments [:color] = remaining_lines_font_color if first_line_font_color @final_gap = final_gap if first_line_text_transform remaining_fragments = fill_formatted_text_box remaining_fragments, draw_remaining_formatted_text_on_new_pages remaining_fragments, end end |
#verso_page?(pgnum = nil) ⇒ Boolean
Returns whether the page is a verso page.
248 249 250 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 248 def verso_page? pgnum = nil (pgnum || page_number).even? end |
#width_of_string(string, options) ⇒ Object
Override width of string to check for placeholder char, which uses character spacing to control width
403 404 405 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 403 def width_of_string string, string == PlaceholderChar ? @character_spacing : super end |
#with_dry_run {|dry_run(&block).position_onto self, cursor| ... } ⇒ Object
979 980 981 |
# File 'lib/asciidoctor/pdf/ext/prawn/extensions.rb', line 979 def with_dry_run &block yield dry_run(&block).position_onto self, cursor end |