Skip to content

Commit

Permalink
Move even more low level code into PDF::COre
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit 168c44f
Author: Gregory Brown <[email protected]>
Date:   Mon Sep 15 15:25:26 2014 -0400

    Continue to shrink renderer's API surface

commit 0c8befe
Author: Gregory Brown <[email protected]>
Date:   Sat Sep 13 20:53:31 2014 -0400

    Make Prawn::Document::Internals mixin smaller

commit 0071a68
Author: Gregory Brown <[email protected]>
Date:   Sat Sep 13 20:33:18 2014 -0400

    Use explicit names for delegated methods

commit a77e9aa
Author: Gregory Brown <[email protected]>
Date:   Sat Sep 13 20:28:30 2014 -0400

    Remove some monkey patches and push more down to PDF::Core

commit a42d70d
Author: Gregory Brown <[email protected]>
Date:   Sat Sep 13 19:03:00 2014 -0400

    Rough integration of PDF::Core::Renderer
  • Loading branch information
practicingruby committed Sep 16, 2014
1 parent fa80690 commit b48b206
Show file tree
Hide file tree
Showing 20 changed files with 92 additions and 283 deletions.
2 changes: 2 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,5 @@ ClassVars:
Enabled: false
ParameterLists:
Enabled: false
BlockComments:
Enabled: false
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
source "https://rubygems.org"

gem "pdf-core", :git => "https://github.com/prawnpdf/pdf-core.git",
:branch => "renderer"
gemspec

if ENV["CI"]
Expand Down
35 changes: 8 additions & 27 deletions lib/prawn/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
require_relative "document/column_box"
require_relative "document/internals"
require_relative "document/span"
require_relative "document/graphics_state"

module Prawn

Expand Down Expand Up @@ -53,7 +52,6 @@ class Document
include Prawn::Document::Internals
include PDF::Core::Annotations
include PDF::Core::Destinations
include Prawn::Document::GraphicsState
include Prawn::Document::Security
include Prawn::Text
include Prawn::Graphics
Expand Down Expand Up @@ -202,9 +200,9 @@ def initialize(options={},&block)
self.class.extensions.reverse_each { |e| extend e }
@internal_state = PDF::Core::DocumentState.new(options)
@internal_state.populate_pages_from_store(self)
min_version(state.store.min_version) if state.store.min_version
renderer.min_version(state.store.min_version) if state.store.min_version

min_version(1.6) if options[:print_scaling] == :none
renderer.min_version(1.6) if options[:print_scaling] == :none

@background = options[:background]
@background_scale = options[:background_scale] || 1
Expand Down Expand Up @@ -349,23 +347,13 @@ def float
# Renders the PDF document to string.
# Pass an open file descriptor to render to file.
#
def render(output = StringIO.new)
if output.instance_of?(StringIO)
output.set_encoding(::Encoding::ASCII_8BIT)
end
finalize_all_page_contents

render_header(output)
render_body(output)
render_xref(output)
render_trailer(output)
if output.instance_of?(StringIO)
str = output.string
str.force_encoding(::Encoding::ASCII_8BIT)
return str
else
return nil
def render(*a, &b)
(1..page_count).each do |i|
go_to_page i
repeaters.each { |r| r.run(i) }
end

renderer.render(*a, &b)
end

# Renders the PDF document to file.
Expand Down Expand Up @@ -567,13 +555,6 @@ def number_pages(string, options={})
end
end

# Returns true if content streams will be compressed before rendering,
# false otherwise
#
def compression_enabled?
!!state.compress
end

# @group Experimental API

# Attempts to group the given block vertically within the current context.
Expand Down
73 changes: 0 additions & 73 deletions lib/prawn/document/graphics_state.rb

This file was deleted.

159 changes: 28 additions & 131 deletions lib/prawn/document/internals.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#
# This is free software. Please see the LICENSE and COPYING files for details.

require "forwardable"

module Prawn
class Document

Expand All @@ -16,145 +18,40 @@ class Document
#
# @private
module Internals
# Creates a new Prawn::Reference and adds it to the Document's object
# list. The +data+ argument is anything that Prawn::PdfObject() can convert.
#
# Returns the identifier which points to the reference in the ObjectStore
#
def ref(data)
ref!(data).identifier
end
extend Forwardable

# Like ref, but returns the actual reference instead of its identifier.
#
# While you can use this to build up nested references within the object
# tree, it is recommended to persist only identifiers, and them provide
# helper methods to look up the actual references in the ObjectStore
# if needed. If you take this approach, Prawn::Document::Snapshot
# will probably work with your extension
#
def ref!(data)
state.store.ref(data)
end
# These methods are not officially part of Prawn's public API,
# but they are used in documentation and possibly in extensions.
# Perhaps they will become part of the extension API?
# Anyway, for now it's not clear what we should do w. them.
delegate [ :graphic_state,
:save_graphics_state,
:restore_graphics_state ] => :renderer

# At any stage in the object tree an object can be replaced with an
# indirect reference. To get access to the object safely, regardless
# of if it's hidden behind a Prawn::Reference, wrap it in deref().
# FIXME: This is a circular reference, because in theory Prawn should
# be passing instances of renderer to PDF::Core::Page, but it's
# passing Prawn::Document objects instead.
#
def deref(obj)
obj.is_a?(PDF::Core::Reference) ? obj.data : obj
end
# A proper design would probably not require Prawn to directly instantiate
# PDF::Core::Page objects at all!
delegate [:compression_enabled?] => :renderer

# Appends a raw string to the current page content.
#
# # Raw line drawing example:
# x1,y1,x2,y2 = 100,500,300,550
# pdf.add_content("%.3f %.3f m" % [ x1, y1 ]) # move
# pdf.add_content("%.3f %.3f l" % [ x2, y2 ]) # draw path
# pdf.add_content("S") # stroke
#
def add_content(str)
save_graphics_state if graphic_state.nil?
state.page.content << str << "\n"
end
# FIXME: More circular references in PDF::Core::Page.
delegate [ :ref, :ref!, :deref ] => :renderer

# The Name dictionary (PDF spec 3.6.3) for this document. It is
# lazily initialized, so that documents that do not need a name
# dictionary do not incur the additional overhead.
#
def names
state.store.root.data[:Names] ||= ref!(:Type => :Names)
end

# Returns true if the Names dictionary is in use for this document.
#
def names?
state.store.root.data[:Names]
end
# FIXME: Another circular reference, because we mix in a module from
# PDF::Core to provide destinations, which in theory should not
# rely on a Prawn::Document object but is currently wired up that way.
delegate [:names] => :renderer

# Defines a block to be called just before the document is rendered.
#
def before_render(&block)
state.before_render_callbacks << block
end
# FIXME: Circular reference because we mix PDF::Core::Text into
# Prawn::Document. PDF::Core::Text should either be split up or
# moved in its entirety back up into Prawn.
delegate [:add_content] => :renderer

# Defines a block to be called just before a new page is started.
#
def on_page_create(&block)
if block_given?
state.on_page_create_callback = block
else
state.on_page_create_callback = nil
end
def renderer
@renderer ||= PDF::Core::Renderer.new(state)
end

private

def finalize_all_page_contents
(1..page_count).each do |i|
go_to_page i
repeaters.each { |r| r.run(i) }
while graphic_stack.present?
restore_graphics_state
end
state.page.finalize
end
end

# raise the PDF version of the file we're going to generate.
# A private method, designed for internal use when the user adds a feature
# to their document that requires a particular version.
#
def min_version(min)
state.version = min if min > state.version
end

# Write out the PDF Header, as per spec 3.4.1
#
def render_header(output)
state.before_render_actions(self)

# pdf version
output << "%PDF-#{state.version}\n"

# 4 binary chars, as recommended by the spec
output << "%\xFF\xFF\xFF\xFF\n"
end

# Write out the PDF Body, as per spec 3.4.2
#
def render_body(output)
state.render_body(output)
end

# Write out the PDF Cross Reference Table, as per spec 3.4.3
#
def render_xref(output)
@xref_offset = output.size
output << "xref\n"
output << "0 #{state.store.size + 1}\n"
output << "0000000000 65535 f \n"
state.store.each do |ref|
output.printf("%010d", ref.offset)
output << " 00000 n \n"
end
end

# Write out the PDF Trailer, as per spec 3.4.4
#
def render_trailer(output)
trailer_hash = {:Size => state.store.size + 1,
:Root => state.store.root,
:Info => state.store.info}
trailer_hash.merge!(state.trailer) if state.trailer

output << "trailer\n"
output << PDF::Core::PdfObject(trailer_hash) << "\n"
output << "startxref\n"
output << @xref_offset << "\n"
output << "%%EOF" << "\n"
end

end
end
end
2 changes: 1 addition & 1 deletion lib/prawn/font/ttf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ def register(subset)

# Embed the font metrics in the document after everything has been
# drawn, just before the document is emitted.
@document.before_render { |doc| embed(ref, subset) }
@document.renderer.before_render { |doc| embed(ref, subset) }

ref
end
Expand Down
Loading

0 comments on commit b48b206

Please sign in to comment.