object MathML.MathMLVisitor.Visit(MathMLApplyElement e, object args) { return ((Area)formatter.Visit(e, args)).BoundingBox; }
object MathML.MathMLVisitor.Visit(MathMLApplyElement e, object args) { return(args); }
/// <summary> /// Create a XmlElement. This is typically called by the base class when creating a DOM tree /// </summary> /// <param name="prefix"></param> /// <param name="localname"></param> /// <param name="nsURI"></param> /// <returns></returns> public override XmlElement CreateElement(string prefix, string localname, string nsURI) { XmlElement result = null; switch(localname) { case "math": result = new MathMLMathElement(prefix, localname, nsURI, this); break; case "mi": case "mn": case "mtext": result = new MathMLPresentationToken(prefix, localname, nsURI, this); break; case "mo": result = new MathMLOperatorElement(prefix, localname, nsURI, this); break; case "mspace": result = new MathMLSpaceElement(prefix, localname, nsURI, this); break; case "ms": result = new MathMLStringLitElement(prefix, localname, nsURI, this); break; case "mglyph": result = new MathMLGlyphElement(prefix, localname, nsURI, this); break; case "mrow": case "merror": case "mphantom": result = new MathMLPresentationContainer(prefix, localname, nsURI, this); break; case "mfrac": result = new MathMLFractionElement(prefix, localname, nsURI, this); break; case "msqrt": case "mroot": result = new MathMLRadicalElement(prefix, localname, nsURI, this); break; case "mstyle": result = new MathMLStyleElement(prefix, localname, nsURI, this); break; case "mpadded": result = new MathMLPaddedElement(prefix, localname, nsURI, this); break; case "mfenced": result = new MathMLFencedElement(prefix, localname, nsURI, this); break; case "menclose": result = new MathMLEncloseElement(prefix, localname, nsURI, this); break; case "msub": case "msup": case "msubsup": result = new MathMLScriptElement(prefix, localname, nsURI, this); break; case "munder": case "mover": case "munderover": result = new MathMLUnderOverElement(prefix, localname, nsURI, this); break; case "mmultiscripts": result = new MathMLMultiScriptsElement(prefix, localname, nsURI, this); break; case "mtable": result = new MathMLTableElement(prefix, localname, nsURI, this); break; case "mlabeledtr": result = new MathMLLabeledRowElement(prefix, localname, nsURI, this); break; case "mtr": result = new MathMLTableRowElement(prefix, localname, nsURI, this); break; case "mtd": result = new MathMLTableCellElement(prefix, localname, nsURI, this); break; case "maligngroup": result = new MathMLAlignGroupElement(prefix, localname, nsURI, this); break; case "malignmark": result = new MathMLAlignMarkElement(prefix, localname, nsURI, this); break; case "maction": result = new MathMLActionElement(prefix, localname, nsURI, this); break; case "cn": result = new MathMLCnElement(prefix, localname, nsURI, this); break; case "ci": result = new MathMLCiElement(prefix, localname, nsURI, this); break; case "csymbol": result = new MathMLCsymbolElement(prefix, localname, nsURI, this); break; case "apply": result = new MathMLApplyElement(prefix, localname, nsURI, this); break; case "fn": result = new MathMLFnElement(prefix, localname, nsURI, this); break; case "interval": result = new MathMLIntervalElement(prefix, localname, nsURI, this); break; case "inverse": case "compose": case "ident": case "domain": case "codomain": case "image": case "quotient": case "exp": case "factorial": case "divide": case "max": case "min": case "minus": case "plus": case "power": case "rem": case "times": case "root": case "gcd": case "and": case "or": case "xor": case "not": case "implies": case "forall": case "exists": case "abs": case "conjugate": case "arg": case "real": case "imaginary": case "lcm": case "floor": case "ceiling": case "eq": case "neq": case "gt": case "lt": case "geq": case "leq": case "equivalent": case "approx": case "factorof": case "int": case "diff": case "partialdiff": case "divergence": case "grad": case "curl": case "laplacian": case "union": case "intersect": case "in": case "notin": case "subset": case "prsubset": case "notsubset": case "notprsubset": case "setdiff": case "card": case "cartesianproduct": case "sum": case "product": case "limit": case "tendsto": case "ln": case "log": case "sin": case "cos": case "tan": case "sec": case "csc": case "cot": case "sinh": case "cosh": case "tanh": case "sech": case "csch": case "coth": case "arcsin": case "arccos": case "arctan": case "arccosh": case "arccot": case "arccoth": case "arccsc": case "arccsch": case "arcsec": case "arcsech": case "arcsinh": case "arctanh": case "mean": case "sdev": case "variance": case "median": case "mode": case "moment": case "determinant": case "transpose": case "selector": case "vectorproduct": case "scalarproduct": case "outerproduct": case "integers": case "reals": case "rationals": case "naturalnumbers": case "complexes": case "primes": case "exponentiale": case "imaginaryi": case "notanumber": case "true": case "false": case "emptyset": case "pi": case "eulergamma": case "infinity": result = new MathMLPredefinedSymbol(prefix, localname, nsURI, this); break; case "condition": result = new MathMLConditionElement(prefix, localname, nsURI, this); break; case "declare": result = new MathMLDeclareElement(prefix, localname, nsURI, this); break; case "lambda": result = new MathMLLambdaElement(prefix, localname, nsURI, this); break; case "piecewise": result = new MathMLPiecewiseElement(prefix, localname, nsURI, this); break; case "piecev": result = new MathMLCaseElement(prefix, localname, nsURI, this); break; case "reln": case "domainofapplication": case "otherwise": case "lowlimit": case "uplimit": case "degree": case "momentabout": case "logbase": // TODO is this correct, 'logbase' not specified in mathml docs???? result = new MathMLContentContainer(prefix, localname, nsURI, this); break; case "bvar": result = new MathMLBvarElement(prefix, localname, nsURI, this); break; case "set": result = new MathMLSetElement(prefix, localname, nsURI, this); break; case "list": result = new MathMLListElement(prefix, localname, nsURI, this); break; case "vector": result = new MathMLVectorElement(prefix, localname, nsURI, this); break; case "matrix": result = new MathMLMatrixElement(prefix, localname, nsURI, this); break; case "matrixrow": result = new MathMLMatrixRowElement(prefix, localname, nsURI, this); break; case "annotation": result = new MathMLAnnotationElement(prefix, localname, nsURI, this); break; case "semantics": result = new MathMLSemanticsElement(prefix, localname, nsURI, this); break; case "annotation-xml": result = new MathMLXMLAnnotationElement(prefix, localname, nsURI, this); break; case "sep": result = new MathMLSeparator(prefix, localname, nsURI, this); break; case "placeholder": result = new MathMLPlaceholderElement(prefix, localname, nsURI, this); break; default: result = base.CreateElement(prefix, localname, nsURI); break; } return result; }
object MathML.MathMLVisitor.Visit(MathMLApplyElement e, object args) { return(((Area)formatter.Visit(e, args)).BoundingBox); }
/// <summary> /// format an apply element /// </summary> /// <param name="e"></param> /// <param name="args"></param> /// <returns></returns> public object Visit(MathMLApplyElement e, object args) { Area cache = Area.GetArea(e); if(cache != null) return cache; // document to create tmp elements MathMLDocument document = new MathMLDocument(); Area area = null; IFormattingContext ctx = ((IFormattingContext)args).Clone(); if(e.Operator is MathMLPredefinedSymbol) { MathMLPredefinedSymbol predefSymbol = (MathMLPredefinedSymbol)e.Operator; PredefinedSymbolInfo info = PredefinedSymbolInfo.Get(predefSymbol.Name); if(info != null) { switch(info.Type) { case PredefinedSymbolType.Function: { MathMLNodeList arguments = e.Arguments; ArrayList argList = new ArrayList(arguments.Count); foreach(Object o in arguments) { argList.Add(o); } Area[] areas = new Area[3]; areas[0] = AreaFactory.String(ctx, info.Value); areas[1] = GlyphFactory.GetGlyph(ctx, ctx.Size, PredefinedSymbolInfo.ApplyFunction[0]); ctx.Parens = false; areas[2] = FormatFencedContainer(e, ctx, argList, new Char[] {','}, "(", ")"); area = AreaFactory.Horizontal(areas); } break; case PredefinedSymbolType.Fraction: { bool parens = ctx.Parens; ctx.Parens = false; IEnumerator arguments = e.Arguments.GetEnumerator(); arguments.MoveNext(); MathMLElement n = (MathMLElement)arguments.Current; Area numerator = (Area)n.Accept(this, ctx); // idea is we can have lots of arguments, so keep dividing the numerator // by the denominator while(arguments.MoveNext()) { MathMLElement d = (MathMLElement)arguments.Current; Area denominator = (Area)d.Accept(this, ctx); numerator = AreaFactory.Fraction(ctx, numerator, denominator, 5); } area = numerator; if(parens) { area = FenceArea(ctx, area, ctx.Size, '(', ')'); } } break; case PredefinedSymbolType.Infix: { // make a MathMLOperatorElement for the operator symbol MathMLOperatorElement opElement = (MathMLOperatorElement)document.CreateElement("mo"); XmlNode text = opElement.OwnerDocument.CreateTextNode(info.Value); opElement.AppendChild(text); int argCount = e.ArgumentCount; // count of items + operators int itemCount = 2 * argCount - 1; // list of items to format ArrayList items = new ArrayList(itemCount + (info.Parens && ctx.Parens ? 2 : 0)); // only one arg, so make it a prefix op if(argCount == 1) { items.Add(opElement); IEnumerator en = e.Arguments.GetEnumerator(); en.MoveNext(); items.Add(en.Current); } else { foreach(MathMLElement arg in e.Arguments) { items.Add(arg); if(items.Count + 1 < itemCount) { items.Add(opElement); } } } // add open and close parens if we want them if(info.Parens && ctx.Parens) { MathMLOperatorElement open = (MathMLOperatorElement)document.CreateElement("mo"); MathMLOperatorElement close = (MathMLOperatorElement)document.CreateElement("mo"); open.AppendChild(document.CreateTextNode("(")); close.AppendChild(document.CreateTextNode(")")); items.Insert(0, open); items.Add(close); } ctx.Parens = info.ChildParens; area = FormatContainer(e, ctx, items); } break; case PredefinedSymbolType.Postfix: { // make a MathMLOperatorElement for the operator symbol MathMLOperatorElement opElement = (MathMLOperatorElement)document.CreateElement("mo"); XmlNode text = opElement.OwnerDocument.CreateTextNode(info.Value); opElement.AppendChild(text); // list of items to format ArrayList items = new ArrayList(2 + (info.Parens && ctx.Parens ? 2 : 0)); // a postfix element only expect one arg IEnumerator en = e.Arguments.GetEnumerator(); en.MoveNext(); items.Add(en.Current); items.Add(opElement); // add open and close parens if we want them if(ctx.Parens && info.Parens) { MathMLOperatorElement open = (MathMLOperatorElement)document.CreateElement("mo"); MathMLOperatorElement close = (MathMLOperatorElement)document.CreateElement("mo"); open.AppendChild(document.CreateTextNode("(")); close.AppendChild(document.CreateTextNode(")")); items.Insert(0, open); items.Add(close); } ctx.Parens = true; area = FormatContainer(e, ctx, items); } break; case PredefinedSymbolType.Root: { MathMLContentContainer indexElement = null; MathMLElement radicandElement = null; foreach(XmlNode node in e.ChildNodes) { if(node == e.Operator) { continue; } if(indexElement == null && node is MathMLContentContainer && node.Name == "degree") { indexElement = (MathMLContentContainer)node; continue; } if(radicandElement == null && node is MathMLElement) { radicandElement = (MathMLElement)node; } } if(radicandElement != null) { IFormattingContext indexCtx = ctx.Clone(); indexCtx.ScriptLevel++; Area index = (Area)indexElement.Accept(this, indexCtx); area = AreaFactory.Radical(ctx, (Area)radicandElement.Accept(this, ctx), index); } } break; case PredefinedSymbolType.Power: { MathMLNodeList arguments = e.Arguments; int argCount = arguments.Count; Area bseArea = null, scriptArea = null; if(argCount > 0) { IFormattingContext bseCtx = ctx.Clone(); bseCtx.Parens = true; MathMLElement bse = (MathMLElement)arguments.Item(0); bseArea = (Area)bse.Accept(this, bseCtx); } if(argCount > 1) { IFormattingContext scriptCtx = ctx.Clone(); scriptCtx.ScriptLevel++; scriptCtx.Parens = true; MathMLElement script = (MathMLElement)arguments.Item(1); scriptArea = (Area)script.Accept(this, scriptCtx); } if(bseArea != null) { area = AreaFactory.Script(ctx, bseArea, null, new Length(LengthType.Undefined), scriptArea, new Length(LengthType.Undefined)); } else { // TODO error msg } } break; case PredefinedSymbolType.Exp: { MathMLNodeList arguments = e.Arguments; int argCount = arguments.Count; Area bseArea = null, scriptArea = null; MathMLElement baseElm = (MathMLElement)document.CreateElement("mi"); baseElm.AppendChild(document.CreateTextNode(info.Value)); bseArea = (Area)baseElm.Accept(this, ctx); if(argCount > 0) { IFormattingContext scriptCtx = ctx.Clone(); scriptCtx.ScriptLevel++; scriptCtx.Parens = true; MathMLElement script = (MathMLElement)arguments.Item(0); scriptArea = (Area)script.Accept(this, scriptCtx); } area = AreaFactory.Script(ctx, bseArea, null, new Length(LengthType.Undefined), scriptArea, new Length(LengthType.Undefined)); } break; case PredefinedSymbolType.Fenced: { MathMLNodeList arguments = e.Arguments; if(arguments.Count > 0) { MathMLElement argument = (MathMLElement)arguments.Item(0); ArrayList argList = new ArrayList(1); argList.Add(argument); area = FormatFencedContainer(argument, ctx, argList, new char[0], info.Value[0].ToString(), info.Value[1].ToString()); } } break; case PredefinedSymbolType.Log: { MathMLElement arg = null; ArrayList argList = new ArrayList(1); MathMLElement logbase = null; Area bseArea = AreaFactory.String(ctx, info.Value); Area logbaseArea = null; foreach(XmlNode n in e.ChildNodes) { if(n == e.Operator) continue; else if(logbase == null && n is MathMLElement && n.Name == "logbase") { logbase = (MathMLElement)n; IFormattingContext scriptCtx = ctx.Clone(); scriptCtx.ScriptLevel++; logbaseArea = (Area)logbase.Accept(this, scriptCtx); continue; } else if(arg == null && n is MathMLElement) { arg = (MathMLElement)n; argList.Add(arg); } } area = AreaFactory.Script(ctx, bseArea, logbaseArea, new Length(LengthType.Undefined), null, new Length(LengthType.Undefined)); Area[] areas = new Area[3]; areas[0] = area; areas[1] = GlyphFactory.GetGlyph(ctx, ctx.Size, PredefinedSymbolInfo.ApplyFunction[0]); ctx.Parens = false; areas[2] = FormatFencedContainer(e, ctx, argList, new Char[] {','}, "(", ")"); area = AreaFactory.Horizontal(areas); } break; } } } else if(e.Operator is MathMLApplyElement) { MathMLNodeList arguments = e.Arguments; ArrayList argList = new ArrayList(arguments.Count); foreach(Object o in arguments) { argList.Add(o); } Area[] areas = new Area[3]; ctx.Parens = true; areas[0] = (Area)e.Operator.Accept(this, ctx); areas[1] = GlyphFactory.GetGlyph(ctx, ctx.Size, PredefinedSymbolInfo.ApplyFunction[0]); ctx.Parens = false; areas[2] = FormatFencedContainer(e, ctx, argList, new Char[] {','}, "(", ")"); area = AreaFactory.Horizontal(areas); } if(area == null) { area = AreaFactory.String((IFormattingContext)args, "?"); } return CompleteArea(ctx, e, area); }