prawn 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
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