thinreports 0.6.0.pre3

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 (146) hide show
  1. data/.yardopts +1 -0
  2. data/README.rdoc +100 -0
  3. data/Rakefile +10 -0
  4. data/doc/yardoc_templates/default/layout/html/footer.erb +10 -0
  5. data/lib/thinreports.rb +11 -0
  6. data/lib/thinreports/core.rb +20 -0
  7. data/lib/thinreports/core/errors.rb +58 -0
  8. data/lib/thinreports/core/events.rb +71 -0
  9. data/lib/thinreports/core/ext.rb +5 -0
  10. data/lib/thinreports/core/ext/array.rb +19 -0
  11. data/lib/thinreports/core/ext/hash.rb +19 -0
  12. data/lib/thinreports/core/ext/object.rb +25 -0
  13. data/lib/thinreports/core/format.rb +14 -0
  14. data/lib/thinreports/core/format/base.rb +93 -0
  15. data/lib/thinreports/core/format/builder.rb +65 -0
  16. data/lib/thinreports/core/ordered_hash.rb +39 -0
  17. data/lib/thinreports/core/page.rb +91 -0
  18. data/lib/thinreports/core/shape.rb +53 -0
  19. data/lib/thinreports/core/shape/base.rb +16 -0
  20. data/lib/thinreports/core/shape/base/interface.rb +38 -0
  21. data/lib/thinreports/core/shape/base/internal.rb +60 -0
  22. data/lib/thinreports/core/shape/basic.rb +15 -0
  23. data/lib/thinreports/core/shape/basic/format.rb +26 -0
  24. data/lib/thinreports/core/shape/basic/interface.rb +57 -0
  25. data/lib/thinreports/core/shape/basic/internal.rb +29 -0
  26. data/lib/thinreports/core/shape/list.rb +25 -0
  27. data/lib/thinreports/core/shape/list/configuration.rb +33 -0
  28. data/lib/thinreports/core/shape/list/events.rb +30 -0
  29. data/lib/thinreports/core/shape/list/format.rb +72 -0
  30. data/lib/thinreports/core/shape/list/manager.rb +209 -0
  31. data/lib/thinreports/core/shape/list/page.rb +118 -0
  32. data/lib/thinreports/core/shape/list/page_state.rb +40 -0
  33. data/lib/thinreports/core/shape/list/section_format.rb +32 -0
  34. data/lib/thinreports/core/shape/list/section_interface.rb +48 -0
  35. data/lib/thinreports/core/shape/list/section_internal.rb +29 -0
  36. data/lib/thinreports/core/shape/list/store.rb +34 -0
  37. data/lib/thinreports/core/shape/manager.rb +14 -0
  38. data/lib/thinreports/core/shape/manager/format.rb +28 -0
  39. data/lib/thinreports/core/shape/manager/internal.rb +87 -0
  40. data/lib/thinreports/core/shape/manager/target.rb +85 -0
  41. data/lib/thinreports/core/shape/tblock.rb +16 -0
  42. data/lib/thinreports/core/shape/tblock/format.rb +36 -0
  43. data/lib/thinreports/core/shape/tblock/formatter.rb +32 -0
  44. data/lib/thinreports/core/shape/tblock/formatter/basic.rb +38 -0
  45. data/lib/thinreports/core/shape/tblock/formatter/datetime.rb +21 -0
  46. data/lib/thinreports/core/shape/tblock/formatter/number.rb +49 -0
  47. data/lib/thinreports/core/shape/tblock/formatter/padding.rb +43 -0
  48. data/lib/thinreports/core/shape/tblock/interface.rb +52 -0
  49. data/lib/thinreports/core/shape/tblock/internal.rb +70 -0
  50. data/lib/thinreports/core/shape/text.rb +15 -0
  51. data/lib/thinreports/core/shape/text/format.rb +25 -0
  52. data/lib/thinreports/core/shape/text/interface.rb +16 -0
  53. data/lib/thinreports/core/shape/text/internal.rb +17 -0
  54. data/lib/thinreports/core/utils.rb +48 -0
  55. data/lib/thinreports/generator.rb +30 -0
  56. data/lib/thinreports/generator/base.rb +49 -0
  57. data/lib/thinreports/generator/pdf.rb +63 -0
  58. data/lib/thinreports/generator/pdf/document.rb +171 -0
  59. data/lib/thinreports/generator/pdf/document/draw_shape.rb +74 -0
  60. data/lib/thinreports/generator/pdf/document/font.rb +59 -0
  61. data/lib/thinreports/generator/pdf/document/graphics.rb +42 -0
  62. data/lib/thinreports/generator/pdf/document/graphics/attributes.rb +92 -0
  63. data/lib/thinreports/generator/pdf/document/graphics/basic.rb +132 -0
  64. data/lib/thinreports/generator/pdf/document/graphics/image.rb +51 -0
  65. data/lib/thinreports/generator/pdf/document/graphics/text.rb +130 -0
  66. data/lib/thinreports/generator/pdf/document/parse_color.rb +51 -0
  67. data/lib/thinreports/generator/pdf/document/parse_svg.rb +102 -0
  68. data/lib/thinreports/generator/pdf/drawer.rb +16 -0
  69. data/lib/thinreports/generator/pdf/drawer/base.rb +56 -0
  70. data/lib/thinreports/generator/pdf/drawer/list.rb +39 -0
  71. data/lib/thinreports/generator/pdf/drawer/list_section.rb +46 -0
  72. data/lib/thinreports/generator/pdf/drawer/page.rb +101 -0
  73. data/lib/thinreports/generator/pdf/prawn_ext.rb +36 -0
  74. data/lib/thinreports/generator/pxd.rb +75 -0
  75. data/lib/thinreports/generator/pxd/helper.rb +33 -0
  76. data/lib/thinreports/generator/pxd/list_renderer.rb +58 -0
  77. data/lib/thinreports/generator/pxd/page_renderer.rb +75 -0
  78. data/lib/thinreports/layout.rb +17 -0
  79. data/lib/thinreports/layout/base.rb +78 -0
  80. data/lib/thinreports/layout/configuration.rb +27 -0
  81. data/lib/thinreports/layout/format.rb +77 -0
  82. data/lib/thinreports/layout/version.rb +43 -0
  83. data/lib/thinreports/report.rb +31 -0
  84. data/lib/thinreports/report/base.rb +160 -0
  85. data/lib/thinreports/report/events.rb +32 -0
  86. data/lib/thinreports/report/internal.rb +131 -0
  87. data/resources/fonts/IPA_Font_License_Agreement_v1.0.txt +117 -0
  88. data/resources/fonts/ipag.ttf +0 -0
  89. data/resources/fonts/ipagp.ttf +0 -0
  90. data/resources/fonts/ipam.ttf +0 -0
  91. data/resources/fonts/ipamp.ttf +0 -0
  92. data/tasks/clean.rake +6 -0
  93. data/tasks/doc.rake +13 -0
  94. data/tasks/test.rake +18 -0
  95. data/test/unit/core/ext/array_spec.rb +29 -0
  96. data/test/unit/core/ext/hash_spec.rb +29 -0
  97. data/test/unit/core/ext/object_spec.rb +30 -0
  98. data/test/unit/core/format/test_base.rb +148 -0
  99. data/test/unit/core/format/test_builder.rb +114 -0
  100. data/test/unit/core/ordered_hash_spec.rb +51 -0
  101. data/test/unit/core/shape/base/test_interface.rb +52 -0
  102. data/test/unit/core/shape/base/test_internal.rb +109 -0
  103. data/test/unit/core/shape/basic/test_format.rb +59 -0
  104. data/test/unit/core/shape/basic/test_interface.rb +70 -0
  105. data/test/unit/core/shape/basic/test_internal.rb +42 -0
  106. data/test/unit/core/shape/list/test_configuration.rb +52 -0
  107. data/test/unit/core/shape/list/test_events.rb +28 -0
  108. data/test/unit/core/shape/list/test_format.rb +71 -0
  109. data/test/unit/core/shape/list/test_page.rb +10 -0
  110. data/test/unit/core/shape/list/test_page_state.rb +31 -0
  111. data/test/unit/core/shape/list/test_section_format.rb +46 -0
  112. data/test/unit/core/shape/list/test_section_interface.rb +52 -0
  113. data/test/unit/core/shape/list/test_section_internal.rb +30 -0
  114. data/test/unit/core/shape/list/test_store.rb +41 -0
  115. data/test/unit/core/shape/manager/test_format.rb +40 -0
  116. data/test/unit/core/shape/manager/test_internal.rb +137 -0
  117. data/test/unit/core/shape/manager/test_target.rb +109 -0
  118. data/test/unit/core/shape/tblock/formatter/test_basic.rb +24 -0
  119. data/test/unit/core/shape/tblock/formatter/test_datetime.rb +47 -0
  120. data/test/unit/core/shape/tblock/formatter/test_number.rb +76 -0
  121. data/test/unit/core/shape/tblock/formatter/test_padding.rb +72 -0
  122. data/test/unit/core/shape/tblock/test_format.rb +125 -0
  123. data/test/unit/core/shape/tblock/test_formatter.rb +28 -0
  124. data/test/unit/core/shape/tblock/test_interface.rb +40 -0
  125. data/test/unit/core/shape/tblock/test_internal.rb +139 -0
  126. data/test/unit/core/shape/text/test_format.rb +73 -0
  127. data/test/unit/core/shape/text/test_internal.rb +21 -0
  128. data/test/unit/core/test_events.rb +91 -0
  129. data/test/unit/core/test_shape.rb +35 -0
  130. data/test/unit/core/utils_spec.rb +56 -0
  131. data/test/unit/generator/pdf/document/graphics/test_attributes.rb +103 -0
  132. data/test/unit/generator/pdf/document/test_font.rb +54 -0
  133. data/test/unit/generator/pdf/document/test_graphics.rb +43 -0
  134. data/test/unit/generator/pdf/document/test_parse_color.rb +30 -0
  135. data/test/unit/generator/test_base.rb +51 -0
  136. data/test/unit/helper.rb +37 -0
  137. data/test/unit/layout/test_base.rb +92 -0
  138. data/test/unit/layout/test_configuration.rb +46 -0
  139. data/test/unit/layout/test_format.rb +104 -0
  140. data/test/unit/layout/test_version.rb +62 -0
  141. data/test/unit/report/test_base.rb +187 -0
  142. data/test/unit/report/test_events.rb +22 -0
  143. data/test/unit/report/test_internal.rb +234 -0
  144. data/test/unit/test_layout.rb +12 -0
  145. data/test/unit/test_report.rb +30 -0
  146. metadata +218 -0
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+
5
+ module Generator
6
+ # @param [Symbol] type
7
+ # @param report (see ThinReports::Generator::Base#initialize)
8
+ # @param options (see ThinReports::Generator::Base#initialize)
9
+ def self.new(type, report, options = {})
10
+ unless generator = registry[type]
11
+ raise ThinReports::Errors::UnknownGeneratorType
12
+ end
13
+ generator.new(report, options)
14
+ end
15
+
16
+ # @private
17
+ def self.register(type, generator)
18
+ registry[type] = generator
19
+ end
20
+
21
+ # @private
22
+ def self.registry
23
+ @generators ||= {}
24
+ end
25
+ end
26
+ end
27
+
28
+ require 'thinreports/generator/base'
29
+ require 'thinreports/generator/pxd'
30
+ require 'thinreports/generator/pdf'
@@ -0,0 +1,49 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+ module Generator
5
+
6
+ # @abstract
7
+ class Base
8
+ # @return [ThinReports::Report::Base]
9
+ # @private
10
+ attr_reader :report
11
+
12
+ # @return [Hash]
13
+ # @private
14
+ attr_reader :options
15
+
16
+ # @private
17
+ def self.inherited(g)
18
+ Generator.register(g.name.split('::').last.downcase.to_sym, g);
19
+ end
20
+
21
+ # @param [ThinReports::Report::Base] report
22
+ # @param [Hash] options
23
+ def initialize(report, options = {})
24
+ report.finalize
25
+
26
+ @report = report.internal
27
+ @options = options || {}
28
+ end
29
+
30
+ # @return [String]
31
+ # @abstract
32
+ def generate
33
+ raise NotImplementedError
34
+ end
35
+
36
+ # @param [String] filename
37
+ # @abstract
38
+ def generate_file(filename)
39
+ raise NotImplementedError
40
+ end
41
+
42
+ # @private
43
+ def default_layout
44
+ report.default_layout
45
+ end
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,63 @@
1
+ # coding: utf-8
2
+
3
+ require 'prawn'
4
+
5
+ module ThinReports
6
+ module Generator
7
+
8
+ class Pdf < Base
9
+ # @param report (see ThinReports::Generator::Base#initialize)
10
+ # @param [Hash] options
11
+ # @option options [Hash] :security (nil)
12
+ # See Prawn::Document#encrypt_document
13
+ def initialize(report, options)
14
+ super
15
+ @pdf = Document.new(options)
16
+ @drawers = {}
17
+ @current_format = nil
18
+ end
19
+
20
+ # @see ThinReports::Generator::Base#generate
21
+ def generate
22
+ draw_report
23
+ @pdf.render
24
+ end
25
+
26
+ # @see ThinReports::Generator::Base#generate_file
27
+ def generate_file(filename)
28
+ draw_report
29
+ @pdf.render_file(filename)
30
+ end
31
+
32
+ private
33
+
34
+ def draw_report
35
+ report.pages.each do |page|
36
+ draw_page(page)
37
+ end
38
+ end
39
+
40
+ def draw_page(page)
41
+ return @pdf.add_blank_page if page.blank?
42
+
43
+ format = page.layout.format
44
+ # On format change.
45
+ unless @current_format == format.identifier
46
+ @pdf.start_new_page(format)
47
+ else
48
+ @pdf.start_new_page
49
+ end
50
+ drawer(format).draw(page.manager)
51
+ end
52
+
53
+ def drawer(format)
54
+ @drawers[format.identifier] ||= Drawer::Page.new(@pdf, format)
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+
61
+ require 'thinreports/generator/pdf/prawn_ext'
62
+ require 'thinreports/generator/pdf/document'
63
+ require 'thinreports/generator/pdf/drawer'
@@ -0,0 +1,171 @@
1
+ # coding: utf-8
2
+
3
+ require 'thinreports/generator/pdf/document/font'
4
+ require 'thinreports/generator/pdf/document/parse_color'
5
+ require 'thinreports/generator/pdf/document/graphics'
6
+ require 'thinreports/generator/pdf/document/draw_shape'
7
+ require 'thinreports/generator/pdf/document/parse_svg'
8
+
9
+ module ThinReports
10
+ module Generator
11
+
12
+ # @private
13
+ class Pdf::Document
14
+ include Pdf::Font
15
+ include Pdf::ParseColor
16
+ include Pdf::Graphics
17
+ include Pdf::DrawShape
18
+ include Pdf::ParseSVG
19
+
20
+ # @param options (see ThinReports::Generator::Pdf#initialize)
21
+ def initialize(options = {})
22
+ @pdf = Prawn::Document.new(
23
+ :skip_page_creation => true,
24
+ :margin => [0, 0],
25
+ :info => {:Creator => 'ThinReports Generator for Ruby ' +
26
+ ThinReports::VERSION}
27
+ )
28
+ @format_stamp_registry = []
29
+
30
+ # Setup to Prawn::Document.
31
+ setup_fonts
32
+ setup_custom_graphic_states
33
+
34
+ # Encrypts the document.
35
+ if options[:security]
36
+ @pdf.encrypt_document(options[:security])
37
+ end
38
+ end
39
+
40
+ # @param [ThinReports::Layout::Format] format (nil)
41
+ def start_new_page(format = nil)
42
+ options = {}
43
+ format_id = format.identifier
44
+
45
+ if format
46
+ options[:layout] = format.page_orientation.to_sym
47
+ options[:size] = if format.user_paper_type?
48
+ [format.page_width.to_f, format.page_height.to_f]
49
+ else
50
+ format.page_paper_type
51
+ end
52
+ end
53
+
54
+ pdf.start_new_page(options)
55
+
56
+ # @note
57
+ # The best way is to create a template for each layout.
58
+ # However, in the latest Prawn library, because of problems handling
59
+ # the template that you want supported by future releases.
60
+ # @see https://github.com/sandal/prawn/issues/199
61
+ unless format_stamp_registry.include?(format_id)
62
+ create_format_stamp(format)
63
+ end
64
+ # Apply the static shapes of current format.
65
+ stamp(format_id.to_s)
66
+ end
67
+
68
+ def add_blank_page
69
+ pdf.start_new_page(pdf.page_count.zero? ? {:size => 'A4'} : {})
70
+ end
71
+
72
+ # Delegate to Prawn::Document#render
73
+ # @see Prawn::Document#render
74
+ def render
75
+ result = pdf.render
76
+ finalize
77
+ result
78
+ end
79
+
80
+ # Delegate to Prawn::Document#render_file
81
+ # @see Prawn::Document#render_file
82
+ def render_file(*args)
83
+ finalize
84
+ pdf.render_file(*args)
85
+ end
86
+
87
+ # @param [Numeric, String] x
88
+ # @param [Numeric, String] y
89
+ def translate(x, y, &block)
90
+ x, y = rpos(x, y)
91
+ pdf.translate(x, y, &block)
92
+ end
93
+
94
+ # @param [String] stamp_id
95
+ # @param [Array<Numeric>] at (nil)
96
+ def stamp(stamp_id, at = nil)
97
+ unless at.nil?
98
+ pdf.stamp_at(stamp_id, rpos(*at))
99
+ else
100
+ pdf.stamp(stamp_id)
101
+ end
102
+ end
103
+
104
+ # Delegate to Prawn::Document#create_stamp
105
+ # @param [String] id
106
+ # @see Prawn::Document#create_stamp
107
+ def create_stamp(id, &block)
108
+ pdf.create_stamp(id, &block)
109
+ end
110
+
111
+ # @private
112
+ # @see #pdf
113
+ def internal
114
+ @pdf
115
+ end
116
+
117
+ private
118
+
119
+ # @return [Prawn::Document]
120
+ attr_reader :pdf
121
+
122
+ # @return [Array<Symbol>]
123
+ attr_reader :format_stamp_registry
124
+
125
+ def finalize
126
+ clean_temp_images
127
+ end
128
+
129
+ # @param [ThinReports::Layout::Format] format
130
+ def create_format_stamp(format)
131
+ create_stamp(format.identifier.to_s) do
132
+ parse_svg(format.layout, '/svg/g')
133
+ end
134
+ format_stamp_registry << format.identifier
135
+ end
136
+
137
+ # @param [Array<String, Numeric>] values
138
+ # @return [Numeric, Array<Numeric>, nil]
139
+ def s2f(*values)
140
+ return nil if values.empty?
141
+
142
+ if values.size == 1
143
+ if value = values.first
144
+ value.is_a?(::Numeric) ? value : value.to_f
145
+ end
146
+ else
147
+ values.map {|v| s2f(v) }
148
+ end
149
+ end
150
+
151
+ # @param [Numeric, String] x
152
+ # @param [Numeric, String] y
153
+ # @return [Array<Float>]
154
+ def map_to_upper_left_relative_position(x, y)
155
+ x, y = s2f(x, y)
156
+ [x, -y]
157
+ end
158
+ alias_method :rpos, :map_to_upper_left_relative_position
159
+
160
+ # @param [Numeric, String] x
161
+ # @param [Numeric, String] y
162
+ # @return [Array<Float>]
163
+ def map_to_upper_left_position(x, y)
164
+ x, y = s2f(x, y)
165
+ [x, pdf.bounds.height - y]
166
+ end
167
+ alias_method :pos, :map_to_upper_left_position
168
+ end
169
+
170
+ end
171
+ end
@@ -0,0 +1,74 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+ module Generator
5
+
6
+ # @private
7
+ module Pdf::DrawShape
8
+ # @param [ThinReports::Core::Shape::Tblock::Internal] shape
9
+ def draw_shape_tblock(shape)
10
+ x, y, w, h = shape.box.values_at('x', 'y', 'width', 'height')
11
+
12
+ content = shape.real_value.to_s
13
+ unless shape.multiple?
14
+ content = content.gsub(/\n/, ' ')
15
+ end
16
+ text_box(content, x, y, w, h, common_text_attrs(shape.attributes))
17
+ end
18
+
19
+ # @param [ThinReports::Core::Shape::Basic::Internal] shape
20
+ def draw_shape_image(shape)
21
+ x, y, w, h = shape.svg_attrs.values_at('x', 'y', 'width', 'height')
22
+ base64image(extract_base64_string(shape.svg_attrs['xlink:href']),
23
+ x, y, w, h)
24
+ end
25
+
26
+ # @param [ThinReports::Core::Shape::Text::Internal] shape
27
+ def draw_shape_text(shape)
28
+ x, y, w, h = shape.box.values_at('x', 'y', 'width', 'height')
29
+ text(shape.text.join("\n"), x, y, w, h,
30
+ shape_text_attrs(shape))
31
+ end
32
+
33
+ # @param [ThinReports::Core::Shape::Basic::Internal] shape
34
+ def draw_shape_ellipse(shape)
35
+ args = shape.svg_attrs.values_at('cx', 'cy', 'rx', 'ry')
36
+ args << common_graphic_attrs(shape.attributes)
37
+ ellipse(*args)
38
+ end
39
+
40
+ # @param [ThinReports::Core::Shape::Basic::Internal] shape
41
+ def draw_shape_line(shape)
42
+ args = shape.svg_attrs.values_at('x1', 'y1', 'x2', 'y2')
43
+ args << common_graphic_attrs(shape.attributes)
44
+ line(*args)
45
+ end
46
+
47
+ # @param [ThinReports::Core::Shape::Basic::Internal] shape
48
+ def draw_shape_rect(shape)
49
+ args = shape.svg_attrs.values_at('x', 'y', 'width', 'height')
50
+ args << common_graphic_attrs(shape.attributes) do |attrs|
51
+ attrs[:radius] = shape.svg_attrs['rx']
52
+ end
53
+ rect(*args)
54
+ end
55
+
56
+ private
57
+
58
+ # @param [ThinReports::Core::Shape::Text::Internal]
59
+ # @return [Hash]
60
+ def shape_text_attrs(shape)
61
+ format = shape.format
62
+
63
+ common_text_attrs(shape.attributes) do |attrs|
64
+ # Set the :line_height option.
65
+ attrs[:line_height] = format.line_height unless format.line_height.blank?
66
+ # Set the :valign option.
67
+ attrs[:valign] = text_valign(format.valign)
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,59 @@
1
+ # coding: utf-8
2
+
3
+ module ThinReports
4
+ module Generator
5
+
6
+ # @private
7
+ module Pdf::Font
8
+ FONT_STORE = File.join(ThinReports::ROOTDIR, 'resources', 'fonts')
9
+
10
+ BUILTIN_FONTS = {
11
+ 'IPAMincho' => {:normal => File.join(FONT_STORE, 'ipam.ttf')},
12
+ 'IPAPMincho' => {:normal => File.join(FONT_STORE, 'ipamp.ttf')},
13
+ 'IPAGothic' => {:normal => File.join(FONT_STORE, 'ipag.ttf')},
14
+ 'IPAPGothic' => {:normal => File.join(FONT_STORE, 'ipagp.ttf')}
15
+ }
16
+
17
+ private
18
+
19
+ def setup_fonts
20
+ # Install built-in fonts.
21
+ pdf.font_families.update(BUILTIN_FONTS)
22
+
23
+ # Install fall-back font that IPAMincho.
24
+ fallback_font = BUILTIN_FONTS['IPAMincho'][:normal]
25
+ pdf.font_families['FallbackFont'] = {:normal => fallback_font,
26
+ :bold => fallback_font,
27
+ :italic => fallback_font,
28
+ :bold_italic => fallback_font}
29
+ # Setup fallback font.
30
+ pdf.fallback_fonts(['FallbackFont'])
31
+
32
+ # Create aliases from the font list provided by Prawn.
33
+ pdf.font_families.update(
34
+ 'Courier New' => pdf.font_families['Courier'],
35
+ 'Times New Roman' => pdf.font_families['Times-Roman']
36
+ )
37
+ end
38
+
39
+ # @return [String]
40
+ def default_family
41
+ 'Helvetica'
42
+ end
43
+
44
+ # @param [String] family
45
+ # @return [String]
46
+ def default_family_if_missing(family)
47
+ pdf.font_families.key?(family) ? family : default_family
48
+ end
49
+
50
+ # @param [String] font
51
+ # @param [Symbol] style
52
+ # @return [Boolean]
53
+ def font_has_style?(font, style)
54
+ (f = pdf.font_families[font]) && f.key?(style)
55
+ end
56
+ end
57
+
58
+ end
59
+ end