srdperu-prawn-format 0.1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+
3
+ module Prawn
4
+ module Format
5
+ module Effects
6
+
7
+ class Link
8
+ def initialize(target, x)
9
+ @target = target
10
+ @x = x
11
+ end
12
+
13
+ def finish(document, draw_state)
14
+ x1 = draw_state[:real_x] + @x
15
+ x2 = draw_state[:real_x] + draw_state[:dx]
16
+ y = draw_state[:real_y] + draw_state[:dy]
17
+
18
+ rect = [x1, y + draw_state[:line].descent, x2, y + draw_state[:line].ascent]
19
+ if @target.match(/^#/)
20
+ document.link_annotation(rect, :Dest => @target.sub(/^#/,""), :Border => [0,0,0])
21
+ else
22
+ document.link_annotation(rect, :Border => [0,0,0], :A => { :Type => :Action, :S => :URI, :URI => Prawn::LiteralString.new(@target) } )
23
+ end #new
24
+ end
25
+
26
+ def wrap(document, draw_state)
27
+ finish(document, draw_state)
28
+ @x = 0
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ module Prawn
4
+ module Format
5
+ module Effects
6
+
7
+ class Underline
8
+ def initialize(from, state)
9
+ @from = from
10
+ @state = state
11
+ end
12
+
13
+ def finish(document, draw_state)
14
+ x1 = draw_state[:x] + @from
15
+ x2 = draw_state[:x] + draw_state[:dx]
16
+ y = draw_state[:y] + draw_state[:dy] - 2
17
+
18
+ document.stroke_color(@state.color)
19
+ document.move_to(x1, y)
20
+ document.line_to(x2, y)
21
+ document.stroke
22
+ end
23
+
24
+ def wrap(document, draw_state)
25
+ finish(document, draw_state)
26
+ @from = 0
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,62 @@
1
+ # encoding: utf-8
2
+
3
+ module Prawn
4
+ module Format
5
+ module Instructions
6
+
7
+ class Base
8
+ attr_reader :state, :ascent, :descent
9
+
10
+ def initialize(state)
11
+ @state = state
12
+ state.document.font_size(state.font_size) do
13
+ @height = state.font.height
14
+ @ascent = state.font.ascender
15
+ @descent = state.font.descender
16
+ end
17
+ end
18
+
19
+ def spaces
20
+ 0
21
+ end
22
+
23
+ def width(*args)
24
+ 0
25
+ end
26
+
27
+ def height(*args)
28
+ @height
29
+ end
30
+
31
+ def break?
32
+ false
33
+ end
34
+
35
+ def force_break?
36
+ false
37
+ end
38
+
39
+ def discardable?
40
+ false
41
+ end
42
+
43
+ def start_verbatim?
44
+ false
45
+ end
46
+
47
+ def end_verbatim?
48
+ false
49
+ end
50
+
51
+ def style
52
+ {}
53
+ end
54
+
55
+ def accumulate(list)
56
+ list.push(self)
57
+ end
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ require 'prawn/format/instructions/base'
4
+
5
+ module Prawn
6
+ module Format
7
+ module Instructions
8
+
9
+ class TagClose < Base
10
+ def self.close(state, tag, draw_state)
11
+ closer = new(state, tag)
12
+ closer.draw(state.document, draw_state)
13
+ end
14
+
15
+ attr_reader :tag
16
+
17
+ def initialize(state, tag)
18
+ super(state)
19
+ @tag = tag
20
+ end
21
+
22
+ def [](property)
23
+ @tag[:style][property]
24
+ end
25
+
26
+ def draw(document, draw_state, options={})
27
+ (@tag[:effects] || []).each do |effect|
28
+ effect.finish(document, draw_state)
29
+ draw_state[:pending_effects].delete(effect)
30
+ end
31
+ end
32
+
33
+ def break?
34
+ force_break?
35
+ end
36
+
37
+ def style
38
+ @tag[:style]
39
+ end
40
+
41
+ def force_break?
42
+ @tag[:style][:display] == :break
43
+ end
44
+
45
+ def end_verbatim?
46
+ @tag[:style][:white_space] == :pre
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,95 @@
1
+ # encoding: utf-8
2
+
3
+ require 'prawn/format/instructions/base'
4
+ require 'prawn/format/effects/link'
5
+ require 'prawn/format/effects/underline'
6
+
7
+ module Prawn
8
+ module Format
9
+ module Instructions
10
+
11
+ class TagOpen < Base
12
+ attr_reader :tag
13
+
14
+ def initialize(state, tag)
15
+ super(state)
16
+ @tag = tag
17
+ end
18
+
19
+ def draw(document, draw_state, options={})
20
+ draw_width(document, draw_state)
21
+ draw_destination(document, draw_state)
22
+ draw_link(document, draw_state)
23
+ draw_underline(document, draw_state)
24
+ end
25
+
26
+ def start_verbatim?
27
+ @tag[:style][:white_space] == :pre
28
+ end
29
+
30
+ def style
31
+ @tag[:style]
32
+ end
33
+
34
+ def width
35
+ @state.width
36
+ end
37
+
38
+ private
39
+
40
+ def draw_width(document, draw_state)
41
+ if width > 0
42
+ draw_state[:dx] += width
43
+ draw_state[:text].move_to(draw_state[:dx], draw_state[:dy])
44
+ end
45
+ end
46
+
47
+ def draw_destination(document, draw_state)
48
+ return unless tag[:style][:anchor]
49
+
50
+ x = draw_state[:real_x]
51
+ y = draw_state[:real_y] + draw_state[:dy] + ascent
52
+
53
+ label, destination = case tag[:style][:anchor]
54
+ when /^zoom=([\d\.]+):(.*)$/
55
+ [$2, document.dest_xyz(x, y, $1.to_f)]
56
+ when /^fit:(.*)$/
57
+ [$1, document.dest_fit]
58
+ when /^fith:(.*)$/
59
+ [$1, document.dest_fit_horizontally(y)]
60
+ when /^fitv:(.*)$/
61
+ [$1, document.dest_fit_vertically(x)]
62
+ when /^fitb:(.*)$/
63
+ [$1, document.dest_fit_bounds]
64
+ when /^fitbh:(.*)$/
65
+ [$1, document.dest_fit_bounds_horizontally(y)]
66
+ when /^fitbv:(.*)$/
67
+ [$1, document.dest_fit_bounds_vertically(x)]
68
+ else
69
+ [tag[:style][:anchor], document.dest_fit_bounds]
70
+ end
71
+
72
+ document.add_dest(label, destination)
73
+ end
74
+
75
+ def draw_link(document, draw_state)
76
+ return unless tag[:style][:target]
77
+ add_effect(Effects::Link.new(tag[:style][:target], draw_state[:dx]), draw_state)
78
+ end
79
+
80
+ def draw_underline(document, draw_state)
81
+ return unless tag[:style][:text_decoration] == :underline
82
+ add_effect(Effects::Underline.new(draw_state[:dx], @state), draw_state)
83
+ end
84
+
85
+ def add_effect(effect, draw_state)
86
+ tag[:effects] ||= []
87
+ tag[:effects].push(effect)
88
+
89
+ draw_state[:pending_effects].push(effect)
90
+ end
91
+ end
92
+
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,89 @@
1
+ # encoding: utf-8
2
+
3
+ require 'prawn/format/instructions/base'
4
+
5
+ module Prawn
6
+ module Format
7
+ module Instructions
8
+
9
+ class Text < Base
10
+ attr_reader :text
11
+
12
+ def initialize(state, text, options={})
13
+ super(state)
14
+ @text = text
15
+ @break = options.key?(:break) ? options[:break] : text.index(/[-\xE2\x80\x94\s]/)
16
+ @discardable = options.key?(:discardable) ? options[:discardable] : text.index(/\s/)
17
+ state.font.normalize_encoding(@text) if options.fetch(:normalize, true)
18
+ end
19
+
20
+ def dup
21
+ self.class.new(state, @text.dup, :normalize => false,
22
+ :break => @break, :discardable => @discardable)
23
+ end
24
+
25
+ def accumulate(list)
26
+ if list.last.is_a?(Text) && list.last.state == state
27
+ list.last.text << @text
28
+ else
29
+ list.push(dup)
30
+ end
31
+
32
+ return list
33
+ end
34
+
35
+ def spaces
36
+ @spaces ||= @text.scan(/ /).length
37
+ end
38
+
39
+ def height(ignore_discardable=false)
40
+ if ignore_discardable && discardable?
41
+ 0
42
+ else
43
+ @height
44
+ end
45
+ end
46
+
47
+ def break?
48
+ @break
49
+ end
50
+
51
+ def discardable?
52
+ @discardable
53
+ end
54
+
55
+ def compatible?(with)
56
+ with.is_a?(self.class) && with.state == state
57
+ end
58
+
59
+ def width(type=:all)
60
+ @width ||= @state.font.compute_width_of(@text, :size => @state.font_size, :kerning => @state.kerning?)
61
+
62
+ case type
63
+ when :discardable then discardable? ? @width : 0
64
+ when :nondiscardable then discardable? ? 0 : @width
65
+ else @width
66
+ end
67
+ end
68
+
69
+ def to_s
70
+ @text
71
+ end
72
+
73
+ def draw(document, draw_state, options={})
74
+ @state.apply!(draw_state[:text], draw_state[:cookies])
75
+
76
+ encoded_text = @state.font.encode_text(@text, :kerning => @state.kerning?)
77
+ encoded_text.each do |subset, chunk|
78
+ @state.apply_font!(draw_state[:text], draw_state[:cookies], subset)
79
+ draw_state[:text].show(chunk)
80
+ end
81
+ draw_state[:dx] += width
82
+
83
+ draw_state[:dx] += draw_state[:padding] * spaces if draw_state[:padding]
84
+ end
85
+ end
86
+
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,113 @@
1
+ # encoding: utf-8
2
+
3
+ require 'prawn/format/line'
4
+ require 'prawn/format/parser'
5
+
6
+ module Prawn
7
+ module Format
8
+ class LayoutBuilder
9
+ attr_reader :document, :options
10
+
11
+ def initialize(document, text, options={})
12
+ @document = document
13
+ @options = options
14
+ @tags = document.tags.merge(options[:tags] || {})
15
+ @styles = document.styles.merge(options[:styles] || {})
16
+ style = document.default_style.merge(options[:default_style] || {})
17
+
18
+ translate_prawn_options(style, options)
19
+
20
+ @parser = Parser.new(@document, text,
21
+ :tags => @tags, :styles => @styles, :style => style)
22
+
23
+ @state = {}
24
+ end
25
+
26
+ def done?
27
+ @parser.eos?
28
+ end
29
+
30
+ def word_wrap(width, options={}, &block)
31
+ if options[:height] && block
32
+ raise ArgumentError, "cannot specify both height and a block"
33
+ elsif options[:height]
34
+ block = Proc.new { |l, h| h > options[:height] }
35
+ elsif block.nil?
36
+ block = Proc.new { |l, h| false }
37
+ end
38
+
39
+ lines = []
40
+ total_height = 0
41
+
42
+ while (line = self.next(width))
43
+ if block[line, total_height + line.height]
44
+ unget(line)
45
+ break
46
+ end
47
+
48
+ total_height += line.height
49
+ lines.push(line)
50
+ end
51
+
52
+ return lines
53
+ end
54
+
55
+ def fill(x, y, width, fill_options={}, &block)
56
+ lines = word_wrap(width, fill_options, &block)
57
+ draw_options = options.merge(fill_options).merge(:state => @state)
58
+ @state = document.draw_lines(x, y, width, lines, draw_options)
59
+ @state.delete(:cookies)
60
+ return @state[:dy] + y
61
+ end
62
+
63
+ def next(line_width=nil)
64
+ line = []
65
+ width = 0
66
+ break_at = nil
67
+
68
+ while (instruction = @parser.next)
69
+ next if !@parser.verbatim? && line.empty? && instruction.discardable? # ignore discardables at line start
70
+ line.push(instruction)
71
+
72
+ if instruction.break?
73
+ width += instruction.width(:nondiscardable)
74
+ break_at = line.length if line_width && width <= line_width
75
+ width += instruction.width(:discardable)
76
+ else
77
+ width += instruction.width
78
+ end
79
+
80
+ if instruction.force_break? || line_width && width >= line_width
81
+ break_at ||= line.length
82
+
83
+ @parser.push(line.pop) while line.length > break_at
84
+ hard_break = instruction.force_break? || @parser.eos?
85
+
86
+ return Line.new(line, hard_break)
87
+ end
88
+ end
89
+
90
+ Line.new(line, true) if line.any?
91
+ end
92
+
93
+ def unget(line)
94
+ line.source.reverse_each { |instruction| @parser.push(instruction) }
95
+ end
96
+
97
+ def translate_prawn_options(style, options)
98
+ style[:kerning] = options[:kerning] if options.key?(:kerning)
99
+ style[:font_size] = options[:size] if options.key?(:size)
100
+
101
+ case options[:style]
102
+ when :bold then
103
+ style[:font_weight] = :bold
104
+ when :italic then
105
+ style[:font_style] = :italic
106
+ when :bold_italic then
107
+ style[:font_weight] = :bold
108
+ style[:font_style] = :italic
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end