NodeStyle.mesa
Written by Bill Paxton, January 1981
Last changed by Bill Paxton, December 1, 1982 8:37 am
DIRECTORY
JaMBasic,
TextNode,
TextLooks,
NameSymbolTable;
NodeStyle: CEDAR DEFINITIONS =
BEGIN
***** Declarations
Ref: TYPE = REF StyleBody;
StyleBody: TYPE = RECORD [
fontFace: FontFace ← Regular, -- 2 bits
fontAlphabets: FontAlphabets ← CapsAndLower, -- 2 bits
strikeout: FontUnderlining ← None, -- 2 bits
underlining: FontUnderlining ← None, -- 2 bits
lineFormatting: LineFormatting ← FlushLeft, -- 2 bits
pathType: PathType ← Filled, -- 2 bits
print: BOOLFALSE, -- true if using the hardcopy style rules
isComment: BOOLFALSE, -- set to node.comment; readonly for style rules
fixedTabs: BOOLFALSE, -- true if stops at fixed locations. else relative to left margin
nestingLevel: [0..MaxNestingLevel] ← 0, -- node level in tree; readonly for style rules
numTabStops: [0..64) ← 0, -- length of the tabStops list
name: ARRAY NameParam OF Name,
real: PACKED ARRAY RealParam OF RealCode,
defaultTabStops: TabStop, -- if NIL, use 0.5 in flushLeft blank defaultTabStops
tabStops: LIST OF TabStop, -- kept sorted by decreasing location, i.e., from right to left on page
this order substantially reduces allocations during the creation of the list since styles tend to define tab stops in increasing order, so can add to start of list and list additions must be non-destructive of the previous list. since length of list is given, can easily find the nth stop.
dataList: DataList -- for special parameters
];
MaxNestingLevel: INTEGER = 31; -- 5 bits
NameParam: TYPE = {
style, -- name of the style, such as "TechicalNote"
fontFamily -- name of the font family, such as "Helvetica"
};
DataList: TYPE = REF DataEntry;
OfEntry: TYPE = { object, real, tab };
DataEntry: TYPE = RECORD [
next: DataList,
data: SELECT kind:OfEntry FROM
object => [
name: Name, -- name of the parameter
object: NameSymbolTable.Object ], -- value of the parameter
real => [ -- for real values which overflow the table of common values
param: RealParam, -- which one it is
value: Real, -- the value
valueI: INTEGER -- the value rounded to an integer -- ],
tab => [ -- for real values from tabspecs which overflow the table of common values
tabStop: TabStop, -- which tab stop it is
which: TabRealParam, -- which value for the tab stop it is
value: Real, -- the value
valueI: INTEGER -- the value rounded to an integer -- ]
ENDCASE];
TabRealParam: TYPE = { loc, spacing, weight, vshift };
TabStop: TYPE = REF TabStopRec;
LeaderTabStop: TYPE = REF leaders TabStopRec;
RuleTabStop: TYPE = REF rule TabStopRec;
RulesTabStop: TYPE = REF rules TabStopRec;
TabStopRec: TYPE = RECORD [
looks: TextLooks.Looks, -- the default looks for the stop
loc: RealCode, -- the location of the stop
alignment: TabAlign ← FlushLeft, -- how the tab is aligned
alignmentChar: CHAR ← 0C, -- only of interest if alignment=Character
breakIfPast: BOOLFALSE, -- what to do if you are already beyond the tab stop
fill: SELECT fillKind:OfTabFill FROM
blank => [],
leaders => [
congruent: BOOLTRUE, -- otherwise, centered
char: CHAR ← 0C, -- the character to be repeated
spacing: RealCode -- the distance between repetitions
],
rule => [
weight: RealCode, -- the thickness of the rule
vshift: RealCode -- the distance up from the baseline to the bottom of the rule
],
rules => [
array: JaMArrayObject -- array[0] holds real for first weight, array[1] holds real for first vshift
],
ENDCASE
];
TabAlign: TYPE = { FlushLeft, FlushRight, Centered, Character };
OfTabFill: TYPE = { blank, leaders, rule, rules };
JaMArrayObject: TYPE = array JaMBasic.Object ← [X, array[0, NIL]];
FontFace: TYPE = { Regular, Bold, Italic, BoldItalic };
FontAlphabets: TYPE = { CapsAndLower, CapsAndSmallCaps, LowerOnly, CapsOnly };
FontUnderlining: TYPE = { None, LettersAndDigits, Visible, All };
LineFormatting: TYPE = { FlushLeft, FlushRight, Justified, Centered };
PathType: TYPE = { Filled, Outlined, FilledAndOutlined };
Name: TYPE = NameSymbolTable.Name ← NameSymbolTable.nullName;
Real: TYPE = REAL ← 0.0;
RealParam: TYPE = {
miscellaneous
fontSize, -- in points
vshift, -- distance to raise text above baseline (can be negative)
tabStops, -- number of spaces equivalent to one tab
minLineGap, -- min distance between line top and previous bottom (can be negative)
freeVar, -- for use by extensions
indent parameters
leftIndent, -- all lines indent this much on left
rightIndent, -- all lines indent this much on right
firstIndent, -- first line indent this much more on left
restIndent, -- other lines indent this much more on left
topIndent, -- top line at least this much down from top of viewer/page
bottomIndent, -- bottom baseline at least this up from bottom of page
leading parameters
leading, -- distance between baselines
leadingStretch,
leadingShrink,
topLeading, -- min distance from first baseline to previous
topLeadingStretch,
topLeadingShrink,
bottomLeading, -- min distance from last baseline to next
bottomLeadingStretch,
bottomLeadingShrink,
parameters for graphics
areaHue, -- color for filled areas
areaSaturation,
areaBrightness,
outlineHue, -- color for outlines
outlineSaturation,
outlineBrightness,
textHue, -- color for text
textSaturation,
textBrightness,
textRotation,
lineWeight, -- width of graphics lines
page layout parameters
pageWidth,
pageLength,
leftMargin,
rightMargin,
topMargin,
bottomMargin,
headerMargin,
footerMargin,
bindingMargin,
lineLength,
column, -- number of columns
penalty parameters for page layout
pageBreakPenalty, -- penalty for breaking inside node
pageBreakAfterFirstLinePenalty, -- penalty for breaking node after its first line
pageBreakBeforeLastLinePenalty, -- penalty for breaking node before its last line
pageBreakBeforeFirstLinePenalty, -- penalty for breaking before first line of node
pageBreakAfterLastLinePenalty -- penalty for breaking after last line of node
};
RealCode: TYPE = [0..255] ← 0;
zero: RealCode = 0;
PointsPerPica: REAL;
PointsPerInch: REAL;
PointsPerCentimeter: REAL;
PointsPerMillimeter: REAL;
PointsPerDidot: REAL;
PointsPerFil: REAL;
PointsPerFill: REAL;
**** Style free variables
These are used for style extensions that need free variables similar to node level or node comment property. Once the name is registered, style rules may use the name to get access to the value for the current node. The registered eval proc's are called to get the current value whenever the style for the node is computed.
RegisterStyleFreeVar: PROC [
name: Name, eval: PROC [node: TextNode.Ref] RETURNS [REAL]];
The first REAL valued free variable is very efficiently implemented. After that, free var's start costing more. Use them to check out new ideas, then get the variable "blessed" and incorporated in the system in a more effiecient manner.
RegisterStyleFreeObjVar: PROC [
name: Name, eval: PROC [node: TextNode.Ref] RETURNS [JaMBasic.Object]];
RemoveNodeFromApplyAllCache: PROC [node: TextNode.Ref];
Whenever something happens to the node that might cause the value of the free variable eval proc to change, call this routine.
RemoveAllFromApplyAllCache: PROC;
Whenever something happens that might change values for free variable eval procs to change, call this routine.
UnregisterStyleFreeVar: PROC [name: Name];
**** Special extension style parameters
These are for use in extensions to the basic style variables. DefineSpecial and DefineSpecialObj make the name available in all styles. Style rules can read and set the new variable just like any other style variable. Formatting programs can get at the value by calling GetSpecial, GetSpecialI, or GetSpecialObj.
DefineSpecial: PROC [name: Name, initialValue: Real];
GetSpecial: PROC [s:Ref, name: Name] RETURNS [Real];
GetSpecialI: PROC [s:Ref, name: Name] RETURNS [INTEGER];
nonNumeric: ERROR; -- raised if call GetSpecial or GetSpecialI for nonnumeric variable
DefineSpecialObj: PROC [name: Name, initialValue: JaMBasic.Object];
GetSpecialObj: PROC [s:Ref, name: Name] RETURNS [JaMBasic.Object];
**** Non-numeric style parameters
GetStyleName: PROC [s:Ref] RETURNS [Name] = INLINE {
RETURN [s.name[style]] };
GetFontFamily: PROC [s:Ref] RETURNS [Name] = INLINE {
RETURN [s.name[fontFamily]] };
GetFontFace: PROC [s:Ref] RETURNS [FontFace] = INLINE {
enumerated type given above
RETURN [s.fontFace] };
GetFontAlphabets: PROC [s:Ref] RETURNS [FontAlphabets] = INLINE {
enumerated type given above
RETURN [s.fontAlphabets] };
GetUnderlining: PROC [s:Ref] RETURNS [FontUnderlining] = INLINE {
enumerated type given above
RETURN [s.underlining] };
GetStrikeout: PROC [s:Ref] RETURNS [FontUnderlining] = INLINE {
enumerated type given above
RETURN [s.strikeout] };
GetLineFormatting: PROC [s:Ref] RETURNS [LineFormatting] = INLINE {
enumerated type given above
RETURN [s.lineFormatting] };
GetPathType: PROC [s:Ref] RETURNS [PathType] = INLINE {
enumerated type given above
RETURN [s.pathType] };
**** Miscellaneous real value parameters
GetFontSize: PROC [s:Ref] RETURNS [Real] = INLINE { -- in points
RETURN [GetReal[s,fontSize]] };
GetFontSizeI: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,fontSize]] };
GetVShift: PROC [s:Ref] RETURNS [Real] = INLINE {
distance to raise text above baseline
RETURN [GetReal[s,vshift]] };
GetVShiftI: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,vshift]] };
GetTabStops: PROC [s:Ref] RETURNS [Real] = INLINE {
number of spaces equivalent to one tab
RETURN [GetReal[s,tabStops]] };
GetTabStopsI: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,tabStops]] };
GetMinLineGap: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,minLineGap]] };
GetMinLineGapI: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,minLineGap]] };
GetTextRotation: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,textRotation]] };
GetLineWeight: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,lineWeight]] };
**** Indents
GetLeftIndent: PROC [s:Ref] RETURNS [Real] = INLINE {
all lines indent at least this much on left
RETURN [GetReal[s,leftIndent]] };
GetLeftIndentI: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,leftIndent]] };
GetRightIndent: PROC [s:Ref] RETURNS [Real] = INLINE {
all lines indent at least this much on right
RETURN [GetReal[s,rightIndent]] };
GetRightIndentI: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,rightIndent]] };
GetFirstIndent: PROC [s:Ref] RETURNS [Real] = INLINE {
first line indent this much more on left
RETURN [GetReal[s,firstIndent]] };
GetFirstIndentI: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,firstIndent]] };
GetBodyIndent, GetRestIndent: PROC [s:Ref] RETURNS [Real] = INLINE {
other lines indent this much more on left
RETURN [GetReal[s,restIndent]] };
GetBodyIndentI, GetRestIndentI: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,restIndent]] };
GetTopIndent: PROC [s:Ref] RETURNS [Real] = INLINE {
top line at least this much down from top
RETURN [GetReal[s,topIndent]] };
GetTopIndentI: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,topIndent]] };
GetBottomIndent: PROC [s:Ref] RETURNS [Real] = INLINE {
bottom baseline at least this up from bottom
RETURN [GetReal[s,bottomIndent]] };
GetBottomIndentI: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,bottomIndent]] };
**** Leadings
GetLeading: PROC [s:Ref] RETURNS [Real] = INLINE {
distance between baselines
RETURN [GetReal[s,leading]] };
GetLeadingI: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,leading]] };
GetLeadingStretch: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,leadingStretch]] };
GetLeadingShrink: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,leadingShrink]] };
GetTopLeading: PROC [s:Ref] RETURNS [Real] = INLINE {
min distance from first baseline to previous
RETURN [GetReal[s,topLeading]] };
GetTopLeadingI: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,topLeading]] };
GetTopLeadingStretch: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,topLeadingStretch]] };
GetTopLeadingShrink: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,topLeadingShrink]] };
GetBottomLeading: PROC [s:Ref] RETURNS [Real] = INLINE {
min distance from last baseline to next
RETURN [GetReal[s,bottomLeading]] };
GetBottomLeadingI: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,bottomLeading]] };
GetBottomLeadingStretch: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,bottomLeadingStretch]] };
GetBottomLeadingShrink: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,bottomLeadingShrink]] };
**** Page layout parameters for typesetter
GetPageWidth: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,pageWidth]] };
GetPageLength: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,pageLength]] };
GetLeftMargin: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,leftMargin]] };
GetRightMargin: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,rightMargin]] };
GetTopMargin: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,topMargin]] };
GetBottomMargin: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,bottomMargin]] };
GetHeaderMargin: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,headerMargin]] };
GetFooterMargin: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,footerMargin]] };
GetBindingMargin: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,bindingMargin]] };
GetLineLength: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,lineLength]] };
GetColumns: PROC [s:Ref] RETURNS [INTEGER] = INLINE {
RETURN [GetInt[s,column]] };
**** Penalties
GetPageBreakPenalty: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,pageBreakPenalty]] };
GetPageBreakAfterFirstLinePenalty: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,pageBreakAfterFirstLinePenalty]] };
GetPageBreakBeforeLastLinePenalty: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,pageBreakBeforeLastLinePenalty]] };
GetPageBreakBeforeFirstLinePenalty: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,pageBreakBeforeFirstLinePenalty]] };
GetPageBreakAfterLastLinePenalty: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,pageBreakAfterLastLinePenalty]] };
**** Colors
GetAreaHue: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,areaHue]] };
GetAreaSaturation: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,areaSaturation]] };
GetAreaBrightness: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,areaBrightness]] };
GetOutlineHue: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,outlineHue]] };
GetOutlineSaturation: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,outlineSaturation]] };
GetOutlineBrightness: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,outlineBrightness]] };
GetTextHue: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,textHue]] };
GetTextSaturation: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,textSaturation]] };
GetTextBrightness: PROC [s:Ref] RETURNS [Real] = INLINE {
RETURN [GetReal[s,textBrightness]] };
**** Tab stop info
GetTabLoc: PROC [stop: TabStop, s:Ref] RETURNS [Real] = INLINE {
code: RealCode;
IF (code ← stop.loc) # overflow THEN RETURN [realArray[code]];
RETURN [GetTabOverflow[s,stop,loc]] };
GetTabLocI: PROC [stop: TabStop, s:Ref] RETURNS [INTEGER] = INLINE {
code: RealCode;
IF (code ← stop.loc) # overflow THEN RETURN [intArray[code]];
RETURN [GetTabIntOverflow[s,stop,loc]] };
GetTabLeaderSpacing: PROC [stop: LeaderTabStop, s:Ref] RETURNS [Real] = INLINE {
code: RealCode;
IF (code ← stop.spacing) # overflow THEN RETURN [realArray[code]];
RETURN [GetTabOverflow[s,stop,spacing]] };
GetTabLeaderSpacingI: PROC [stop: LeaderTabStop, s:Ref] RETURNS [INTEGER] = INLINE {
code: RealCode;
IF (code ← stop.spacing) # overflow THEN RETURN [intArray[code]];
RETURN [GetTabIntOverflow[s,stop,spacing]] };
GetTabRuleWeight: PROC [stop: RuleTabStop, s:Ref] RETURNS [Real] = INLINE {
code: RealCode;
IF (code ← stop.weight) # overflow THEN RETURN [realArray[code]];
RETURN [GetTabOverflow[s,stop,weight]] };
GetTabRuleWeightI: PROC [stop: RuleTabStop, s:Ref] RETURNS [INTEGER] = INLINE {
code: RealCode;
IF (code ← stop.weight) # overflow THEN RETURN [intArray[code]];
RETURN [GetTabIntOverflow[s,stop,weight]] };
GetTabRuleVShift: PROC [stop: RuleTabStop, s:Ref] RETURNS [Real] = INLINE {
code: RealCode;
IF (code ← stop.vshift) # overflow THEN RETURN [realArray[code]];
RETURN [GetTabOverflow[s,stop,vshift]] };
GetTabRuleVShiftI: PROC [stop: RuleTabStop, s:Ref] RETURNS [INTEGER] = INLINE {
code: RealCode;
IF (code ← stop.vshift) # overflow THEN RETURN [intArray[code]];
RETURN [GetTabIntOverflow[s,stop,vshift]] };
RulesTabCount: PROC [stop: RulesTabStop] RETURNS [count: INTEGER]; -- number of rules
RulesTabInfo: PROC [stop: RulesTabStop, num: INTEGER] RETURNS [weight, vshift: REAL];
For num in [0..RulesTabCount), returns the weight and vshift values for that rule.
RulesTabInfoI: PROC [stop: RulesTabStop, num: INTEGER] RETURNS [weight, vshift: INTEGER];
GetTabOverflow: PRIVATE PROC [ref: Ref, stop: TabStop, which: TabRealParam]
RETURNS [value: Real];
GetTabIntOverflow: PRIVATE PROC [ref: Ref, stop: TabStop, which: TabRealParam]
RETURNS [value: INTEGER];
**** Support routines; not for clients to use directly
realArray: REF ARRAY RealCode OF Real; -- array of distances
intArray: REF ARRAY RealCode OF INTEGER;
overflow: RealCode = LAST[RealCode];
GetReal: PROC [ref: Ref, param: RealParam] RETURNS [value: Real] = INLINE {
code: RealCode;
IF (code ← ref.real[param]) # overflow THEN RETURN [realArray[code]];
RETURN [GetRealOverflow[ref,param]] };
GetInt: PROC [ref: Ref, param: RealParam] RETURNS [value: INTEGER] = INLINE {
code: RealCode;
IF (code ← ref.real[param]) # overflow THEN RETURN [intArray[code]];
RETURN [GetIntOverflow[ref,param]] };
GetRealOverflow: PRIVATE PROC [ref: Ref, param: RealParam] RETURNS [value: Real];
GetIntOverflow: PRIVATE PROC [ref: Ref, param: RealParam] RETURNS [value: INTEGER];
**** Apply operations
ApplyAll: PROC [ref: Ref, node: TextNode.Ref, kind: OfStyle ← screen];
ApplyAll[ref,NIL] sets ref to default values
including setting style name to "default"
ApplyAll[ref,node] for node # NIL
1. ApplyAll[ref, Parent[node]]
2. ApplyForNode[ref, node, alt]
where alt is "root" if parent=NIL
or "default" otherwise
ApplyForNode: PROC [ref: Ref, node: TextNode.Ref, alt: Name, kind: OfStyle ← screen];
1. ApplyObject[ref, node prefix object]
2. ApplyType[ref, node type, alt]
3. ApplyObject[ref, node postfix object]
ApplyType: PROC [ref: Ref, name, alt: Name, kind: OfStyle ← screen];
executes the name to modify the body
if name is null or undefined, applies alt instead
ApplyLooks: PROC [ref: Ref, looks: TextLooks.Looks, kind: OfStyle ← screen];
executes the looks to modify the body
ApplyObject: PROC [ref: Ref, object: NameSymbolTable.Object, kind: OfStyle ← screen];
executes the object to modify the body
OfStyle: TYPE = { screen, print, base };
StyleNameForNode: PROC [TextNode.Ref] RETURNS [Name];
does an ApplyAll and then returns the style name
FlushCaches: PROC;
**** Other Operations
Create: PROC RETURNS [Ref]; -- create a body
Copy: PROC [dest, source: Ref]; -- copy a body
Alloc: PROC RETURNS [Ref]; -- get from a small cache
Free: PROC [Ref]; -- don't free more than once or disaster!
LoadStyle: PROC [name: Name] RETURNS [ok: BOOLEAN];
make sure that named style is loaded
fast return if is already loaded
ReloadStyle: PROC [name: Name] RETURNS [ok: BOOLEAN];
forces rereading of definition
**** Initialization
Start: PROC;
END.