<> <> <> <<>> DIRECTORY Font USING [FindFont, FONT, ModifyFont], Imager USING [ConcatT], IPFont USING [], IP, Rope USING [Concat, ROPE]; IPFontImpl: CEDAR PROGRAM IMPORTS Font, Imager, IP, Rope EXPORTS IPFont = BEGIN OPEN IP; <<>> ROPE: TYPE ~ Rope.ROPE; FONT: TYPE ~ Font.FONT; <<$Font Vectors>> <<>> fontClass: VectorClass ~ NEW[VectorClassRep _ [type: $Font, shape: FontShape, get: FontGet]]; FontShape: PROC[v: Vector] RETURNS[VectorShape] ~ { RETURN[[l: 0, n: CARDINAL.LAST]]; }; FontGet: PROC[v: Vector, j: Integer] RETURNS[Any] ~ { font: FONT ~ v.font; IF j IN[0..CARDINAL.LAST] THEN RETURN[OperatorFromChar[font: font, code: j]] ELSE { MasterError[$boundsFault, "Font vector index out of bounds."]; ERROR Error; }; }; VectorFromFont: PUBLIC PROC[font: FONT] RETURNS[Vector] ~ { RETURN[NEW[VectorRep _ [class: fontClass, data: NIL, font: font]]]; }; <<>> <<$Char Operators (the result of Get[font, j])>> <<>> CharData: TYPE ~ REF CharDataRep; CharDataRep: TYPE ~ RECORD[font: FONT, code: CARDINAL]; charClass: OperatorClass ~ NEW[OperatorClassRep _ [type: $Char, apply: CharApply]]; CharApply: PROC[op: Operator, state: State] ~ { data: CharData ~ NARROW[op.data]; font: FONT ~ data.font; font.class.DrawChar[font, data.code, state.imager]; }; OperatorFromChar: PROC[font: FONT, code: CARDINAL] RETURNS[Operator] ~ { data: CharData ~ NEW[CharDataRep _ [font: font, code: code]]; RETURN[NEW[OperatorRep _ [class: charClass, data: data]]]; }; <<>> <<$Modified Vectors (the result of ModifyFont[v, ...] where v is not a $Font Vector)>> <<>> ModifiedData: TYPE ~ REF ModifiedDataRep; ModifiedDataRep: TYPE ~ RECORD[v: Vector, m: Transformation]; modifiedClass: VectorClass ~ NEW[VectorClassRep _ [type: $Modified, shape: ModifiedShape, get: ModifiedGet]]; ModifiedShape: PROC[v: Vector] RETURNS[VectorShape] ~ { data: ModifiedData ~ NARROW[v.data]; RETURN[Shape[data.v]]; }; ModifiedGet: PROC[v: Vector, j: Integer] RETURNS[Any] ~ { data: ModifiedData ~ NARROW[v.data]; val: Any ~ Get[data.v, j]; WITH val SELECT FROM op: Operator => RETURN[OperatorFromModifiedChar[e: op, m: data.m]]; ENDCASE => { MasterError[$wrongType, "Element of font vector is not an Operator."]; ERROR Error; }; }; <<$ModifiedChar Operators (the result of Get[v, j], where v is a $Modified Vector)>> <<>> ModifiedCharData: TYPE ~ REF ModifiedCharDataRep; ModifiedCharDataRep: TYPE ~ RECORD[e: Operator, m: Transformation]; modifiedCharClass: OperatorClass ~ NEW[OperatorClassRep _ [type: $ModifiedChar, apply: ModifiedCharApply]]; ModifiedCharApply: PROC[op: Operator, state: State] ~ { data: ModifiedCharData ~ NARROW[op.data]; state.imager.ConcatT[data.m]; Do[state, data.e]; }; OperatorFromModifiedChar: PROC[e: Operator, m: Transformation] RETURNS[Operator] ~ { data: ModifiedCharData ~ NEW[ModifiedCharDataRep _ [e: e, m: m]]; RETURN[NEW[OperatorRep _ [class: modifiedCharClass, data: data]]]; }; <> <<>> RopeFromName: PROC[name: Name] RETURNS[rope: ROPE _ NIL] ~ { FOR list: Name _ name, list.rest UNTIL list=NIL DO IF rope#NIL THEN rope _ rope.Concat["/"]; rope _ rope.Concat[list.first.rope]; ENDLOOP; }; FindFont: PUBLIC PROC[self: State, v: Vector] RETURNS[Vector] ~ { name: Name ~ NameFromVector[v]; rope: ROPE ~ RopeFromName[name]; font: FONT ~ Font.FindFont[rope]; RETURN[VectorFromFont[font]]; }; FindFontVec: PUBLIC PROC[self: State, v: Vector] RETURNS[Vector] ~ { MasterError[$unimplemented, "FINDFONTVEC is not implemented."]; ERROR Error; }; ModifyFont: PUBLIC PROC[v: Vector, m: Transformation] RETURNS[Vector] ~ { IF v.font#NIL THEN RETURN[VectorFromFont[Font.ModifyFont[v.font, m]]] ELSE { data: ModifiedData ~ NEW[ModifiedDataRep _ [v: v, m: m]]; RETURN[NEW[VectorRep _ [class: modifiedClass, data: data]]]; }; }; END.