From 89fc18f7861e81e43c2469187522b067aa33ff76 Mon Sep 17 00:00:00 2001 From: Dan Allen Date: Fri, 12 Jun 2015 00:17:28 -0600 Subject: [PATCH] resolves #185 autofit font size in listing & literal blocks - autofit (reduce font size) to prevent wrapping in listing & literal blocks - prevent font size from being reduced more than *_font_size_min - activate autofit if autofit option is specified on block - activate autofit if autofit-option attribute is specified on document - add autofit example to chronicles.adoc - add additional helper methods to core_ext --- data/themes/default-theme.yml | 1 + examples/chronicles.adoc | 22 +++--- examples/chronicles.pdf | Bin 193016 -> 193698 bytes lib/asciidoctor-pdf/converter.rb | 95 ++++++++++++++++++++++-- lib/asciidoctor-pdf/core_ext.rb | 3 + lib/asciidoctor-pdf/core_ext/array.rb | 14 +++- lib/asciidoctor-pdf/core_ext/numeric.rb | 11 +++ 7 files changed, 126 insertions(+), 20 deletions(-) create mode 100644 lib/asciidoctor-pdf/core_ext.rb create mode 100644 lib/asciidoctor-pdf/core_ext/numeric.rb diff --git a/data/themes/default-theme.yml b/data/themes/default-theme.yml index a6194b0d7..a173b4630 100644 --- a/data/themes/default-theme.yml +++ b/data/themes/default-theme.yml @@ -52,6 +52,7 @@ base: line_height: $base_line_height_length / $base_font_size font_size_large: round($base_font_size * 1.25) font_size_small: round($base_font_size * 0.85) + font_size_min: $base_font_size * 0.75 font_style: normal align: justify border_radius: 4 diff --git a/examples/chronicles.adoc b/examples/chronicles.adoc index 6470090f0..ba96dcf1d 100644 --- a/examples/chronicles.adoc +++ b/examples/chronicles.adoc @@ -268,31 +268,35 @@ code { ``` Where could we go without some Java? +Naturally, some autosizing is necessary. -```java +[source%autofit,java] +---- package org.javaee7.cdi.events; import javax.enterprise.context.SessionScoped; import javax.enterprise.event.Observes; -import java.io.Serializable; +import java.util.*; +import javax.ws.rs.*; /** * @author The Duke */ @SessionScoped -public class GreetingReceiver implements EventReceiver, Serializable { - private String greet = "Willkommen"; +public class GreetingReceiver implements EventReceiver, java.io.Serializable { + private List greetings = new ArrayList(); void receive(@Observes String greet) { - this.greet = greet; + this.greetings.add(greet); } - @Override - public String getGreet() { - return greet; + @GET @Produces("application/json") + public List listAll(@QueryParam("start") Integer start, @QueryParam("max") Integer max) { + // TODO implement filtering by start and max + this.greetings; } } -``` +---- We already showed you an XML example in <>. diff --git a/examples/chronicles.pdf b/examples/chronicles.pdf index 068c9897c083012237793729c1005f93e1b4839c..75e142b01593f60f7014be57b0f2029fedc52693 100644 GIT binary patch delta 15676 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 G`~LuO?V-~E delta 14978 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 E0BliknE(I) diff --git a/lib/asciidoctor-pdf/converter.rb b/lib/asciidoctor-pdf/converter.rb index e22bca518..e881dfc34 100644 --- a/lib/asciidoctor-pdf/converter.rb +++ b/lib/asciidoctor-pdf/converter.rb @@ -1,6 +1,6 @@ # encoding: UTF-8 # TODO cleanup imports...decide what belongs in asciidoctor-pdf.rb -require_relative 'core_ext/array' +require_relative 'core_ext' require 'prawn' require 'prawn-svg' require 'prawn/table' @@ -67,6 +67,7 @@ def self.unicode_char number # CalloutExtractRx synced from /lib/asciidoctor.rb of Asciidoctor core CalloutExtractRx = /(?:(?:\/\/|#|--|;;) ?)?(\\)?(?=(?: ?\\?)*$)/ ImageAttributeValueRx = /^image:{1,2}(.*?)\[(.*?)\]$/ + LineScanRx = /\n|.+/ def initialize backend, opts super @@ -864,7 +865,7 @@ def convert_image node unlink_tmp_file image_path end - # TODO shrink text if it's too wide to fit in the bounding box + # QUESTION can we avoid arranging fragments multiple times (conums & autofit) by eagerly preparing arranger? def convert_listing_or_literal node add_dest_for_block node if node.id # HACK disable built-in syntax highlighter; must be done before calling node.content! @@ -873,13 +874,11 @@ def convert_listing_or_literal node highlighter = node.document.attr 'source-highlighter' # NOTE the source highlighter logic below handles the callouts and highlight subs prev_subs = subs.dup - subs.delete :callouts - subs.delete :highlight + subs.delete_all :highlight, :callouts else highlighter = nil prev_subs = nil end - # FIXME source highlighter freaks out about the non-breaking space characters; does it? source_string = preserve_indentation node.content source_chunks = case highlighter when 'coderay' @@ -897,7 +896,11 @@ def convert_listing_or_literal node conum_mapping ? (restore_conums fragments, conum_mapping) : fragments else # NOTE only format if we detect a need - (source_string =~ BuiltInEntityCharOrTagRx) ? (text_formatter.format source_string) : [{ text: source_string }] + if source_string =~ BuiltInEntityCharOrTagRx + text_formatter.format source_string + else + [{ text: source_string }] + end end node.subs.replace prev_subs if prev_subs @@ -905,6 +908,12 @@ def convert_listing_or_literal node #move_down @theme.block_margin_top unless at_page_top? theme_margin :block, :top + if (node.option? 'autofit') || (node.document.attr? 'autofit-option') + adjusted_font_size = theme_font_size_autofit source_chunks, :code + else + adjusted_font_size = nil + end + keep_together do |box_height = nil| caption_height = node.title? ? (layout_caption node) : 0 theme_font :code do @@ -927,7 +936,9 @@ def convert_listing_or_literal node end pad_box @theme.code_padding do - typeset_formatted_text source_chunks, (calc_line_metrics @theme.code_line_height), color: (@theme.code_font_color || @font_color) + typeset_formatted_text source_chunks, (calc_line_metrics @theme.code_line_height), + color: (@theme.code_font_color || @font_color), + size: adjusted_font_size end end end @@ -962,6 +973,9 @@ def extract_conums string end # Restore the conums into the Array of formatted text fragments + #-- + # QUESTION can this be done more efficiently? + # QUESTION can we reuse arrange_fragments_by_line? def restore_conums fragments, conum_mapping lines = [] line_num = 0 @@ -2004,6 +2018,73 @@ def theme_font category, opts = {} @text_transform = prev_transform if transform end + # Calculate the font size (down to the minimum font size) that would allow + # all the specified fragments to fit in the available width without wrapping lines. + # + # Return the calculated font size if an adjustment is necessary or nil if no + # font size adjustment is necessary. + def theme_font_size_autofit fragments, category + arranger = arrange_fragments_by_line fragments + adjusted_font_size = nil + theme_font category do + # NOTE finalizing the line here generates fragments using current font settings + arranger.finalize_line + actual_width = width_of_fragments arranger.fragments + unless ::Array === (padding = @theme[%(#{category}_padding)]) + padding = [padding] * 4 + end + bounds.add_left_padding(p_left = padding[3] || 0) + bounds.add_right_padding(p_right = padding[1] || 0) + if actual_width > bounds.width + adjusted_font_size = ((bounds.width * font_size).to_f / actual_width).with_precision 4 + if (min = @theme[%(#{category}_font_size_min)] || @theme.base_font_size_min) && adjusted_font_size < min + adjusted_font_size = min + end + end + bounds.subtract_left_padding p_left + bounds.subtract_right_padding p_right + end + adjusted_font_size + end + + # Arrange fragments by line in an arranger and return an unfinalized arranger. + # + # Finalizing the arranger is deferred since it must be done in the context of + # the global font settings you want applied to each fragment. + def arrange_fragments_by_line fragments, opts = {} + arranger = ::Prawn::Text::Formatted::Arranger.new self + by_line = arranger.consumed = [] + fragments.each do |fragment| + if (txt = fragment[:text]) == EOL + by_line << fragment + elsif txt.include? EOL + txt.scan(LineScanRx) do |line| + by_line << fragment.merge(text: line) + end + else + by_line << fragment + end + end + arranger + end + + # Calculate the width that is needed to print all the + # fragments without wrapping any lines. + # + # This method assumes endlines are represented as discrete entries in the + # fragments array. + def width_of_fragments fragments + line_widths = [0] + fragments.each do |fragment| + if fragment.text == EOL + line_widths << 0 + else + line_widths[-1] += fragment.width + end + end + line_widths.max + end + # TODO document me, esp the first line formatting functionality def typeset_text string, line_metrics, opts = {} move_down line_metrics.padding_top diff --git a/lib/asciidoctor-pdf/core_ext.rb b/lib/asciidoctor-pdf/core_ext.rb new file mode 100644 index 000000000..1a63df710 --- /dev/null +++ b/lib/asciidoctor-pdf/core_ext.rb @@ -0,0 +1,3 @@ +require_relative 'core_ext/array' +require_relative 'core_ext/numeric' +#require_relative 'core_ext/ostruct' diff --git a/lib/asciidoctor-pdf/core_ext/array.rb b/lib/asciidoctor-pdf/core_ext/array.rb index e1ac36d75..8bb7f502e 100644 --- a/lib/asciidoctor-pdf/core_ext/array.rb +++ b/lib/asciidoctor-pdf/core_ext/array.rb @@ -1,5 +1,11 @@ class Array - def to_h - Hash[to_a] - end unless respond_to? :to_h -end if RUBY_VERSION < '2.1.0' + if RUBY_VERSION < '2.1.0' + def to_h + Hash[to_a] + end unless respond_to? :to_h + end + + def delete_all *entries + entries.map {|entry| delete entry }.compact + end unless respond_to? :delete_all +end diff --git a/lib/asciidoctor-pdf/core_ext/numeric.rb b/lib/asciidoctor-pdf/core_ext/numeric.rb new file mode 100644 index 000000000..3d246652e --- /dev/null +++ b/lib/asciidoctor-pdf/core_ext/numeric.rb @@ -0,0 +1,11 @@ +class Numeric + def with_precision precision + precision = precision.to_i + if precision > 0 + factor = 10 ** precision + (self * factor).truncate / factor.to_f + else + self.truncate + end + end unless respond_to? :with_precision +end