# -*- encoding: utf-8; frozen_string_literal: true -*-
#
#--
# This file is part of HexaPDF.
#
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
# Copyright (C) 2014-2023 Thomas Leitner
#
# HexaPDF is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License version 3 as
# published by the Free Software Foundation with the addition of the
# following permission added to Section 15 as permitted in Section 7(a):
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
# INFRINGEMENT OF THIRD PARTY RIGHTS.
#
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with HexaPDF. If not, see .
#
# The interactive user interfaces in modified source and object code
# versions of HexaPDF must display Appropriate Legal Notices, as required
# under Section 5 of the GNU Affero General Public License version 3.
#
# In accordance with Section 7(b) of the GNU Affero General Public
# License, a covered work must retain the producer line in every PDF that
# is created or manipulated using HexaPDF.
#
# If the GNU Affero General Public License doesn't fit your need,
# commercial licenses are available at .
#++
require 'hexapdf/type/font'
module HexaPDF
module Type
# Represents a generic CIDFont which can only be used as a descendant font of a composite PDF
# font.
#
# See: PDF2.0 s9.7.4
class CIDFont < Font
# Describes the CIDSystemInfo dictionary specifying the character collection assumed by the
# CIDFont.
#
# See: PDF2.0 s9.7.3
class CIDSystemInfo < Dictionary
define_type :XXCIDSystemInfo
define_field :Registry, type: String, required: true
define_field :Ordering, type: String, required: true
define_field :Supplement, type: Integer, required: true
end
DEFAULT_WIDTH = 1000 # :nodoc:
define_field :BaseFont, type: Symbol, required: true
define_field :CIDSystemInfo, type: :XXCIDSystemInfo, required: true
define_field :FontDescriptor, type: :FontDescriptor, indirect: true, required: true
define_field :DW, type: Integer, default: DEFAULT_WIDTH
define_field :W, type: PDFArray
define_field :DW2, type: PDFArray, default: [880, -1100]
define_field :W2, type: PDFArray
# Returns the unscaled width of the given CID in glyph units, or 0 if the width for the CID is
# missing.
#
# Note that in contrast to other fonts, the argument must *not* be a code point but a CID!
def width(cid)
widths[cid] || value[:DW] || DEFAULT_WIDTH
end
# Sets the /W and /DW keys using the given array of [CID, width] pairs and an optional default
# width.
#
# See: PDF2.0 s9.7.4.3
def set_widths(widths, default_width: DEFAULT_WIDTH)
if widths.empty?
(default_width == DEFAULT_WIDTH ? delete(:DW) : self[:DW] = default_width)
delete(:W)
else
self[:DW] = default_width.to_i unless default_width == DEFAULT_WIDTH
self[:W] = w = []
last_cid = -10
cur_widths = nil
widths.each do |cid, width|
if last_cid + 1 != cid
cur_widths = []
w << cid << cur_widths
end
cur_widths << width.to_i
last_cid = cid
end
end
end
private
# Returns a hash mapping CIDs to their respective width.
#
# Note that the hash is cached internally when accessed the first time.
#
# See: PDF2.0 s9.7.4.3
def widths
cache(:widths) do
result = {}
index = 0
array = self[:W] || []
while index < array.size
entry = array[index]
value = array[index + 1]
if value.kind_of?(Array)
value.each_with_index {|width, i| result[entry + i] = width }
index += 2
else
width = array[index + 2]
entry.upto(value) {|cid| result[cid] = width }
index += 3
end
end
result
end
end
end
end
end