protected void CompilePositioningAppendixFromMachine(GlyphTypeface typeface, uint featureId, PositioningAppendix positioning, GlyphClassesAppendix glyphClasses, double emSize, StateMachine machine) { Debug.Assert(machine.States[0] == machine.EntryState, "First state is not the entry state."); PositioningAppendix.Feature feature = new PositioningAppendix.Feature(); checked { for (ushort requiredState = 0; requiredState < machine.States.Count; requiredState++) { var state = machine.States[requiredState]; foreach (var transition in state.Transitions) { PositioningAppendix.Rule rule = new PositioningAppendix.Rule(); rule.RequiredState = requiredState; rule.NewState = (ushort)machine.States.IndexOf(transition.TargetState); if (transition is AlwaysTransition) { rule.Condition = PositioningAppendix.RuleCondition.Unconditional; } else if (transition is SimpleTransition) { rule.Condition = PositioningAppendix.RuleCondition.Glyph; rule.ConditionParameter = ((SimpleTransition)transition).GlyphId; } else if (transition is SetTransition) { SetTransition setTransition = (SetTransition)transition; int[] glyphs = setTransition.GlyphIdSet.Select(id => (int)id).ToArray(); GlyphClassesAppendix.Coverage coverage = glyphClasses.FindCoverage(glyphs); if (coverage == null) { coverage = glyphClasses.AppendCoverage(glyphs); } if (!glyphClasses.Coverages.Contains(coverage)) { glyphClasses.Coverages.Add(coverage); } rule.Condition = SubstitutionAppendix.RuleCondition.GlyphClass; rule.ConditionParameter = (ushort)glyphClasses.Coverages.IndexOf(coverage); } else { Debug.Assert(false, "Unknown condition: " + transition.GetType()); continue; } if (transition.Action == null) { rule.Action = PositioningAppendix.RuleAction.Nothing; } else { if (transition.Action is AnchorPointToAnchorPointAction) { AnchorPointToAnchorPointAction anchorAction = transition.Action as AnchorPointToAnchorPointAction; sbyte x = ToPixels(anchorAction.PreviousGlyphAnchorPoint.X - anchorAction.CurrentGlyphAnchorPoint.X, emSize, typeface); sbyte y = ToPixels(anchorAction.PreviousGlyphAnchorPoint.Y - anchorAction.CurrentGlyphAnchorPoint.Y, emSize, typeface); rule.Action = PositioningAppendix.RuleAction.PositionOffset; rule.ActionParameter = Pack(x, y); rule.ActionOffset = 0; } else if (transition.Action is PositioningAdjustmentAction) { PositioningAdjustmentAction positioningAction = transition.Action as PositioningAdjustmentAction; List <GlyphPositionChange> changes = positioningAction.PositionChanges.ToList(); rule.ActionOffset = (sbyte)(1 - changes.Count); rule.TapeMovement = (sbyte)TrimEnd(changes); if (changes.Count == 0) { rule.Action = SubstitutionAppendix.RuleAction.Nothing; rule.ActionOffset = 0; } else { if (changes.Count == 1) { GlyphPositionChange position = changes[0]; if ((position.AdvanceX != 0 || position.AdvanceY != 0) && (position.OffsetX == 0 && position.OffsetY == 0)) { sbyte x = ToPixels(position.AdvanceX, emSize, typeface); sbyte y = ToPixels(position.AdvanceY, emSize, typeface); rule.Action = PositioningAppendix.RuleAction.PositionAdvance; rule.ActionParameter = Pack(x, y); } else if ((position.OffsetX != 0 || position.OffsetY != 0) && (position.AdvanceX == 0 && position.AdvanceY == 0)) { sbyte x = ToPixels(position.OffsetX, emSize, typeface); sbyte y = ToPixels(position.OffsetY, emSize, typeface); rule.Action = PositioningAppendix.RuleAction.PositionOffset; rule.ActionParameter = Pack(x, y); } } if (rule.Action == StateMachineAppendix.RuleAction.Nothing) { PositioningAppendix.PositionChangesParameters parameters = new StateMachineAppendix.PositionChangesParameters(); foreach (GlyphPositionChange position in changes) { PositioningAppendix.PositionChange change = new StateMachineAppendix.PositionChange(ToPixels(position.OffsetX, emSize, typeface), ToPixels(position.OffsetY, emSize, typeface), ToPixels(position.AdvanceX, emSize, typeface), ToPixels(position.AdvanceY, emSize, typeface)); parameters.PositionChanges.Add(change); } rule.Action = PositioningAppendix.RuleAction.PositionComplex; rule.ActionParameter = positioning.AppendParameters(parameters); } } } else { Debug.Assert(false, "Unknown transition action: " + transition.Action.GetType()); continue; } } rule.TapeMovement += (sbyte)(transition.HeadShift); feature.Rules.Add(rule); } } } positioning.Features.Add(feature); positioning.FeatureOffsets.Add(new SubstitutionAppendix.FeatureOffset { Tag = featureId }); }
protected void CompileSubstitutionAppendingFromMachine(uint featureId, SubstitutionAppendix substitution, GlyphClassesAppendix glyphClasses, StateMachine machine) { Debug.Assert(machine.States[0] == machine.EntryState, "First state is not the entry state."); SubstitutionAppendix.Feature feature = new SubstitutionAppendix.Feature(); checked { for (ushort requiredState = 0; requiredState < machine.States.Count; requiredState++) { var state = machine.States[requiredState]; foreach (var transition in state.Transitions) { SubstitutionAppendix.Rule rule = new SubstitutionAppendix.Rule(); rule.RequiredState = requiredState; rule.NewState = (ushort)machine.States.IndexOf(transition.TargetState); if (transition is AlwaysTransition) { rule.Condition = SubstitutionAppendix.RuleCondition.Unconditional; } else if (transition is SimpleTransition) { rule.Condition = SubstitutionAppendix.RuleCondition.Glyph; rule.ConditionParameter = ((SimpleTransition)transition).GlyphId; } else if (transition is SetTransition) { SetTransition setTransition = (SetTransition)transition; int[] glyphs = setTransition.GlyphIdSet.Select(id => (int)id).ToArray(); GlyphClassesAppendix.Coverage coverage = glyphClasses.FindCoverage(glyphs); if (coverage == null) { coverage = glyphClasses.AppendCoverage(glyphs); } if (!glyphClasses.Coverages.Contains(coverage)) { glyphClasses.Coverages.Add(coverage); } rule.Condition = SubstitutionAppendix.RuleCondition.GlyphClass; rule.ConditionParameter = (ushort)glyphClasses.Coverages.IndexOf(coverage); } else { Debug.Assert(false, "Unknown condition: " + transition.GetType()); continue; } if (transition.Action == null) { rule.Action = SubstitutionAppendix.RuleAction.Nothing; } else { SubstitutionAction action = transition.Action as SubstitutionAction; if (action == null) { Debug.Assert(false, "Unknown action: " + transition.Action.GetType()); continue; } int replacementGlyphCount = action.ReplacementGlyphIds.Count(); if (replacementGlyphCount == 1 && action.ReplacedGlyphCount <= 3) { if (action.ReplacedGlyphCount == 0) { rule.Action = SubstitutionAppendix.RuleAction.GlyphInsertion; } else if (action.ReplacedGlyphCount == 1) { rule.Action = SubstitutionAppendix.RuleAction.GlyphOverwrite; } else if (action.ReplacedGlyphCount == 2) { rule.Action = SubstitutionAppendix.RuleAction.GlyphRewrite_2_1; } else if (action.ReplacedGlyphCount == 3) { rule.Action = SubstitutionAppendix.RuleAction.GlyphRewrite_3_1; } else { Debug.Assert(false, "Unknown action: " + action); continue; } rule.ActionParameter = action.ReplacementGlyphIds.First(); } else if (replacementGlyphCount == 0) { rule.Action = SubstitutionAppendix.RuleAction.GlyphDeletion; rule.ActionParameter = (ushort)action.ReplacedGlyphCount; } else { rule.Action = SubstitutionAppendix.RuleAction.GlyphRewrite_N_M; rule.ActionParameter = substitution.AppendParameters(new SubstitutionAppendix.GlyphRewriteParameters((byte)action.ReplacedGlyphCount, action.ReplacementGlyphIds.Select(g => (int)g).ToArray())); } rule.ActionOffset = (sbyte)(1 - action.SkippedGlyphCount - action.ReplacedGlyphCount); rule.TapeMovement = (sbyte)action.SkippedGlyphCount; } rule.TapeMovement += (sbyte)(transition.HeadShift); feature.Rules.Add(rule); } } } substitution.Features.Add(feature); substitution.FeatureOffsets.Add(new SubstitutionAppendix.FeatureOffset { Tag = featureId }); }