prawn 0.14.0 → 0.15.0

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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -1
  3. data/Rakefile +12 -0
  4. data/lib/prawn.rb +9 -21
  5. data/lib/prawn/document.rb +95 -68
  6. data/lib/prawn/document/bounding_box.rb +22 -4
  7. data/lib/prawn/document/column_box.rb +2 -0
  8. data/lib/prawn/document/graphics_state.rb +1 -1
  9. data/lib/prawn/document/internals.rb +2 -2
  10. data/lib/prawn/document/snapshot.rb +2 -1
  11. data/lib/prawn/document/span.rb +2 -0
  12. data/lib/prawn/encoding.rb +1 -1
  13. data/lib/prawn/font.rb +89 -75
  14. data/lib/prawn/font/afm.rb +3 -0
  15. data/lib/prawn/font/dfont.rb +1 -0
  16. data/lib/prawn/font/ttf.rb +2 -0
  17. data/lib/prawn/font_metric_cache.rb +3 -1
  18. data/lib/prawn/graphics.rb +2 -14
  19. data/lib/prawn/graphics/cap_style.rb +1 -0
  20. data/lib/prawn/graphics/color.rb +1 -0
  21. data/lib/prawn/graphics/dash.rb +3 -2
  22. data/lib/prawn/graphics/join_style.rb +2 -0
  23. data/lib/prawn/graphics/patterns.rb +1 -0
  24. data/lib/prawn/graphics/transformation.rb +1 -0
  25. data/lib/prawn/graphics/transparency.rb +2 -0
  26. data/lib/prawn/image_handler.rb +2 -0
  27. data/lib/prawn/images.rb +5 -0
  28. data/lib/prawn/images/image.rb +1 -0
  29. data/lib/prawn/images/jpg.rb +3 -0
  30. data/lib/prawn/images/png.rb +2 -0
  31. data/lib/prawn/layout.rb +8 -13
  32. data/lib/prawn/layout/grid.rb +15 -3
  33. data/lib/prawn/measurement_extensions.rb +4 -0
  34. data/lib/prawn/measurements.rb +2 -0
  35. data/lib/prawn/outline.rb +3 -1
  36. data/lib/prawn/repeater.rb +3 -1
  37. data/lib/prawn/security.rb +15 -7
  38. data/lib/prawn/security/arcfour.rb +52 -0
  39. data/lib/prawn/soft_mask.rb +3 -1
  40. data/lib/prawn/stamp.rb +2 -0
  41. data/lib/prawn/table.rb +2 -0
  42. data/lib/prawn/table/cell.rb +4 -1
  43. data/lib/prawn/table/cell/image.rb +1 -2
  44. data/lib/prawn/table/cell/in_table.rb +2 -0
  45. data/lib/prawn/table/cell/span_dummy.rb +1 -0
  46. data/lib/prawn/table/cells.rb +7 -2
  47. data/lib/prawn/table/column_width_calculator.rb +8 -2
  48. data/lib/prawn/text.rb +4 -2
  49. data/lib/prawn/text/box.rb +3 -0
  50. data/lib/prawn/text/formatted/arranger.rb +2 -0
  51. data/lib/prawn/text/formatted/box.rb +55 -50
  52. data/lib/prawn/text/formatted/fragment.rb +2 -0
  53. data/lib/prawn/text/formatted/line_wrap.rb +1 -0
  54. data/lib/prawn/text/formatted/parser.rb +2 -0
  55. data/lib/prawn/text/formatted/wrap.rb +2 -0
  56. data/lib/prawn/utilities.rb +5 -3
  57. data/manual/graphics/common_lines.rb +2 -0
  58. data/manual/text/group.rb +2 -0
  59. data/manual/text/text.rb +1 -1
  60. data/prawn.gemspec +4 -3
  61. data/spec/grid_spec.rb +11 -0
  62. data/spec/object_store_spec.rb +1 -96
  63. data/spec/reference_spec.rb +0 -57
  64. data/spec/spec_helper.rb +7 -0
  65. data/spec/table_spec.rb +26 -0
  66. metadata +172 -185
  67. data/lib/pdf/core.rb +0 -35
  68. data/lib/pdf/core/annotations.rb +0 -60
  69. data/lib/pdf/core/byte_string.rb +0 -9
  70. data/lib/pdf/core/destinations.rb +0 -90
  71. data/lib/pdf/core/document_state.rb +0 -79
  72. data/lib/pdf/core/filter_list.rb +0 -51
  73. data/lib/pdf/core/filters.rb +0 -36
  74. data/lib/pdf/core/graphics_state.rb +0 -89
  75. data/lib/pdf/core/literal_string.rb +0 -16
  76. data/lib/pdf/core/name_tree.rb +0 -177
  77. data/lib/pdf/core/object_store.rb +0 -311
  78. data/lib/pdf/core/outline.rb +0 -315
  79. data/lib/pdf/core/page.rb +0 -212
  80. data/lib/pdf/core/page_geometry.rb +0 -126
  81. data/lib/pdf/core/pdf_object.rb +0 -99
  82. data/lib/pdf/core/reference.rb +0 -103
  83. data/lib/pdf/core/stream.rb +0 -98
  84. data/lib/pdf/core/text.rb +0 -275
  85. data/lib/prawn/templates.rb +0 -75
  86. data/spec/filters_spec.rb +0 -34
  87. data/spec/name_tree_spec.rb +0 -112
  88. data/spec/pdf_object_spec.rb +0 -172
  89. data/spec/stream_spec.rb +0 -58
  90. data/spec/template_spec_obsolete.rb +0 -352
@@ -1,126 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # Describes PDF page geometries
4
- #
5
- # Copyright April 2008, Gregory Brown. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
-
9
- module PDF
10
- module Core
11
-
12
- # Dimensions pulled from PDF::Writer, rubyforge.org/projects/ruby-pdf
13
- #
14
- # All of these dimensions are in PDF Points (1/72 inch)
15
- #
16
- # ===Inbuilt Sizes:
17
- #
18
- #
19
- # 4A0:: => 4767.87 x 6740.79
20
- # 2A0:: => 3370.39 x 4767.87
21
- # A0:: => 2383.94 x 3370.39
22
- # A1:: => 1683.78 x 2383.94
23
- # A2:: => 1190.55 x 1683.78
24
- # A3:: => 841.89 x 1190.55
25
- # A4:: => 595.28 x 841.89
26
- # A5:: => 419.53 x 595.28
27
- # A6:: => 297.64 x 419.53
28
- # A7:: => 209.76 x 297.64
29
- # A8:: => 147.40 x 209.76
30
- # A9:: => 104.88 x 147.40
31
- # A10:: => 73.70 x 104.88
32
- # B0:: => 2834.65 x 4008.19
33
- # B1:: => 2004.09 x 2834.65
34
- # B2:: => 1417.32 x 2004.09
35
- # B3:: => 1000.63 x 1417.32
36
- # B4:: => 708.66 x 1000.63
37
- # B5:: => 498.90 x 708.66
38
- # B6:: => 354.33 x 498.90
39
- # B7:: => 249.45 x 354.33
40
- # B8:: => 175.75 x 249.45
41
- # B9:: => 124.72 x 175.75
42
- # B10:: => 87.87 x 124.72
43
- # C0:: => 2599.37 x 3676.54
44
- # C1:: => 1836.85 x 2599.37
45
- # C2:: => 1298.27 x 1836.85
46
- # C3:: => 918.43 x 1298.27
47
- # C4:: => 649.13 x 918.43
48
- # C5:: => 459.21 x 649.13
49
- # C6:: => 323.15 x 459.21
50
- # C7:: => 229.61 x 323.15
51
- # C8:: => 161.57 x 229.61
52
- # C9:: => 113.39 x 161.57
53
- # C10:: => 79.37 x 113.39
54
- # RA0:: => 2437.80 x 3458.27
55
- # RA1:: => 1729.13 x 2437.80
56
- # RA2:: => 1218.90 x 1729.13
57
- # RA3:: => 864.57 x 1218.90
58
- # RA4:: => 609.45 x 864.57
59
- # SRA0:: => 2551.18 x 3628.35
60
- # SRA1:: => 1814.17 x 2551.18
61
- # SRA2:: => 1275.59 x 1814.17
62
- # SRA3:: => 907.09 x 1275.59
63
- # SRA4:: => 637.80 x 907.09
64
- # EXECUTIVE:: => 521.86 x 756.00
65
- # FOLIO:: => 612.00 x 936.00
66
- # LEGAL:: => 612.00 x 1008.00
67
- # LETTER:: => 612.00 x 792.00
68
- # TABLOID:: => 792.00 x 1224.00
69
- #
70
- module PageGeometry
71
-
72
- SIZES = { "4A0" => [4767.87, 6740.79],
73
- "2A0" => [3370.39, 4767.87],
74
- "A0" => [2383.94, 3370.39],
75
- "A1" => [1683.78, 2383.94],
76
- "A2" => [1190.55, 1683.78],
77
- "A3" => [841.89, 1190.55],
78
- "A4" => [595.28, 841.89],
79
- "A5" => [419.53, 595.28],
80
- "A6" => [297.64, 419.53],
81
- "A7" => [209.76, 297.64],
82
- "A8" => [147.40, 209.76],
83
- "A9" => [104.88, 147.40],
84
- "A10" => [73.70, 104.88],
85
- "B0" => [2834.65, 4008.19],
86
- "B1" => [2004.09, 2834.65],
87
- "B2" => [1417.32, 2004.09],
88
- "B3" => [1000.63, 1417.32],
89
- "B4" => [708.66, 1000.63],
90
- "B5" => [498.90, 708.66],
91
- "B6" => [354.33, 498.90],
92
- "B7" => [249.45, 354.33],
93
- "B8" => [175.75, 249.45],
94
- "B9" => [124.72, 175.75],
95
- "B10" => [87.87, 124.72],
96
- "C0" => [2599.37, 3676.54],
97
- "C1" => [1836.85, 2599.37],
98
- "C2" => [1298.27, 1836.85],
99
- "C3" => [918.43, 1298.27],
100
- "C4" => [649.13, 918.43],
101
- "C5" => [459.21, 649.13],
102
- "C6" => [323.15, 459.21],
103
- "C7" => [229.61, 323.15],
104
- "C8" => [161.57, 229.61],
105
- "C9" => [113.39, 161.57],
106
- "C10" => [79.37, 113.39],
107
- "RA0" => [2437.80, 3458.27],
108
- "RA1" => [1729.13, 2437.80],
109
- "RA2" => [1218.90, 1729.13],
110
- "RA3" => [864.57, 1218.90],
111
- "RA4" => [609.45, 864.57],
112
- "SRA0" => [2551.18, 3628.35],
113
- "SRA1" => [1814.17, 2551.18],
114
- "SRA2" => [1275.59, 1814.17],
115
- "SRA3" => [907.09, 1275.59],
116
- "SRA4" => [637.80, 907.09],
117
- "EXECUTIVE" => [521.86, 756.00],
118
- "FOLIO" => [612.00, 936.00],
119
- "LEGAL" => [612.00, 1008.00],
120
- "LETTER" => [612.00, 792.00],
121
- "TABLOID" => [792.00, 1224.00] }
122
-
123
- end
124
- end
125
- end
126
-
@@ -1,99 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- # pdf_object.rb : Handles Ruby to PDF object serialization
4
- #
5
- # Copyright April 2008, Gregory Brown. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
-
9
- # Top level Module
10
- #
11
- module PDF
12
- module Core
13
- module_function
14
-
15
- def utf8_to_utf16(str)
16
- "\xFE\xFF".force_encoding(::Encoding::UTF_16BE) + str.encode(::Encoding::UTF_16BE)
17
- end
18
-
19
- # encodes any string into a hex representation. The result is a string
20
- # with only 0-9 and a-f characters. That result is valid ASCII so tag
21
- # it as such to account for behaviour of different ruby VMs
22
- def string_to_hex(str)
23
- str.unpack("H*").first.force_encoding(::Encoding::US_ASCII)
24
- end
25
-
26
- # Serializes Ruby objects to their PDF equivalents. Most primitive objects
27
- # will work as expected, but please note that Name objects are represented
28
- # by Ruby Symbol objects and Dictionary objects are represented by Ruby hashes
29
- # (keyed by symbols)
30
- #
31
- # Examples:
32
- #
33
- # PdfObject(true) #=> "true"
34
- # PdfObject(false) #=> "false"
35
- # PdfObject(1.2124) #=> "1.2124"
36
- # PdfObject("foo bar") #=> "(foo bar)"
37
- # PdfObject(:Symbol) #=> "/Symbol"
38
- # PdfObject(["foo",:bar, [1,2]]) #=> "[foo /bar [1 2]]"
39
- #
40
- def PdfObject(obj, in_content_stream = false)
41
- case(obj)
42
- when NilClass then "null"
43
- when TrueClass then "true"
44
- when FalseClass then "false"
45
- when Numeric
46
- if (str = String(obj)) =~ /e/i
47
- # scientific notation is not supported in PDF
48
- sprintf("%.16f", obj).gsub(/\.?0+\z/, "")
49
- else
50
- str
51
- end
52
- when Array
53
- "[" << obj.map { |e| PdfObject(e, in_content_stream) }.join(' ') << "]"
54
- when PDF::Core::LiteralString
55
- obj = obj.gsub(/[\\\n\r\t\b\f\(\)]/n) { |m| "\\#{m}" }
56
- "(#{obj})"
57
- when Time
58
- obj = obj.strftime("D:%Y%m%d%H%M%S%z").chop.chop + "'00'"
59
- obj = obj.gsub(/[\\\n\r\t\b\f\(\)]/n) { |m| "\\#{m}" }
60
- "(#{obj})"
61
- when PDF::Core::ByteString
62
- "<" << obj.unpack("H*").first << ">"
63
- when String
64
- obj = utf8_to_utf16(obj) unless in_content_stream
65
- "<" << string_to_hex(obj) << ">"
66
- when Symbol
67
- "/" + obj.to_s.unpack("C*").map { |n|
68
- if n < 33 || n > 126 || [35,40,41,47,60,62].include?(n)
69
- "#" + n.to_s(16).upcase
70
- else
71
- [n].pack("C*")
72
- end
73
- }.join
74
- when ::Hash
75
- output = "<< "
76
- obj.each do |k,v|
77
- unless String === k || Symbol === k
78
- raise PDF::Core::Errors::FailedObjectConversion,
79
- "A PDF Dictionary must be keyed by names"
80
- end
81
- output << PdfObject(k.to_sym, in_content_stream) << " " <<
82
- PdfObject(v, in_content_stream) << "\n"
83
- end
84
- output << ">>"
85
- when PDF::Core::Reference
86
- obj.to_s
87
- when PDF::Core::NameTree::Node
88
- PdfObject(obj.to_hash)
89
- when PDF::Core::NameTree::Value
90
- PdfObject(obj.name) + " " + PdfObject(obj.value)
91
- when PDF::Core::OutlineRoot, PDF::Core::OutlineItem
92
- PdfObject(obj.to_hash)
93
- else
94
- raise PDF::Core::Errors::FailedObjectConversion,
95
- "This object cannot be serialized to PDF (#{obj.inspect})"
96
- end
97
- end
98
- end
99
- end
@@ -1,103 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # reference.rb : Implementation of PDF indirect objects
4
- #
5
- # Copyright April 2008, Gregory Brown. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
-
9
-
10
- module PDF
11
- module Core
12
- class Reference #:nodoc:
13
-
14
- attr_accessor :gen, :data, :offset, :stream, :live, :identifier
15
-
16
- def initialize(id, data)
17
- @identifier = id
18
- @gen = 0
19
- @data = data
20
- @stream = Stream.new
21
- end
22
-
23
- def object
24
- output = "#{@identifier} #{gen} obj\n"
25
- unless @stream.empty?
26
- output << PDF::Core::PdfObject(data.merge @stream.data) << "\n" << @stream.object
27
- else
28
- output << PDF::Core::PdfObject(data) << "\n"
29
- end
30
-
31
- output << "endobj\n"
32
- end
33
-
34
- def <<(io)
35
- raise "Cannot attach stream to non-dictionary object" unless @data.is_a?(::Hash)
36
- (@stream ||= Stream.new) << io
37
- end
38
-
39
- def to_s
40
- "#{@identifier} #{gen} R"
41
- end
42
-
43
- # Creates a deep copy of this ref. If +share+ is provided, shares the
44
- # given dictionary entries between the old ref and the new.
45
- #
46
- def deep_copy(share=[])
47
- r = dup
48
-
49
- case r.data
50
- when ::Hash
51
- # Copy each entry not in +share+.
52
- (r.data.keys - share).each do |k|
53
- r.data[k] = Marshal.load(Marshal.dump(r.data[k]))
54
- end
55
- when PDF::Core::NameTree::Node
56
- r.data = r.data.deep_copy
57
- else
58
- r.data = Marshal.load(Marshal.dump(r.data))
59
- end
60
-
61
- r.stream = Marshal.load(Marshal.dump(r.stream))
62
- r
63
- end
64
-
65
- # Replaces the data and stream with that of other_ref.
66
- def replace(other_ref)
67
- @data = other_ref.data
68
- @stream = other_ref.stream
69
- end
70
-
71
- # Marks this and all referenced objects live, recursively.
72
- def mark_live
73
- return if defined?(@live) && @live
74
- @live = true
75
- referenced_objects.each { |o| o.mark_live }
76
- end
77
-
78
- private
79
-
80
- # All objects referenced by this one. Used for GC.
81
- def referenced_objects(obj=@data)
82
- case obj
83
- when self.class
84
- []
85
- when ::Hash
86
- obj.values.map{|v| [v] + referenced_objects(v) }
87
- when Array
88
- obj.map{|v| [v] + referenced_objects(v) }
89
- when PDF::Core::OutlineRoot, PDF::Core::OutlineItem
90
- referenced_objects(obj.to_hash)
91
- else []
92
- end.flatten.grep(self.class)
93
- end
94
-
95
- end
96
-
97
- module_function
98
-
99
- def Reference(*args, &block) #:nodoc:
100
- Reference.new(*args, &block)
101
- end
102
- end
103
- end
@@ -1,98 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # prawn/core/stream.rb : Implements Stream objects
4
- #
5
- # Copyright February 2013, Alexander Mankuta. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
-
9
- module PDF
10
- module Core
11
- class Stream
12
- attr_reader :filters
13
-
14
- def initialize(io = nil)
15
- @filtered_stream = ''
16
- @stream = io
17
- @filters = FilterList.new
18
- end
19
-
20
- def <<(io)
21
- (@stream ||= '') << io
22
- @filtered_stream = nil
23
- self
24
- end
25
-
26
- def compress!
27
- unless @filters.names.include? :FlateDecode
28
- @filtered_stream = nil
29
- @filters << :FlateDecode
30
- end
31
- end
32
-
33
- def compressed?
34
- @filters.names.include? :FlateDecode
35
- end
36
-
37
- def empty?
38
- @stream.nil?
39
- end
40
-
41
- def filtered_stream
42
- if @stream
43
- if @filtered_stream.nil?
44
- @filtered_stream = @stream.dup
45
-
46
- @filters.each do |(filter_name, params)|
47
- if filter = PDF::Core::Filters.const_get(filter_name)
48
- @filtered_stream = filter.encode @filtered_stream, params
49
- end
50
- end
51
- end
52
-
53
- @filtered_stream
54
- # XXX Fillter stream
55
- else
56
- nil
57
- end
58
- end
59
-
60
- def length
61
- @stream.length
62
- end
63
-
64
- def object
65
- if filtered_stream
66
- "stream\n#{filtered_stream}\nendstream\n"
67
- else
68
- ''
69
- end
70
- end
71
-
72
- def data
73
- if @stream
74
- filter_names = @filters.names
75
- filter_params = @filters.decode_params
76
-
77
- d = {
78
- :Length => filtered_stream.length
79
- }
80
- if filter_names.any?
81
- d[:Filter] = filter_names
82
- end
83
- if filter_params.any? {|f| !f.nil? }
84
- d[:DecodeParms] = filter_params
85
- end
86
-
87
- d
88
- else
89
- {}
90
- end
91
- end
92
-
93
- def inspect
94
- "#<#{self.class.name}:0x#{'%014x' % object_id} @stream=#{@stream.inspect}, @filters=#{@filters.inspect}>"
95
- end
96
- end
97
- end
98
- end
@@ -1,275 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # prawn/core/text.rb : Implements low level text helpers for Prawn
4
- #
5
- # Copyright January 2010, Daniel Nelson. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
-
9
- module PDF
10
- module Core
11
- module Text #:nodoc:
12
-
13
- # These should be used as a base. Extensions may build on this list
14
- #
15
- VALID_OPTIONS = [:kerning, :size, :style]
16
- MODES = { :fill => 0, :stroke => 1, :fill_stroke => 2, :invisible => 3,
17
- :fill_clip => 4, :stroke_clip => 5, :fill_stroke_clip => 6,
18
- :clip => 7 }
19
-
20
- attr_reader :skip_encoding
21
-
22
- # Low level text placement method. All font and size alterations
23
- # should already be set
24
- #
25
- def draw_text!(text, options)
26
- x,y = map_to_absolute(options[:at])
27
- add_text_content(text,x,y,options)
28
- end
29
-
30
- # Low level call to set the current font style and extract text options from
31
- # an options hash. Should be called from within a save_font block
32
- #
33
- def process_text_options(options)
34
- if options[:style]
35
- raise "Bad font family" unless font.family
36
- font(font.family, :style => options[:style])
37
- end
38
-
39
- # must compare against false to keep kerning on as default
40
- unless options[:kerning] == false
41
- options[:kerning] = font.has_kerning_data?
42
- end
43
-
44
- options[:size] ||= font_size
45
- end
46
-
47
- # Retrieve the current default kerning setting.
48
- #
49
- # Defaults to true
50
- #
51
- def default_kerning?
52
- return true if !defined?(@default_kerning)
53
- @default_kerning
54
- end
55
-
56
- # Call with a boolean to set the document-wide kerning setting. This can be
57
- # overridden using the :kerning text option when drawing text or a text
58
- # box.
59
- #
60
- # pdf.default_kerning = false
61
- # pdf.text("hello world") # text is not kerned
62
- # pdf.text("hello world", :kerning => true) # text is kerned
63
- #
64
- def default_kerning(boolean)
65
- @default_kerning = boolean
66
- end
67
-
68
- alias_method :default_kerning=, :default_kerning
69
-
70
- # Call with no argument to retrieve the current default leading.
71
- #
72
- # Call with a number to set the document-wide text leading. This can be
73
- # overridden using the :leading text option when drawing text or a text
74
- # box.
75
- #
76
- # pdf.default_leading = 7
77
- # pdf.text("hello world") # a leading of 7 is used
78
- # pdf.text("hello world", :leading => 0) # a leading of 0 is used
79
- #
80
- # Defaults to 0
81
- #
82
- def default_leading(number=nil)
83
- if number.nil?
84
- defined?(@default_leading) && @default_leading || 0
85
- else
86
- @default_leading = number
87
- end
88
- end
89
-
90
- alias_method :default_leading=, :default_leading
91
-
92
- # Call with no argument to retrieve the current text direction.
93
- #
94
- # Call with a symbol to set the document-wide text direction. This can be
95
- # overridden using the :direction text option when drawing text or a text
96
- # box.
97
- #
98
- # pdf.text_direction = :rtl
99
- # pdf.text("hello world") # prints "dlrow olleh"
100
- # pdf.text("hello world", :direction => :ltr) # prints "hello world"
101
- #
102
- # Valid directions are:
103
- #
104
- # * :ltr - left-to-right (default)
105
- # * :rtl - right-to-left
106
- #
107
- # Side effects:
108
- #
109
- # * When printing left-to-right, the default text alignment is :left
110
- # * When printing right-to-left, the default text alignment is :right
111
- #
112
- def text_direction(direction=nil)
113
- if direction.nil?
114
- defined?(@text_direction) && @text_direction || :ltr
115
- else
116
- @text_direction = direction
117
- end
118
- end
119
-
120
- alias_method :text_direction=, :text_direction
121
-
122
- # Call with no argument to retrieve the current fallback fonts.
123
- #
124
- # Call with an array of font names. Each name must be the name of an AFM
125
- # font or the name that was used to register a family of TTF fonts (see
126
- # Prawn::Document#font_families). If present, then each glyph will be
127
- # rendered using the first font that includes the glyph, starting with the
128
- # current font and then moving through :fallback_fonts from left to right.
129
- #
130
- # Call with an empty array to turn off fallback fonts
131
- #
132
- # file = "#{Prawn::DATADIR}/fonts/gkai00mp.ttf"
133
- # font_families["Kai"] = {
134
- # :normal => { :file => file, :font => "Kai" }
135
- # }
136
- # file = "#{Prawn::DATADIR}/fonts/Action Man.dfont"
137
- # font_families["Action Man"] = {
138
- # :normal => { :file => file, :font => "ActionMan" },
139
- # }
140
- # fallback_fonts ["Times-Roman", "Kai"]
141
- # font "Action Man"
142
- # text "hello ƒ 你好"
143
- # > hello prints in Action Man
144
- # > ƒ prints in Times-Roman
145
- # > 你好 prints in Kai
146
- #
147
- # fallback_fonts [] # clears document-wide fallback fonts
148
- #
149
- # Side effects:
150
- #
151
- # * Increased overhead when fallback fonts are declared as each glyph is
152
- # checked to see whether it exists in the current font
153
- #
154
- def fallback_fonts(fallback_fonts=nil)
155
- if fallback_fonts.nil?
156
- defined?(@fallback_fonts) && @fallback_fonts || []
157
- else
158
- @fallback_fonts = fallback_fonts
159
- end
160
- end
161
-
162
- alias_method :fallback_fonts=, :fallback_fonts
163
-
164
- # Call with no argument to retrieve the current text rendering mode.
165
- #
166
- # Call with a symbol and block to temporarily change the current
167
- # text rendering mode.
168
- #
169
- # pdf.text_rendering_mode(:stroke) do
170
- # pdf.text("Outlined Text")
171
- # end
172
- #
173
- # Valid modes are:
174
- #
175
- # * :fill - fill text (default)
176
- # * :stroke - stroke text
177
- # * :fill_stroke - fill, then stroke text
178
- # * :invisible - invisible text
179
- # * :fill_clip - fill text then add to path for clipping
180
- # * :stroke_clip - stroke text then add to path for clipping
181
- # * :fill_stroke_clip - fill then stroke text, then add to path for clipping
182
- # * :clip - add text to path for clipping
183
- #
184
- # There's the special mode :unknown which only occurs when we're working
185
- # with templates. If left in :unknown, the first text command will force
186
- # an assertion to :fill.
187
- def text_rendering_mode(mode=nil)
188
- return (defined?(@text_rendering_mode) && @text_rendering_mode || :fill) if mode.nil?
189
- unless MODES.key?(mode)
190
- raise ArgumentError, "mode must be between one of #{MODES.keys.join(', ')} (#{mode})"
191
- end
192
- original_mode = self.text_rendering_mode
193
- if original_mode == :unknown
194
- original_mode = :fill
195
- add_content "\n#{MODES[:fill]} Tr"
196
- end
197
- if original_mode == mode
198
- yield
199
- else
200
- @text_rendering_mode = mode
201
- add_content "\n#{MODES[mode]} Tr"
202
- yield
203
- add_content "\n#{MODES[original_mode]} Tr"
204
- @text_rendering_mode = original_mode
205
- end
206
- end
207
-
208
- def forget_text_rendering_mode!
209
- @text_rendering_mode = :unknown
210
- end
211
-
212
- # Increases or decreases the space between characters.
213
- # For horizontal text, a positive value will increase the space.
214
- # For veritical text, a positive value will decrease the space.
215
- #
216
- def character_spacing(amount=nil)
217
- return defined?(@character_spacing) && @character_spacing || 0 if amount.nil?
218
- original_character_spacing = character_spacing
219
- if original_character_spacing == amount
220
- yield
221
- else
222
- @character_spacing = amount
223
- add_content "\n%.3f Tc" % amount
224
- yield
225
- add_content "\n%.3f Tc" % original_character_spacing
226
- @character_spacing = original_character_spacing
227
- end
228
- end
229
-
230
- # Increases or decreases the space between words.
231
- # For horizontal text, a positive value will increase the space.
232
- # For veritical text, a positive value will decrease the space.
233
- #
234
- def word_spacing(amount=nil)
235
- return defined?(@word_spacing) && @word_spacing || 0 if amount.nil?
236
- original_word_spacing = word_spacing
237
- if original_word_spacing == amount
238
- yield
239
- else
240
- @word_spacing = amount
241
- add_content "\n%.3f Tw" % amount
242
- yield
243
- add_content "\n%.3f Tw" % original_word_spacing
244
- @word_spacing = original_word_spacing
245
- end
246
- end
247
-
248
- private
249
-
250
- def add_text_content(text, x, y, options)
251
- chunks = font.encode_text(text,options)
252
-
253
- add_content "\nBT"
254
-
255
- if options[:rotate]
256
- rad = options[:rotate].to_f * Math::PI / 180
257
- arr = [ Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), x, y ]
258
- add_content "%.3f %.3f %.3f %.3f %.3f %.3f Tm" % arr
259
- else
260
- add_content "#{x} #{y} Td"
261
- end
262
-
263
- chunks.each do |(subset, string)|
264
- font.add_to_current_page(subset)
265
- add_content "/#{font.identifier_for(subset)} #{font_size} Tf"
266
-
267
- operation = options[:kerning] && string.is_a?(Array) ? "TJ" : "Tj"
268
- add_content PDF::Core::PdfObject(string, true) << " " << operation
269
- end
270
-
271
- add_content "ET\n"
272
- end
273
- end
274
- end
275
- end