Attributes of Dictionaries are typed. The definition of an Attribute specifies the class/type of the object and wheather the object is directly stored or a reference to it.
The following pragmas are used for declaring a type:
The pragmas can occur several times. One of the given types should apply.
Page>>Contents <type: #Contents> <typeArrayOf: #Contents>
The symbol is the type name of the PDF object. So far, the type name corresponds to the class name in the Smalltalk implementation hierarchy.
A type of an object is used when it gets assigned to an attribute. With the type requirement of the attribute, the object is specialized to the attribute type if possible. If this is not possible, a TypeError is raised.
The attribute /Root of /Trailer requires a reference to a /Catalog:
Trailer>>Root <typeIndirect: #Catalog>
When you assign a reference to a plain /Dictionary to it
aTrailer at: #Root put: Dictionary new newReference
the Dictionary is changed to be a /Catalog:
aTrailer Root class name = #Catalog
If something else gets assigned, a TypeError is raised.
aTrailer at: #Root put: Trailer new newReference
As /Dictionary can be subclassed, so can /Array. The attributes are not named, but accessed positionally with their index. The attributes in subclasses of /Array should be typed and documented like dictionary attributes. For this, the same pragmas as in /Dictionary are used. In /Dictionary the pragma's #attribute:documentation:, the attribute number was only used for sorting. In /Array it is the index of the attribute.
/Rectangle (subclass of /Array) Rectangle>>llx <attribute: 1 documentation: 'lower left corner x'> ^self at: 1 Rectangle>>lly <attribute: 2 documentation: 'lower left corner y'> ^self at: 2 Rectangle>>urx <attribute: 3 documentation: 'upper right corner x'> ^self at: 3 Rectangle>>ury <attribute: 4 documentation: 'upper right corner x'> ^self at: 4
Every /Array subclass must implement #numberOfAttributes which is the size of the array. This allows further type checking and the creation of #empty instances with the right number of slots.
From the pragmas above types (instances of Type) are created when sending #typesOf: to a Dictionary with the attribute name as argument. Example:
Trailer new typesOf: #Root
Array with: (IndirectType on: Catalog)
Typing is extended to be able to group several classes in different implementation hierarchies into an abstract PDF Type.
/ColourSpace shall be the super type of all the different /Array and /Name subclasses.
/Function shall be the super type of /FunctionDictionary and /FunctionStream.
/Shading shall be the super type of /ShadingDictionary and /ShadingStream.
PDFObject isType: aType
PDFObject class subsumes: aPDFObject
First, we need to know if an object is already of a specific type. If this is true, we leave it alone, since it is already what we wanted.
A PDF object class implements #subsumes: which is simply the test if the object #isKindOf: the class. The supertypes implement this with a list of top classes to which they delegate.
aPDFObject asType: aType
PDFObject class specializes: aPDFObject
When an object is not a subclass of a type, it can be specialized if the objects class subsumes the type.