/*
*
* (c) COPYRIGHT MIT and INRIA, 1996-2002
* Please first read the full copyright statement in file COPYRIGHT.
*
*/
/*
* MathMLbuilder
*
* Author: V. Quint
*/
#define THOT_EXPORT extern
#include "amaya.h"
#include "css.h"
#include "html2thot_f.h"
#include "HTMLactions_f.h"
#include "MathML.h"
#include "parser.h"
#include "styleparser_f.h"
#include "style.h"
#include "undo.h"
#include "Xml2thot_f.h"
/* Define a pointer to let parser functions access the Math entity table */
extern XmlEntity *pMathEntityTable;
#define MaxMsgLength 200
#include "HTMLtable_f.h"
#include "Mathedit_f.h"
#include "styleparser_f.h"
#include "fetchXMLname_f.h"
/*----------------------------------------------------------------------
MapMathMLAttribute
Search in the Attribute Mapping Table the entry for the
attribute of name Attr and returns the corresponding Thot attribute type.
----------------------------------------------------------------------*/
void MapMathMLAttribute (char *attrName, AttributeType *attrType,
char *elementName, ThotBool *level, Document doc)
{
attrType->AttrSSchema = GetMathMLSSchema (doc);
MapXMLAttribute (MATH_TYPE, attrName, elementName, level, doc, &(attrType->AttrTypeNum));
}
/*----------------------------------------------------------------------
MapMathMLAttributeValue
Search in the Attribute Value Mapping Table the entry for the attribute
ThotAtt and its value AttrVal. Returns the corresponding Thot value.
----------------------------------------------------------------------*/
void MapMathMLAttributeValue (char *attVal, AttributeType attrType, int *value)
{
MapXMLAttributeValue (MATH_TYPE, attVal, attrType, value);
}
/*----------------------------------------------------------------------
MathMLEntityCreated
----------------------------------------------------------------------*/
void MathMLEntityCreated (unsigned char *entityValue, Language lang,
char *entityName, Document doc)
{
}
/*----------------------------------------------------------------------
ElementNeedsPlaceholder
returns TRUE if element el needs a sibling placeholder.
----------------------------------------------------------------------*/
ThotBool ElementNeedsPlaceholder (Element el)
{
ElementType elType;
Element child, parent, sibling;
ThotBool ret;
ret = FALSE;
elType = TtaGetElementType (el);
if (elType.ElTypeNum == MathML_EL_MS ||
elType.ElTypeNum == MathML_EL_MFRAC ||
elType.ElTypeNum == MathML_EL_BevelledMFRAC ||
elType.ElTypeNum == MathML_EL_MSQRT ||
elType.ElTypeNum == MathML_EL_MROOT ||
elType.ElTypeNum == MathML_EL_MSTYLE ||
elType.ElTypeNum == MathML_EL_MERROR ||
elType.ElTypeNum == MathML_EL_MPADDED ||
elType.ElTypeNum == MathML_EL_MPHANTOM ||
elType.ElTypeNum == MathML_EL_MFENCED ||
elType.ElTypeNum == MathML_EL_MF ||
elType.ElTypeNum == MathML_EL_MSUB ||
elType.ElTypeNum == MathML_EL_MSUP ||
elType.ElTypeNum == MathML_EL_MSUBSUP ||
elType.ElTypeNum == MathML_EL_MUNDER ||
elType.ElTypeNum == MathML_EL_MOVER ||
elType.ElTypeNum == MathML_EL_MUNDEROVER ||
elType.ElTypeNum == MathML_EL_MMULTISCRIPTS ||
elType.ElTypeNum == MathML_EL_MTABLE ||
elType.ElTypeNum == MathML_EL_MACTION)
ret = TRUE;
else if (elType.ElTypeNum == MathML_EL_MROW)
/* a mrow needs a place holder only if it's not the sole child of
an element such as Numerator, Denominator, RootBase, Index, etc. */
{
ret = TRUE;
sibling = el; TtaNextSibling (&sibling);
if (!sibling)
{
sibling = el; TtaPreviousSibling (&sibling);
if (!sibling)
{
parent = TtaGetParent (el);
if (parent)
{
elType = TtaGetElementType (parent);
if (elType.ElTypeNum == MathML_EL_Numerator ||
elType.ElTypeNum == MathML_EL_Denominator ||
elType.ElTypeNum == MathML_EL_RootBase ||
elType.ElTypeNum == MathML_EL_Index ||
elType.ElTypeNum == MathML_EL_FencedExpression ||
elType.ElTypeNum == MathML_EL_Base ||
elType.ElTypeNum == MathML_EL_Subscript ||
elType.ElTypeNum == MathML_EL_Superscript ||
elType.ElTypeNum == MathML_EL_UnderOverBase ||
elType.ElTypeNum == MathML_EL_Underscript ||
elType.ElTypeNum == MathML_EL_Overscript ||
elType.ElTypeNum == MathML_EL_MultiscriptBase ||
elType.ElTypeNum == MathML_EL_MSubscript ||
elType.ElTypeNum == MathML_EL_MSuperscript)
ret = FALSE;
}
}
}
}
else if (elType.ElTypeNum == MathML_EL_MO ||
elType.ElTypeNum == MathML_EL_OpeningFence ||
elType.ElTypeNum == MathML_EL_ClosingFence ||
elType.ElTypeNum == MathML_EL_FencedSeparator)
/* an operator that contains a single Symbol needs a placeholder,
except when it is in a Base or UnderOverBase */
{
child = TtaGetFirstChild (el);
if (child != NULL)
{
elType = TtaGetElementType (child);
if (elType.ElTypeNum == MathML_EL_SYMBOL_UNIT)
{
ret = TRUE;
parent = TtaGetParent (el);
if (parent != NULL)
{
elType = TtaGetElementType (parent);
if (elType.ElTypeNum == MathML_EL_Base ||
elType.ElTypeNum == MathML_EL_UnderOverBase)
ret = FALSE;
}
}
}
}
else if (elType.ElTypeNum == MathML_EL_MSPACE)
{
/* in principle mspace needs a placeholder sibling */
ret = TRUE;
/* but if it's the only child of a mstyle element, the placeholders
would change the height and width of the mstyle. Consider for
instance:
<mstyle background="#000099">
<mspace depth="2mm" width=".2in"/>
</mstyle> */
sibling = el; TtaNextSibling (&sibling);
if (!sibling)
{
sibling = el; TtaPreviousSibling (&sibling);
if (!sibling)
{
parent = TtaGetParent (el);
if (parent)
{
elType = TtaGetElementType (parent);
if (elType.ElTypeNum == MathML_EL_MSTYLE)
ret = FALSE;
}
}
}
}
return ret;
}
/*----------------------------------------------------------------------
CreatePlaceholders
----------------------------------------------------------------------*/
static void CreatePlaceholders (Element el, Document doc)
{
Element sibling, prev, constr, child;
Attribute attr;
ElementType elType;
AttributeType attrType;
ThotBool create, stretchableSubsup;
if (!el)
return;
elType.ElSSchema = GetMathMLSSchema (doc);
prev = NULL;
create = TRUE;
sibling = el;
while (sibling != NULL)
{
if (!ElementNeedsPlaceholder (sibling))
create = FALSE;
else
{
if (sibling == el)
/* first element */
{
elType = TtaGetElementType (sibling);
if (elType.ElTypeNum == MathML_EL_MF)
/* the first element is a MF. Don't create a placeholder
before */
create = FALSE;
else if (elType.ElTypeNum == MathML_EL_MROW)
/* the first element is a MROW */
{
child = TtaGetFirstChild (sibling);
if (child != NULL)
{
elType = TtaGetElementType (child);
if (elType.ElTypeNum != MathML_EL_MF)
/* the first child of the MROW element is not a MF */
/* Don't create a placeholder before */
create = FALSE;
}
}
}
if (create)
{
elType.ElTypeNum = MathML_EL_Construct;
constr = TtaNewElement (doc, elType);
TtaInsertSibling (constr, sibling, TRUE, doc);
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = MathML_ATTR_IntPlaceholder;
attr = TtaNewAttribute (attrType);
TtaAttachAttribute (constr, attr, doc);
TtaSetAttributeValue (attr, MathML_ATTR_IntPlaceholder_VAL_yes_,
constr, doc);
}
create = TRUE;
}
prev = sibling;
TtaNextSibling (&sibling);
}
if (prev != NULL && create)
{
stretchableSubsup = FALSE;
elType = TtaGetElementType (prev);
/* don't insert a placeholder after the last element if it's a MF */
if (elType.ElTypeNum == MathML_EL_MF)
create = FALSE;
else if (elType.ElTypeNum == MathML_EL_MROW)
/* the last element is a MROW */
{
child = TtaGetLastChild (prev);
if (child != NULL)
{
elType = TtaGetElementType (child);
if (elType.ElTypeNum != MathML_EL_MF)
/* the last child of the MROW element is not a MF */
/* Don't create a placeholder before */
create = FALSE;
}
}
else if (elType.ElTypeNum == MathML_EL_MSUBSUP ||
elType.ElTypeNum == MathML_EL_MSUB ||
elType.ElTypeNum == MathML_EL_MSUP ||
elType.ElTypeNum == MathML_EL_MUNDEROVER ||
elType.ElTypeNum == MathML_EL_MUNDER ||
elType.ElTypeNum == MathML_EL_MUNDEROVER)
{
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = MathML_ATTR_IntVertStretch;
if (TtaGetAttribute (prev, attrType))
stretchableSubsup = TRUE;
}
if (create)
{
if (stretchableSubsup)
elType.ElTypeNum = MathML_EL_Construct1;
else
elType.ElTypeNum = MathML_EL_Construct;
constr = TtaNewElement (doc, elType);
TtaInsertSibling (constr, prev, FALSE, doc);
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = MathML_ATTR_IntPlaceholder;
attr = TtaNewAttribute (attrType);
TtaAttachAttribute (constr, attr, doc);
TtaSetAttributeValue (attr, MathML_ATTR_IntPlaceholder_VAL_yes_,
constr, doc);
}
}
}
/*----------------------------------------------------------------------
NextNotComment
Return the next sibling of element el that is not an XMLcomment element.
Return el itself if it's not a comment.
----------------------------------------------------------------------*/
static void NextNotComment (Element* el, Element* prev)
{
ElementType elType;
if (*el == NULL)
return;
elType = TtaGetElementType (*el);
while (*el != NULL && elType.ElTypeNum == MathML_EL_XMLcomment)
{
*prev = *el;
TtaNextSibling (el);
if (*el != NULL)
elType = TtaGetElementType (*el);
}
}
/*----------------------------------------------------------------------
CheckMathSubExpressions
Children of element el should be of type type1, type2, and type3.
If they are not, wrap them in elements of these types.
If element el has too many or not enough children, return FALSE.
----------------------------------------------------------------------*/
static ThotBool CheckMathSubExpressions (Element el, int type1, int type2, int type3, Document doc)
{
Element child, new, prev;
ElementType elType, childType;
char msgBuffer[200];
ThotBool result;
result = TRUE;
elType.ElSSchema = GetMathMLSSchema (doc);
child = TtaGetFirstChild (el);
prev = NULL;
NextNotComment (&child, &prev);
if (type1 == 0)
{
if (child)
/* no child expected and there is one, error */
{
sprintf (msgBuffer, "No subexpression allowed in %s",
TtaGetElementTypeName (TtaGetElementType (el)));
XmlParseError (errorParsing, msgBuffer, 0);
result = FALSE;
}
}
else
if (!child)
/* a first child is expected and it's missing */
{
sprintf (msgBuffer, "Missing subexpression in %s",
TtaGetElementTypeName (TtaGetElementType (el)));
XmlParseError (errorParsing, msgBuffer, 0);
result = FALSE;
}
else
{
elType.ElTypeNum = type1;
childType = TtaGetElementType (child);
if (TtaSameTypes (childType, elType) == 0)
{
TtaRemoveTree (child, doc);
new = TtaNewElement (doc, elType);
if (prev == NULL)
TtaInsertFirstChild (&new, el, doc);
else
TtaInsertSibling (new, prev, FALSE, doc);
TtaInsertFirstChild (&child, new, doc);
CreatePlaceholders (child, doc);
child = new;
}
prev = child;
TtaNextSibling (&child);
NextNotComment (&child, &prev);
if (type2 == 0)
{
if (child)
/* this second child is not expected, error */
{
sprintf (msgBuffer, "Only 1 subexpression allowed in %s",
TtaGetElementTypeName (TtaGetElementType (el)));
XmlParseError (errorParsing, msgBuffer, 0);
result = FALSE;
}
}
else
{
if (!child)
/* a second child is expected and it's missing */
{
sprintf (msgBuffer, "2 subexpressions required in %s",
TtaGetElementTypeName (TtaGetElementType (el)));
XmlParseError (errorParsing, msgBuffer, 0);
result = FALSE;
}
else
{
elType.ElTypeNum = type2;
childType = TtaGetElementType (child);
if (TtaSameTypes (childType, elType) == 0)
{
TtaRemoveTree (child, doc);
new = TtaNewElement (doc, elType);
TtaInsertSibling (new, prev, FALSE, doc);
TtaInsertFirstChild (&child, new, doc);
CreatePlaceholders (child, doc);
child = new;
}
prev = child;
TtaNextSibling (&child);
NextNotComment (&child, &prev);
if (type3 == 0)
{
if (child)
/* this third child is not expected, error */
{
sprintf (msgBuffer, "Only 2 subexpressions allowed in %s",
TtaGetElementTypeName (TtaGetElementType (el)));
XmlParseError (errorParsing, msgBuffer, 0);
result = FALSE;
}
}
else
{
if (!child)
/* a third child is expected and it's missing */
{
sprintf (msgBuffer, "3 subexpressions required in %s",
TtaGetElementTypeName (TtaGetElementType (el)));
XmlParseError (errorParsing, msgBuffer, 0);
result = FALSE;
}
else
{
elType.ElTypeNum = type3;
childType = TtaGetElementType (child);
if (TtaSameTypes (childType, elType) == 0)
{
TtaRemoveTree (child, doc);
new = TtaNewElement (doc, elType);
TtaInsertSibling (new, prev, FALSE, doc);
TtaInsertFirstChild (&child, new, doc);
CreatePlaceholders (child, doc);
child = new;
}
}
prev = child;
TtaNextSibling (&child);
NextNotComment (&child, &prev);
if (child)
/* this fourth child is unexpected */
{
sprintf (msgBuffer,"Only 3 subexpressions allowed in %s",
TtaGetElementTypeName (TtaGetElementType (el)));
XmlParseError (errorParsing, msgBuffer, 0);
result = FALSE;
}
}
}
}
}
return result;
}
/*----------------------------------------------------------------------
SetSingleIntHorizStretchAttr
Put a IntHorizStretch attribute on element el if it contains only
a MO element that is a stretchable symbol.
-----------------------------------------------------------------------*/
void SetSingleIntHorizStretchAttr (Element el, Document doc, Element* selEl)
{
Element child, sibling, textEl, symbolEl;
ElementType elType, childType, siblingType;
Attribute attr;
AttributeType attrType;
Language lang;
CHAR_T text[2];
char script;
unsigned char c;
int len;
ThotBool doit;
if (el == NULL)
return;
child = TtaGetFirstChild (el);
textEl = NULL;
if (child)
{
elType = TtaGetElementType (child);
/* skip empty Constructs (placeholders) and comments */
while (child &&
(elType.ElTypeNum == MathML_EL_Construct ||
elType.ElTypeNum == MathML_EL_XMLcomment) &&
!strcmp (TtaGetSSchemaName (elType.ElSSchema), "MathML"))
{
TtaNextSibling (&child);
if (child)
elType = TtaGetElementType (child);
}
while (child && elType.ElTypeNum == MathML_EL_MROW &&
strcmp (TtaGetSSchemaName (elType.ElSSchema), "MathML") == 0)
/* the first significant child is a mrow. Check whether it has a
single child */
{
child = TtaGetFirstChild (child);
if (child)
{
elType = TtaGetElementType (child);
/* skip empty Constructs (placeholders) and comments */
while (child &&
(elType.ElTypeNum == MathML_EL_Construct ||
elType.ElTypeNum == MathML_EL_XMLcomment) &&
!strcmp (TtaGetSSchemaName (elType.ElSSchema), "MathML"))
{
TtaNextSibling (&child);
if (child)
elType = TtaGetElementType (child);
}
sibling = child;
TtaNextSibling (&sibling);
if (sibling)
/* there are other children */
{
siblingType = TtaGetElementType (sibling);
while (sibling &&
(siblingType.ElTypeNum == MathML_EL_Construct ||
siblingType.ElTypeNum == MathML_EL_XMLcomment) &&
!strcmp (TtaGetSSchemaName (siblingType.ElSSchema), "MathML"))
/* its an empty construct (placeholder) or a comment, skip it*/
{
TtaNextSibling (&sibling);
if (sibling)
siblingType = TtaGetElementType (sibling);
}
if (sibling)
/* there are significant siblings */
child = NULL;
}
}
}
if (child && (elType.ElTypeNum == MathML_EL_MO ||
elType.ElTypeNum == MathML_EL_MOVER ||
elType.ElTypeNum == MathML_EL_MUNDER))
/* the first child is a MO, a MUNDER or a MOVER */
{
sibling = child;
TtaNextSibling (&sibling);
if (sibling)
siblingType = TtaGetElementType (sibling);
/* skip empty Constructs (placeholders) and comments */
while (sibling &&
(siblingType.ElTypeNum == MathML_EL_Construct ||
siblingType.ElTypeNum == MathML_EL_XMLcomment) &&
!strcmp (TtaGetSSchemaName (siblingType.ElSSchema), "MathML"))
{
TtaNextSibling (&sibling);
if (sibling)
siblingType = TtaGetElementType (sibling);
}
if (sibling == NULL)
/* there is no other significant child */
{
c = EOS;
doit = FALSE;
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = MathML_ATTR_IntHorizStretch;
if (elType.ElTypeNum == MathML_EL_MOVER ||
elType.ElTypeNum == MathML_EL_MUNDER)
/* check if the UnderOverBase has a IntHorizStretch attribute */
{
childType.ElTypeNum = MathML_EL_UnderOverBase;
textEl = TtaSearchTypedElement (childType, SearchInTree, child);
if (textEl)
{
if (TtaGetAttribute (textEl, attrType))
doit = TRUE;
}
}
else if (elType.ElTypeNum == MathML_EL_MO)
{
textEl = TtaGetFirstChild (child);
childType = TtaGetElementType (textEl);
if (childType.ElTypeNum == MathML_EL_TEXT_UNIT)
/* the MO child contains a TEXT element */
{
len = TtaGetElementVolume (textEl);
if (len == 1)
/* the TEXT element contains a single character */
{
/* get that character */
len = 2;
TtaGiveBufferContent (textEl, text, len, &lang);
script = TtaGetScript (lang);
if (
#ifndef _I18N_
(script == 'L') &&
#endif
(text[0] == '-' || text[0] == '_' ||
text[0] == 175))
/* a horizontal line in the middle of the box */
c = 'h';
else
#ifdef _I18N_
if (text[0] == 0x2190)
c = 'L'; /* arrow left */
else if (text[0] == 0x2192)
c = 'R'; /* arrow right */
else if (text[0] == 45) /* - (minus) */
/* a horizontal line in the middle of the box */
c = 'h';
else if (text[0] == 0x2212) /* - (minus) */
/* a horizontal line in the middle of the box */
c = 'h';
else if (text[0] == 0x0332) /* UnderBar */
/* a horizontal line */
c = 'h';
else if (text[0] == 65079)
c = 'o'; /* Over brace */
else if (text[0] == 65080)
c = 'u'; /* Under brace */
#else
if (script == 'G')
/* a single Symbol character */
{
if (text[0] == 172)
c = 'L'; /* arrow left */
else if (text[0] == 174)
c = 'R'; /* arrow right */
else if (text[0] == 45) /* - (minus) */
/* a horizontal line in the middle of the box */
c = 'h';
else if (text[0] == 132)
c = 'o'; /* Over brace */
else if (text[0] == 133)
c = 'u'; /* Under brace */
}
#endif
if (c != EOS)
doit = TRUE;
}
}
}
if (doit)
{
/* attach a IntHorizStretch attribute to the element
(UnderOverBase, Underscript, or Overscript) */
attr = TtaNewAttribute (attrType);
TtaAttachAttribute (el, attr, doc);
TtaSetAttributeValue (attr, MathML_ATTR_IntHorizStretch_VAL_yes_, el, doc);
attr = TtaNewAttribute (attrType);
TtaAttachAttribute (child, attr, doc);
TtaSetAttributeValue (attr, MathML_ATTR_IntHorizStretch_VAL_yes_, child, doc);
}
if (c != EOS)
{
/* replace the TEXT element by a Thot SYMBOL element */
childType.ElTypeNum = MathML_EL_SYMBOL_UNIT;
symbolEl = TtaNewElement (doc, childType);
TtaInsertSibling (symbolEl, textEl, FALSE, doc);
if (selEl != NULL)
if (*selEl == textEl)
*selEl = symbolEl;
TtaDeleteTree (textEl, doc);
if (c != EOS)
TtaSetGraphicsShape (symbolEl, c, doc);
}
}
}
}
}
/*----------------------------------------------------------------------
SetIntHorizStretchAttr
Put a IntHorizStretch attribute on all children of element el that
contain only a MO element that is a stretchable symbol.
-----------------------------------------------------------------------*/
static void SetIntHorizStretchAttr (Element el, Document doc)
{
Element child;
if (el == NULL)
return;
child = TtaGetFirstChild (el);
while (child != NULL)
{
SetSingleIntHorizStretchAttr (child, doc, NULL);
TtaNextSibling (&child);
}
}
/*----------------------------------------------------------------------
SetIntVertStretchAttr
Put a IntVertStretch attribute on element el if its base element
(Base for a MSUBSUP, MSUP or MSUB; UnderOverBase for a MUNDEROVER,
a MUNDER of a MOVER) contains only a MO element that is a vertically
stretchable symbol (integral, vertical arrow, etc).
-----------------------------------------------------------------------*/
void SetIntVertStretchAttr (Element el, Document doc, int base, Element* selEl)
{
Element child, sibling, textEl, symbolEl, parent, operator, next;
ElementType elType;
Attribute attr;
AttributeType attrType;
SSchema MathMLSSchema;
Language lang;
char script;
#define buflen 50
CHAR_T text[buflen];
unsigned char c;
int len, i;
ThotBool inbase, stretchable;
if (el == NULL)
return;
operator = NULL;
inbase = FALSE;
MathMLSSchema = TtaGetElementType(el).ElSSchema;
symbolEl = parent = NULL;
if (base == 0)
/* it's a MO */
{
parent = TtaGetParent (el);
if (parent != NULL)
{
/* don't process the mo if it is within a base. It will be processed
when the enclosing construct is processed (see below) */
elType = TtaGetElementType (parent);
if (elType.ElSSchema != MathMLSSchema ||
(elType.ElTypeNum != MathML_EL_Base &&
elType.ElTypeNum != MathML_EL_UnderOverBase &&
elType.ElTypeNum != MathML_EL_MSUBSUP &&
elType.ElTypeNum != MathML_EL_MSUB &&
elType.ElTypeNum != MathML_EL_MSUP &&
elType.ElTypeNum != MathML_EL_MUNDEROVER &&
elType.ElTypeNum != MathML_EL_MUNDER &&
elType.ElTypeNum != MathML_EL_MUNDEROVER &&
elType.ElTypeNum != MathML_EL_MTD))
operator = el;
}
}
else
/* it's not a MO */
{
/* search the Base or UnderOverBase child */
child = TtaGetFirstChild (el);
if (child != NULL)
{
elType = TtaGetElementType (child);
/* skip empty Constructs (placeholders) and comments */
while (child &&
(elType.ElTypeNum == MathML_EL_Construct ||
elType.ElTypeNum == MathML_EL_XMLcomment) &&
elType.ElSSchema == MathMLSSchema)
{
TtaNextSibling (&child);
if (child)
elType = TtaGetElementType (child);
}
if (elType.ElTypeNum == base && elType.ElSSchema == MathMLSSchema)
/* the first child is a Base or UnderOverBase */
{
child = TtaGetFirstChild (child);
if (child != NULL)
{
elType = TtaGetElementType (child);
/* skip empty Constructs (placeholders) and comments */
while (child &&
(elType.ElTypeNum == MathML_EL_Construct ||
elType.ElTypeNum == MathML_EL_XMLcomment) &&
elType.ElSSchema == MathMLSSchema)
{
TtaNextSibling (&child);
if (child)
elType = TtaGetElementType (child);
}
if (elType.ElTypeNum == MathML_EL_MO &&
elType.ElSSchema == MathMLSSchema)
/* its first significant child is a MO */
{
sibling = child;
TtaNextSibling (&sibling);
/* skip empty Constructs (placeholders) and comments */
while (sibling &&
(elType.ElTypeNum == MathML_EL_Construct ||
elType.ElTypeNum == MathML_EL_XMLcomment) &&
elType.ElSSchema == MathMLSSchema)
{
TtaNextSibling (&sibling);
if (sibling)
elType = TtaGetElementType (sibling);
}
if (sibling == NULL)
/* there is no other significant child */
{
operator = child;
if (base == MathML_EL_Base ||
base == MathML_EL_UnderOverBase)
{
parent = el;
inbase = TRUE;
}
}
}
}
}
}
}
if (operator)
{
textEl = TtaGetFirstChild (operator);
if (textEl != NULL)
{
elType = TtaGetElementType (textEl);
if (elType.ElTypeNum == MathML_EL_TEXT_UNIT)
{
len = TtaGetElementVolume (textEl);
if (len >= 1)
{
if (len >= buflen)
len = buflen-1;
TtaGiveBufferContent (textEl, text, len+1, &lang);
script = TtaGetScript (lang);
#ifdef _I18N_
stretchable = TRUE;
for (i = 0; i < len; i++)
if ((text[i] < 0x222B || text[i] > 0x2233) &&
text[i] != 0x2191 && text[i] != 0x2193 &&
text[i] != 0x2195 &&
text[i] != 0x21D1 && text[i] != 0x21D3 &&
text[i] != 0x21D5)
/* accept only symbols like simple integral, double or
triple integral, contour integral, etc. or vertical
arrows (add more arrows *****) */
stretchable = FALSE;
#else
stretchable = FALSE;
if (script == 'G')
/* Adobe Symbol character set */
{
stretchable = TRUE;
/* check all characters in this TEXT element */
for (i = 0; i < len; i++)
if (text[i] != 242 && /* integral */
text[i] != 173 && text[i] != 175 && /* arrows */
text[i] != 221 && text[i] != 223) /* double arrows */
/**** accept also other symbols like double or triple
integral, contour integral, etc. ****/
stretchable = FALSE;
}
#endif
if (stretchable)
/* the operator contains only stretchable symbols */
{
/* attach a IntVertStretch attribute */
attrType.AttrSSchema = MathMLSSchema;
attrType.AttrTypeNum = MathML_ATTR_IntVertStretch;
attr = TtaNewAttribute (attrType);
TtaAttachAttribute (el, attr, doc);
TtaSetAttributeValue (attr,
MathML_ATTR_IntVertStretch_VAL_yes_,
el, doc);
TtaRegisterAttributeCreate (attr, el, doc);
/* replace the stretchable characters by a Thot SYMBOL
element. If there are several such characters in
the mo (multiple integral for instance), replace
them too. */
do
{
/* replace the TEXT element by a Thot SYMBOL */
elType.ElSSchema = MathMLSSchema;
elType.ElTypeNum = MathML_EL_SYMBOL_UNIT;
for (i = 0; i < len; i++)
{
if (selEl != NULL)
if (*selEl == textEl)
*selEl = symbolEl;
#ifdef _I18N_
if (text[i] == 0x222B)
c = 'i';
else if (text[i] == 0x222C)
c = 'd';
else if (text[i] == 0x222D)
c = 't';
else if (text[i] == 0x222E)
c = 'c';
else if (text[i] == 0x2191)
c = '^';
else if (text[i] == 0x2193)
c = 'V';
#else
if (text[i] == 242)
c = 'i';
else if (text[i] == 173)
c = '<';
else if (text[i] == 175)
c = '>';
#endif
symbolEl = TtaNewElement (doc, elType);
TtaInsertSibling (symbolEl, textEl, TRUE,doc);
TtaSetGraphicsShape (symbolEl, c, doc);
TtaRegisterElementCreate (symbolEl, doc);
}
TtaRegisterElementDelete (textEl, doc);
TtaDeleteTree (textEl, doc);
/* is there an other text element after the
stretchable symbol? */
textEl = symbolEl; TtaNextSibling (&textEl);
if (textEl)
{
elType = TtaGetElementType (textEl);
if (elType.ElTypeNum != MathML_EL_TEXT_UNIT)
textEl = NULL;
else
/* there is another text element.
Is it a single stretchable symbol? */
{
len = TtaGetElementVolume (textEl);
if (len < 1)
/* not a single character */
textEl = NULL;
else
{
if (len >= buflen)
len = buflen-1;
TtaGiveBufferContent (textEl, text,
len+1, &lang);
script = TtaGetScript (lang);
#ifdef _I18N_
if (text[0] != 0x222B &&
text[0] != 0x222C &&
text[0] != 0x222D &&
text[0] != 0x222E &&
text[0] != 0x2191 &&
text[0] != 0x2193)
#else
if (script != 'G' ||
(text[0] != 242 && text[0] != 173 &&
text[0] != 175))
#endif
/* not a stretchable symbol */
textEl = NULL;
}
}
}
}
while (textEl);
if (inbase)
/* it's within a Base or UnderOverBase element */
{
sibling = parent;
TtaNextSibling (&sibling);
if (sibling)
/* the msubsup of munderover element has a next
sibling */
{
elType = TtaGetElementType (sibling);
if (elType.ElTypeNum == MathML_EL_Construct &&
elType.ElSSchema == MathMLSSchema)
/* the next sibling is a Construct */
{
next = sibling;
TtaNextSibling (&next);
if (!next)
/* there is no other sibling after the
Construct. Change it into Construct1*/
{
TtaRegisterElementDelete (sibling, doc);
TtaRemoveTree (sibling, doc);
ChangeElementType (sibling,
MathML_EL_Construct1);
TtaInsertSibling (sibling, parent,
FALSE, doc);
TtaRegisterElementCreate (sibling, doc);
/* force the msubsup element to be
reformatted and to take into account
its new next sibling */
TtaRemoveTree (parent, doc);
TtaInsertSibling (parent, sibling, TRUE,
doc);
}
}
}
}
}
}
}
}
}
}
/*----------------------------------------------------------------------
SetIntPlaceholderAttr
Put a IntPlaceholder attribute on all Construct elements in the
subtree of root el.
-----------------------------------------------------------------------*/
static void SetIntPlaceholderAttr (Element el, Document doc)
{
Element child;
ElementType elType;
Attribute attr;
AttributeType attrType;
if (el == NULL)
return;
elType = TtaGetElementType (el);
if (elType.ElTypeNum == MathML_EL_Construct &&
elType.ElSSchema == GetMathMLSSchema (doc))
{
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = MathML_ATTR_IntPlaceholder;
attr = TtaNewAttribute (attrType);
TtaAttachAttribute (el, attr, doc);
TtaSetAttributeValue (attr, MathML_ATTR_IntPlaceholder_VAL_yes_, el, doc);
}
else
{
child = TtaGetFirstChild (el);
while (child != NULL)
{
SetIntPlaceholderAttr (child, doc);
TtaNextSibling (&child);
}
}
}
/*----------------------------------------------------------------------
BuildMultiscript
The content of a MMULTISCRIPT element has been created following
the original MathML structure. Create all Thot elements defined
in the MathML S schema.
-----------------------------------------------------------------------*/
static void BuildMultiscript (Element elMMULTISCRIPT, Document doc)
{
Element elem, base, next, group, pair, script, prevPair, prevScript;
ElementType elType, elTypeGroup, elTypePair, elTypeScript;
SSchema MathMLSSchema;
base = NULL;
group = NULL;
prevPair = NULL;
prevScript = NULL;
MathMLSSchema = GetMathMLSSchema (doc);
elTypeGroup.ElSSchema = MathMLSSchema;
elTypePair.ElSSchema = MathMLSSchema;
elTypeScript.ElSSchema = MathMLSSchema;
/* process all children of the MMULTISCRIPT element */
elem = TtaGetFirstChild (elMMULTISCRIPT);
while (elem != NULL)
{
/* remember the element to be processed after the current one */
next = elem;
TtaNextSibling (&next);
/* remove the current element from the tree */
TtaRemoveTree (elem, doc);
if (base == NULL)
/* the current element is the first child of the MMULTISCRIPT
element */
{
/* Create a MultiscriptBase element as the first child of
MMULTISCRIPT and move the current element as the first child
of the MultiscriptBase element */
elTypeGroup.ElTypeNum = MathML_EL_MultiscriptBase;
base = TtaNewElement (doc, elTypeGroup);
TtaInsertFirstChild (&base, elMMULTISCRIPT, doc);
TtaInsertFirstChild (&elem, base, doc);
}
else
/* the current element is a subscript or a superscript */
{
if (group == NULL)
/* there is no PostscriptPairs element. Create one */
{
elTypeGroup.ElTypeNum = MathML_EL_PostscriptPairs;
group = TtaNewElement (doc, elTypeGroup);
TtaInsertSibling (group, base, FALSE, doc);
elTypePair.ElTypeNum = MathML_EL_PostscriptPair;
/* create a first and a last PostscriptPair as placeholders */
pair = TtaNewTree (doc, elTypePair, "");
TtaInsertFirstChild (&pair, group, doc);
SetIntPlaceholderAttr (pair, doc);
prevPair = pair;
pair = TtaNewTree (doc, elTypePair, "");
TtaInsertSibling (pair, prevPair, FALSE, doc);
SetIntPlaceholderAttr (pair, doc);
prevScript = NULL;
}
if (prevScript == NULL)
/* the current element is the first subscript or superscript
in a pair */
{
/* create a PostscriptPair or PrescriptPair element */
pair = TtaNewElement (doc, elTypePair);
if (prevPair == NULL)
TtaInsertFirstChild (&pair, group, doc);
else
TtaInsertSibling (pair, prevPair, FALSE, doc);
prevPair = pair;
/* create a MSubscript element */
elTypeScript.ElTypeNum = MathML_EL_MSubscript;
script = TtaNewElement (doc, elTypeScript);
TtaInsertFirstChild (&script, pair, doc);
prevScript = script;
}
else
/* the current element is a superscript in a pair */
{
/* create a MSuperscript element */
elTypeScript.ElTypeNum = MathML_EL_MSuperscript;
script = TtaNewElement (doc, elTypeScript);
/* insert it as a sibling of the previous MSubscript element */
TtaInsertSibling (script, prevScript, FALSE, doc);
prevScript = NULL;
}
/* insert the current element as a child of the new MSuperscript or
MSubscript element */
TtaInsertFirstChild (&elem, script, doc);
SetIntPlaceholderAttr (elem, doc);
}
CreatePlaceholders (elem, doc);
/* get next child of the MMULTISCRIPT element */
elem = next;
if (elem != NULL)
{
elType = TtaGetElementType (elem);
if (elType.ElSSchema == MathMLSSchema &&
elType.ElTypeNum == MathML_EL_PrescriptPairs)
/* the next element is a PrescriptPairs */
{
/* if there there is no PostscriptPairs element, create one as a
placeholder */
if (elTypeGroup.ElTypeNum != MathML_EL_PostscriptPairs)
{
elTypeGroup.ElTypeNum = MathML_EL_PostscriptPairs;
group = TtaNewTree (doc, elTypeGroup, "");
TtaInsertSibling (group, elem, TRUE, doc);
SetIntPlaceholderAttr (group, doc);
}
/* the following elements will be interpreted as sub- superscripts
in PrescriptPair elements, wich will be children of this
PrescriptPairs element */
elTypeGroup.ElTypeNum = MathML_EL_PrescriptPairs;
elTypePair.ElTypeNum = MathML_EL_PrescriptPair;
group = elem;
/* create a first and a last PostscriptPair as placeholders */
pair = TtaNewTree (doc, elTypePair, "");
TtaInsertFirstChild (&pair, group, doc);
SetIntPlaceholderAttr (pair, doc);
prevPair = pair;
pair = TtaNewTree (doc, elTypePair, "");
TtaInsertSibling (pair, prevPair, FALSE, doc);
SetIntPlaceholderAttr (pair, doc);
prevScript = NULL;
TtaNextSibling (&elem);
}
}
}
/* all children of element MMULTISCRIPTS have been processed */
/* if the last group processed is not a PrescriptPairs element,
create one as a placeholder */
if (elTypeGroup.ElTypeNum != MathML_EL_PrescriptPairs && base != NULL)
{
elTypeGroup.ElTypeNum = MathML_EL_PrescriptPairs;
elem = TtaNewTree (doc, elTypeGroup, "");
if (group == NULL)
group = base;
TtaInsertSibling (elem, group, TRUE, doc);
SetIntPlaceholderAttr (elem, doc);
}
}
/*----------------------------------------------------------------------
CreateWrapper
Create an element of type wrapperType as a child of element el and
move all chidren of element el within the new element.
-----------------------------------------------------------------------*/
static void CreateWrapper (Element el, int wrapperType, Document doc)
{
Element wrapper, child, prevChild, nextChild;
ElementType elType;
child = TtaGetFirstChild (el);
elType.ElSSchema = GetMathMLSSchema (doc);
elType.ElTypeNum = wrapperType;
wrapper = TtaNewElement (doc, elType);
TtaInsertFirstChild (&wrapper, el, doc);
prevChild = NULL;
while (child)
{
nextChild = child;
TtaNextSibling (&nextChild);
TtaRemoveTree (child, doc);
if (prevChild == NULL)
TtaInsertFirstChild (&child, wrapper, doc);
else
TtaInsertSibling (child, prevChild, FALSE, doc);
prevChild = child;
child = nextChild;
}
}
/*----------------------------------------------------------------------
CheckMTable
The content of a MTABLE element has been created following
the original MathML structure. Create all Thot elements defined
in the MathML S schema.
If placeholder, associate an attribute IntPlaceholder with all
cells generated in the MathML table.
-----------------------------------------------------------------------*/
void CheckMTable (Element elMTABLE, Document doc, ThotBool placeholder)
{
ElementType elType;
Element MTableHead, MTableBody, row, nextRow, el, prevRow, cell,
nextCell, newMTD, firstColHead, label;
SSchema MathMLSSchema;
MathMLSSchema = GetMathMLSSchema (doc);
row = TtaGetFirstChild (elMTABLE);
/* create a MTable_head as the first child of element MTABLE */
elType.ElSSchema = MathMLSSchema;
elType.ElTypeNum = MathML_EL_MTable_head;
MTableHead = TtaNewElement (doc, elType);
TtaInsertFirstChild (&MTableHead, elMTABLE, doc);
elType.ElTypeNum = MathML_EL_MColumn_head;
firstColHead = TtaNewTree (doc, elType, "");
TtaInsertFirstChild (&firstColHead, MTableHead, doc);
/* create a MTable_body */
elType.ElTypeNum = MathML_EL_MTable_body;
MTableBody = TtaNewElement (doc, elType);
TtaInsertSibling (MTableBody, MTableHead, FALSE, doc);
/* move all children of element MTABLE into the new MTable_body element
and wrap each non-MTR element in a MTR, except comments */
prevRow = NULL;
while (row)
{
nextRow = row;
TtaNextSibling (&nextRow);
elType = TtaGetElementType (row);
TtaRemoveTree (row, doc);
if (TtaSameSSchemas (elType.ElSSchema, MathMLSSchema) &&
(elType.ElTypeNum == MathML_EL_XMLcomment ||
elType.ElTypeNum == MathML_EL_MTR ||
elType.ElTypeNum == MathML_EL_MLABELEDTR))
{
if (prevRow == NULL)
TtaInsertFirstChild (&row, MTableBody, doc);
else
TtaInsertSibling (row, prevRow, FALSE, doc);
prevRow = row;
if (elType.ElTypeNum == MathML_EL_MTR ||
elType.ElTypeNum == MathML_EL_MLABELEDTR)
{
cell = TtaGetFirstChild (row);
if (elType.ElTypeNum == MathML_EL_MLABELEDTR)
/* skip the first significant child of the mlabeledtr element */
{
/* skip comments first */
do
{
elType = TtaGetElementType (cell);
if (TtaSameSSchemas (elType.ElSSchema, MathMLSSchema) &&
elType.ElTypeNum == MathML_EL_XMLcomment)
TtaNextSibling (&cell);
}
while (cell && elType.ElTypeNum == MathML_EL_XMLcomment);
/* skip the first element after the comments: it's a label */
if (cell)
{
/* if it's a MTD change its type into LabelCell */
if (elType.ElTypeNum == MathML_EL_MTD &&
elType.ElSSchema == MathMLSSchema)
ChangeElementType (cell, MathML_EL_LabelCell);
/* wrap this element in a RowLabel element */
/* This will allow the P schema to specify the horizontal
position of the label */
elType.ElSSchema = MathMLSSchema;
elType.ElTypeNum = MathML_EL_RowLabel;
label = TtaNewElement (doc, elType);
TtaInsertSibling (label, cell, TRUE, doc);
TtaRemoveTree (cell, doc);
TtaInsertFirstChild (&cell, label, doc);
cell = label;
TtaNextSibling (&cell);
}
}
}
else
cell = NULL;
}
else
/* this child is not a MTR, MLABELEDTR, or a comment.
In MathML 2.0, this in an error, but we try to recover by
creating a MTR element */
{
elType.ElSSchema = MathMLSSchema;
elType.ElTypeNum = MathML_EL_MTR;
el = TtaNewElement (doc, elType);
if (prevRow == NULL)
TtaInsertFirstChild (&el, MTableBody, doc);
else
TtaInsertSibling (el, prevRow, FALSE, doc);
TtaInsertFirstChild (&row, el, doc);
cell = row;
prevRow = el;
}
while (cell)
/* check all children of the current MTR element */
{
nextCell = cell;
TtaNextSibling (&nextCell);
elType = TtaGetElementType (cell);
if (!TtaSameSSchemas (elType.ElSSchema, MathMLSSchema) ||
(elType.ElTypeNum != MathML_EL_XMLcomment &&
elType.ElTypeNum != MathML_EL_MTD))
/* this is not a MTD nor a comment, create a wrapping MTD */
{
elType.ElSSchema = MathMLSSchema;
elType.ElTypeNum = MathML_EL_MTD;
newMTD = TtaNewElement (doc, elType);
TtaInsertSibling (newMTD, cell, TRUE, doc);
TtaRemoveTree (cell, doc);
TtaInsertFirstChild (&cell, newMTD, doc);
cell = newMTD;
}
if (elType.ElTypeNum == MathML_EL_MTD)
/* This is a MTD element. Wrap its contents with a CellWrapper */
{
CreateWrapper (cell, MathML_EL_CellWrapper, doc);
SetIntHorizStretchAttr (cell, doc);
SetIntVertStretchAttr (cell, doc, MathML_EL_CellWrapper, NULL);
}
cell = nextCell;
}
row = nextRow;
}
CheckAllRows (elMTABLE, doc, placeholder, FALSE);
}
/*----------------------------------------------------------------------
SetFontstyleAttr
The content of a MI element has been created or modified.
Create or change attribute IntFontstyle for that element accordingly.
-----------------------------------------------------------------------*/
void SetFontstyleAttr (Element el, Document doc)
{
ElementType elType;
AttributeType attrType, attrType1;
Attribute attr, IntAttr;
Element ancestor, textEl;
int len;
Language lang;
#ifndef _I18N_
char script;
#endif
char *value, text[2];
ThotBool italic;
if (el != NULL)
{
/* search the (deprecated) fontstyle attribute or the mathvariant
attribute on the element and its ancestors */
elType = TtaGetElementType (el);
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = MathML_ATTR_fontstyle;
attrType1.AttrSSchema = elType.ElSSchema;
attrType1.AttrTypeNum = MathML_ATTR_mathvariant;
ancestor = el;
attr = NULL;
do
{
attr = TtaGetAttribute (ancestor, attrType);
if (!attr)
attr = TtaGetAttribute (ancestor, attrType1);
if (!attr)
{
ancestor = TtaGetParent (ancestor);
if (ancestor)
{
elType = TtaGetElementType (ancestor);
if (elType.ElSSchema != attrType.AttrSSchema)
/* this ancestor is not in the MathML namespace */
ancestor = NULL;
}
}
}
while (ancestor && !attr);
attrType.AttrTypeNum = MathML_ATTR_IntFontstyle;
IntAttr = TtaGetAttribute (el, attrType);
if (attr != NULL)
/* there is a fontstyle or mathvariant attribute. Remove the
IntFontstyle internal attribute that is not needed */
{
if (IntAttr != NULL)
TtaRemoveAttribute (el, IntAttr, doc);
}
else
/* there is no fontstyle or mathvariant attribute. Create an internal
IntFontstyle attribute with a value that depends on the content of
the MI element */
{
/* get content length */
len = TtaGetElementVolume (el);
if (len > 1)
/* put an attribute IntFontstyle = IntNormal */
{
if (IntAttr == NULL)
{
IntAttr = TtaNewAttribute (attrType);
TtaAttachAttribute (el, IntAttr, doc);
}
TtaSetAttributeValue (IntAttr,
MathML_ATTR_IntFontstyle_VAL_IntNormal,
el, doc);
}
else
/* MI contains a single character. Remove attribute IntFontstyle
if it exists, except if it's ImaginaryI, ExponentialE or
DifferentialD */
{
italic = TRUE;
textEl = TtaGetFirstChild (el);
if (textEl != NULL)
{
elType = TtaGetElementType (textEl);
if (elType.ElTypeNum == MathML_EL_MGLYPH)
/* the content of the MI element is a MGLYPH element */
/* check the length if it's alt attribute */
{
/* by default, use normal style */
italic = FALSE;
attrType.AttrTypeNum = MathML_ATTR_alt;
attr = TtaGetAttribute (textEl, attrType);
if (attr)
/* the MGLYPH element has an alt attribute */
{
len = TtaGetTextAttributeLength (attr);
if (len == 1)
italic = TRUE;
}
}
else if (elType.ElTypeNum == MathML_EL_TEXT_UNIT)
{
/* is there a single digit? */
len = TtaGetTextLength (textEl);
if (len == 1)
{
len++;
TtaGiveTextContent (textEl, text, &len, &lang);
#ifndef _I18N_
script = TtaGetScript (lang);
#endif
if (
#ifndef _I18N_
script == 'L' &&
#endif
text[0] >= '0' && text[0] <= '9')
italic = FALSE;
}
/* is there an attribute EntityName on that character? */
attrType.AttrTypeNum = MathML_ATTR_EntityName;
attr = TtaGetAttribute (textEl, attrType);
if (attr)
{
len = TtaGetTextAttributeLength (attr);
if (len > 0)
{
value = TtaGetMemory (len+1);
TtaGiveTextAttributeValue (attr, value, &len);
if (strcmp (&value[1], "ImaginaryI;") == 0 ||
strcmp (&value[1], "ExponentialE;") == 0 ||
strcmp (&value[1], "DifferentialD;") == 0)
italic = FALSE;
TtaFreeMemory (value);
}
}
}
if (italic)
{
if (IntAttr != NULL)
TtaRemoveAttribute (el, IntAttr, doc);
}
else
{
/* put an attribute IntFontstyle = IntNormal */
if (IntAttr == NULL)
{
attrType.AttrTypeNum = MathML_ATTR_IntFontstyle;
IntAttr = TtaNewAttribute (attrType);
TtaAttachAttribute (el, IntAttr, doc);
}
TtaSetAttributeValue (IntAttr,
MathML_ATTR_IntFontstyle_VAL_IntNormal,
el, doc);
}
}
}
}
}
}
/*----------------------------------------------------------------------
SetIntAddSpaceAttr
The content of a MO element has been created or modified.
Create or change attribute IntAddSpace for that element accordingly.
-----------------------------------------------------------------------*/
void SetIntAddSpaceAttr (Element el, Document doc)
{
Element textEl, previous;
ElementType elType;
AttributeType attrType;
Attribute attr, formAttr;
SSchema MathMLSSchema;
int len, val, form;
CHAR_T text[2];
Language lang;
char script;
ThotBool comment;
MathMLSSchema = TtaGetElementType(el).ElSSchema;
/* get the content of the mo element */
textEl = TtaGetFirstChild (el);
/* skip comments if any */
if (textEl)
do
{
elType = TtaGetElementType (textEl);
if (TtaSameSSchemas (elType.ElSSchema, MathMLSSchema) &&
elType.ElTypeNum == MathML_EL_XMLcomment)
/* it's a comment, skip it */
TtaNextSibling (&textEl);
}
while (textEl && elType.ElTypeNum == MathML_EL_XMLcomment);
if (textEl && elType.ElTypeNum == MathML_EL_TEXT_UNIT)
/* the mo element is not empty */
{
/* does the mo element have an IntAddSpace attribute? */
attrType.AttrSSchema = MathMLSSchema;
attrType.AttrTypeNum = MathML_ATTR_IntAddSpace;
attr = TtaGetAttribute (el, attrType);
if (attr == NULL)
/* no IntAddSpace Attr, create one */
{
attr = TtaNewAttribute (attrType);
TtaAttachAttribute (el, attr, doc);
}
/* space on both sides by default */
val = MathML_ATTR_IntAddSpace_VAL_both;
/* does the mo element have a form attribute? */
attrType.AttrTypeNum = MathML_ATTR_form;
formAttr = TtaGetAttribute (el, attrType);
if (formAttr)
/* there is a form attribute */
{
form = TtaGetAttributeValue (formAttr);
switch (form)
{
case MathML_ATTR_form_VAL_prefix:
val = MathML_ATTR_IntAddSpace_VAL_nospace;
break;
case MathML_ATTR_form_VAL_infix:
val = MathML_ATTR_IntAddSpace_VAL_both;
break;
case MathML_ATTR_form_VAL_postfix:
val = MathML_ATTR_IntAddSpace_VAL_spaceafter;
break;
default:
val = MathML_ATTR_IntAddSpace_VAL_both;
break;
}
}
else
/* no form attribute. Analyze the content */
{
len = TtaGetElementVolume (textEl);
if (len == 1)
{
TtaGiveBufferContent (textEl, text, len+1, &lang);
script = TtaGetScript (lang);
/* the mo element contains a single character */
#ifndef _I18N_
if (script == 'L')
/* ISO-Latin 1 character */
{
#endif
if (text[0] == '-'
#ifdef _I18N_
|| text[0] == 0x2212 /* minus */
#endif
)
/* prefix or infix operator? */
{
/* skip preceding comments if any */
previous = el;
do
{
comment = FALSE;
TtaPreviousSibling (&previous);
if (previous)
{
elType = TtaGetElementType (previous);
comment = (TtaSameSSchemas (elType.ElSSchema, MathMLSSchema) &&
elType.ElTypeNum == MathML_EL_XMLcomment);
}
}
while (previous && comment);
if (previous == NULL)
/* no previous sibling => prefix operator */
val = MathML_ATTR_IntAddSpace_VAL_nospace;
else
{
elType = TtaGetElementType (previous);
if (elType.ElTypeNum == MathML_EL_MO ||
elType.ElTypeNum == MathML_EL_OpeningFence ||
elType.ElTypeNum == MathML_EL_ClosingFence ||
elType.ElTypeNum == MathML_EL_FencedSeparator)
/* after an operator => prefix operator */
val = MathML_ATTR_IntAddSpace_VAL_nospace;
else
/* infix operator */
val = MathML_ATTR_IntAddSpace_VAL_both;
}
}
else if (text[0] == '&' ||
text[0] == '*' ||
text[0] == '+' ||
text[0] == '/' ||
text[0] == '<' ||
text[0] == '=' ||
text[0] == '>' ||
text[0] == '^' ||
(int)text[0] == 177 || /* plus or minus */
(int)text[0] == 215 || /* times */
(int)text[0] == 247) /* divide */
/* infix operator */
val = MathML_ATTR_IntAddSpace_VAL_both;
else if (text[0] == ',' ||
text[0] == '!' ||
text[0] == '&' ||
text[0] == ':' ||
text[0] == ';')
/* separator */
val = MathML_ATTR_IntAddSpace_VAL_spaceafter;
else if (text[0] == '(' ||
text[0] == ')' ||
text[0] == '[' ||
text[0] == ']' ||
text[0] == '{' ||
text[0] == '}' ||
text[0] == '.' ||
text[0] == '@' ||
#ifndef _I18N_
text[0] == 'd' || /* probably DifferentialD */
#endif
(int)text[0] == 129 || /* thin space */
(int)text[0] == 130 || /* en space */
(int)text[0] == 160) /* em space */
val = MathML_ATTR_IntAddSpace_VAL_nospace;
#ifndef _I18N_
}
else if (script == 'G')
{
/* Symbol character set */
if ((int)text[0] == 163 || /* less or equal */
(int)text[0] == 177 || /* plus or minus */
(int)text[0] == 179 || /* greater or equal */
(int)text[0] == 180 || /* times */
(int)text[0] == 184 || /* divide */
(int)text[0] == 185 || /* not equal */
(int)text[0] == 186 || /* identical */
(int)text[0] == 187 || /* equivalent */
(int)text[0] == 196 || /* circle times */
(int)text[0] == 197 || /* circle plus */
((int)text[0] >= 199 && (int)text[0] <= 209) || /* */
(int)text[0] == 217 || /* and */
(int)text[0] == 218) /* or */
#else
else
if ((int)text[0] == 0x2264 || /* less or equal */
(int)text[0] == 0x00B1 || /* plus or minus */
(int)text[0] == 0x2265 || /* greater or equal */
(int)text[0] == 0x00D7 || /* times */
(int)text[0] == 0x00F7 || /* divide */
(int)text[0] == 0x2260 || /* not equal */
(int)text[0] == 0x2261 || /* identical */
(int)text[0] == 0x2248 || /* equivalent */
(int)text[0] == 0x2297 || /* circle times */
(int)text[0] == 0x2295 || /* circle plus */
(int)text[0] == 0x2229 || /* Intersection */
(int)text[0] == 0x222A || /* Union */
(int)text[0] == 0x2283 || /* Superset of */
(int)text[0] == 0x2287 || /* Superset of or equal to */
(int)text[0] == 0x2284 || /* Not a subset of */
(int)text[0] == 0x2282 || /* Subset of */
(int)text[0] == 0x2286 || /* Subset of or equal to */
(int)text[0] == 0x2208 || /* Element of */
(int)text[0] == 0x2209 || /* Not an element of */
(int)text[0] == 0x2220 || /* Angle */
(int)text[0] == 0x2207 || /* Nabla */
(int)text[0] == 0x2227 || /* and */
(int)text[0] == 0x2228 || /* or */
(int)text[0] == 0x2190 || /* left arrow */
(int)text[0] == 0x2192 || /* right arrow */
(int)text[0] == 0x2194) /* left right arrow */
#endif
/* infix operator */
val = MathML_ATTR_IntAddSpace_VAL_both;
else
val = MathML_ATTR_IntAddSpace_VAL_nospace;
#ifndef _I18N_
}
#endif
}
}
TtaSetAttributeValue (attr, val, el, doc);
}
}
/*----------------------------------------------------------------------
ChildOfMRowOrInferred
Return TRUE if element el is a child of a MROW element or an
inferred MROW element
----------------------------------------------------------------------*/
ThotBool ChildOfMRowOrInferred (Element el)
{
ElementType elType;
Element parent;
ThotBool result;
result = FALSE;
parent = TtaGetParent (el);
if (parent)
{
elType = TtaGetElementType (parent);
result = (elType.ElTypeNum == MathML_EL_MROW ||
elType.ElTypeNum == MathML_EL_SqrtBase ||
elType.ElTypeNum == MathML_EL_MSTYLE ||
elType.ElTypeNum == MathML_EL_MERROR ||
elType.ElTypeNum == MathML_EL_MENCLOSE ||
elType.ElTypeNum == MathML_EL_MPADDED ||
elType.ElTypeNum == MathML_EL_MPHANTOM ||
elType.ElTypeNum == MathML_EL_MFENCED ||
elType.ElTypeNum == MathML_EL_CellWrapper ||
elType.ElTypeNum == MathML_EL_MathML ||
elType.ElTypeNum == MathML_EL_FencedExpression);
}
return result;
}
/*----------------------------------------------------------------------
CheckFence
If el is a MO element,
- if it's a large operator (∑ for instance), put a presentation
rule to enlarge the character.
- if it's a child of a MROW (or equivalent) element and if it contains
a single fence character, transform the MO into a MF and the fence
character into a Thot stretchable symbol.
----------------------------------------------------------------------*/
void CheckFence (Element el, Document doc)
{
ElementType elType, contType;
Element content;
AttributeType attrType;
Attribute attr, attrStretchy;
Language lang;
PresentationValue pval;
PresentationContext ctxt;
CHAR_T text[2];
char script;
unsigned char c;
int len, val, oldStructureChecking;
elType = TtaGetElementType (el);
if (elType.ElTypeNum == MathML_EL_MO ||
elType.ElTypeNum == MathML_EL_OpeningFence ||
elType.ElTypeNum == MathML_EL_ClosingFence ||
elType.ElTypeNum == MathML_EL_FencedSeparator)
/* the element is a MO or equivalent */
{
content = TtaGetFirstChild (el);
if (content != NULL)
{
contType = TtaGetElementType (content);
if (contType.ElTypeNum == MathML_EL_TEXT_UNIT)
{
len = TtaGetElementVolume (content);
if (len == 1)
/* the MO element contains a single character */
{
TtaGiveBufferContent (content, text, len+1, &lang);
script = TtaGetScript (lang);
#ifdef _I18N_
if (text[0] == 8721 || text[0] == 8719) /* large Sigma or Pi */
#else
if ((script == 'G') &&
(text[0] == 229 || text[0] == 213)) /* large Sigma or Pi */
#endif
/* it's a large operator */
{
ctxt = TtaGetSpecificStyleContext (doc);
ctxt->destroy = FALSE;
/* the specific presentation to be created is not a CSS rule */
ctxt->cssSpecificity = 0;
pval.typed_data.unit = STYLE_UNIT_PERCENT;
pval.typed_data.real = FALSE;
pval.typed_data.value = 180;
TtaSetStylePresentation (PRSize, content, NULL, ctxt, pval);
}
else if (ChildOfMRowOrInferred (el))
/* the MO element is a child of a MROW element */
{
if ((
#ifndef _I18N_
(script == 'L') &&
#endif
(text[0] == '(' || text[0] == ')' ||
text[0] == '[' || text[0] == ']' ||
text[0] == '{' || text[0] == '}' ||
text[0] == '|')) ||
(
/* test left and right angle brackets */
#ifdef _I18N_
(text[0] == 9001 || text[0] == 9002)
#else
(script == 'G') &&
(text[0] == 225 || text[0] == 241)
#endif
))
/* it's a stretchable parenthesis or equivalent */
{
/* remove the content of the MO element */
TtaDeleteTree (content, doc);
/* change the MO element into a MF element */
if (elType.ElTypeNum == MathML_EL_MO)
ChangeTypeOfElement (el, doc, MathML_EL_MF);
/* is there an attribute stretchy on this mo element? */
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = MathML_ATTR_stretchy;
attrStretchy = TtaGetAttribute (el, attrType);
if (attrStretchy)
val = TtaGetAttributeValue (attrStretchy);
else
val = MathML_ATTR_stretchy_VAL_true;
if (val == MathML_ATTR_stretchy_VAL_true)
{
/* attach a IntVertStretch attribute to the MF element */
attrType.AttrTypeNum = MathML_ATTR_IntVertStretch;
attr = TtaGetAttribute (el, attrType);
if (!attr)
{
attr = TtaNewAttribute (attrType);
TtaAttachAttribute (el, attr, doc);
}
TtaSetAttributeValue (attr,
MathML_ATTR_IntVertStretch_VAL_yes_,
el, doc);
}
/* create a new content for the MF element */
elType.ElTypeNum = MathML_EL_SYMBOL_UNIT;
#ifdef _I18N_
if (text[0] == 9002)
#else
if (script == 'G' && text[0] == 241)
#endif
c = '>'; /* RightAngleBracket */
else
#ifdef _I18N_
if (text[0] == 9001)
#else
if (script == 'G' && text[0] == 225)
#endif
c = '<'; /* LeftAngleBracket */
else
c = (char) text[0];
content = TtaNewElement (doc, elType);
/* do not check the Thot abstract tree against the structure
schema while inserting this child element */
oldStructureChecking = TtaGetStructureChecking (doc);
TtaSetStructureChecking (0, doc);
TtaInsertFirstChild (&content, el, doc);
TtaSetGraphicsShape (content, c, doc);
/* resume structure checking */
TtaSetStructureChecking ((ThotBool)oldStructureChecking, doc);
}
}
}
}
}
}
}
/*----------------------------------------------------------------------
CreateFencedSeparators
Create FencedSeparator elements within the fencedExpression
according to attribute separators of the MFENCED element.
----------------------------------------------------------------------*/
void CreateFencedSeparators (Element fencedExpression, Document doc, ThotBool record)
{
ElementType elType;
Element child, separator, leaf, next, prev, mfenced;
AttributeType attrType;
Attribute attr;
int length, sep, i;
Language lang;
char text[32], sepValue[4];
/* get the separators attribute */
mfenced = TtaGetParent (fencedExpression);
elType = TtaGetElementType (fencedExpression);
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = MathML_ATTR_separators;
text[0] = ','; /* default value is sparators="," */
text[1] = EOS;
length = 1;
attr = TtaGetAttribute (mfenced, attrType);
if (attr != NULL)
{
length = 31;
TtaGiveTextAttributeValue (attr, text, &length);
}
/* create FencedSeparator elements in the FencedExpression */
prev = NULL;
sep = 0;
/* skip leading spaces in attribute separators */
while (text[sep] <= SPACE && text[sep] != EOS)
sep++;
/* if attribute separators is empty or contains only spaces, do not
insert any separator element */
if (text[sep] != EOS)
{
child = TtaGetFirstChild (fencedExpression);
while (child != NULL)
{
next = child;
TtaNextSibling (&next);
elType = TtaGetElementType (child);
if (elType.ElTypeNum != MathML_EL_Construct)
{
if (prev != NULL)
{
elType.ElTypeNum = MathML_EL_FencedSeparator;
separator = TtaNewElement (doc, elType);
TtaInsertSibling (separator, prev, FALSE, doc);
elType.ElTypeNum = MathML_EL_TEXT_UNIT;
leaf = TtaNewElement (doc, elType);
TtaInsertFirstChild (&leaf, separator, doc);
sepValue[0] = text[sep];
sepValue[1] = EOS;
lang = TtaGetLanguageIdFromScript('L');
TtaSetTextContent (leaf, sepValue, lang, doc);
SetIntAddSpaceAttr (separator, doc);
SetIntVertStretchAttr (separator, doc, 0, NULL);
CheckFence (separator, doc);
/* is there a following non-space character in separators? */
i = sep + 1;
while (text[i] <= SPACE && text[i] != EOS)
i++;
if (text[i] > SPACE && text[i] != EOS)
sep = i;
if (record)
TtaRegisterElementCreate (separator, doc);
}
prev = child;
}
child = next;
}
}
}
/*----------------------------------------------------------------------
CreateOpeningOrClosingFence
Create the OpeningFence or ClosingFence element (depending on parameter
open) for the MFENCED element el which contain the fencedExpression
element.
----------------------------------------------------------------------*/
static void CreateOpeningOrClosingFence (Element fencedExpression,
Element el, Document doc,
ThotBool open)
{
ElementType elType;
Element leaf, fence;
AttributeType attrType;
Attribute attr;
int length;
char text[32];
elType = TtaGetElementType (el);
attrType.AttrSSchema = elType.ElSSchema;
if (open)
{
text[0] = '('; /* default value of attribute 'open' */
attrType.AttrTypeNum = MathML_ATTR_open;
elType.ElTypeNum = MathML_EL_OpeningFence;
}
else
{
text[0] = ')'; /* default value of attribute 'close' */
attrType.AttrTypeNum = MathML_ATTR_close;
elType.ElTypeNum = MathML_EL_ClosingFence;
}
attr = TtaGetAttribute (el, attrType);
if (attr != NULL)
{
length = 31;
TtaGiveTextAttributeValue (attr, text, &length);
if (length != 1)
/* content of attribute open or close should be a single character */
text[0] = '?';
}
text[1] = EOS;
fence = TtaNewElement (doc, elType);
TtaInsertSibling (fence, fencedExpression, open, doc);
elType.ElTypeNum = MathML_EL_TEXT_UNIT;
leaf = TtaNewElement (doc, elType);
TtaInsertFirstChild (&leaf, fence, doc);
TtaSetTextContent (leaf, text, TtaGetLanguageIdFromScript('L'), doc);
SetIntAddSpaceAttr (fence, doc);
SetIntVertStretchAttr (fence, doc, 0, NULL);
CheckFence (fence, doc);
}
/*----------------------------------------------------------------------
TransformMFENCED
Transform the content of a MFENCED element: create elements
OpeningFence, FencedExpression, ClosingFence and FencedSeparator.
----------------------------------------------------------------------*/
static void TransformMFENCED (Element el, Document doc)
{
ElementType elType;
Element child, fencedExpression, next, prev, firstChild;
child = TtaGetFirstChild (el);
if (child != NULL)
elType = TtaGetElementType (child);
if (child != NULL && elType.ElTypeNum == MathML_EL_OpeningFence)
/* The first child of this MFENCED element is an OpeningFence.
This MFENCED expression has already been transformed, possibly
by the Transform command */
{
TtaNextSibling (&child);
fencedExpression = child;
if (fencedExpression != NULL)
elType = TtaGetElementType (fencedExpression);
if (elType.ElTypeNum == MathML_EL_FencedExpression)
/* the second child is a FencedExpression. OK.
Remove all existing FencedSeparator elements */
{
child = TtaGetFirstChild (fencedExpression);
prev = NULL;
while (child != NULL)
{
elType = TtaGetElementType (child);
next = child;
TtaNextSibling (&next);
if (elType.ElTypeNum == MathML_EL_FencedSeparator)
/* Remove this separator */
TtaDeleteTree (child, doc);
child = next;
}
/* create FencedSeparator elements in the FencedExpression */
CreateFencedSeparators (fencedExpression, doc, FALSE);
}
}
else
/* this MFENCED element must be transformed */
{
/* create a FencedExpression element as a child of the MFENCED elem. */
elType = TtaGetElementType (el);
elType.ElTypeNum = MathML_EL_FencedExpression;
fencedExpression = TtaNewElement (doc, elType);
TtaInsertFirstChild (&fencedExpression, el, doc);
if (child == NULL)
/* empty MFENCED element */
{
elType.ElTypeNum = MathML_EL_Construct;
child = TtaNewElement (doc, elType);
TtaInsertFirstChild (&child, fencedExpression, doc);
SetIntPlaceholderAttr (child, doc);
}
else
{
/* move the content of the MFENCED element within the new
FencedExpression element */
prev = NULL;
firstChild = NULL;
while (child != NULL)
{
next = child;
TtaNextSibling (&next);
TtaRemoveTree (child, doc);
if (prev == NULL)
{
TtaInsertFirstChild (&child, fencedExpression, doc);
firstChild = child;
}
else
TtaInsertSibling (child, prev, FALSE, doc);
prev = child;
child = next;
}
/* create FencedSeparator elements in the FencedExpression */
CreateFencedSeparators (fencedExpression, doc, FALSE);
/* Create placeholders within the FencedExpression element */
CreatePlaceholders (firstChild, doc);
}
/* create the OpeningFence element according to the open attribute */
CreateOpeningOrClosingFence (fencedExpression, el, doc, TRUE);
/* create the ClosingFence element according to close attribute */
CreateOpeningOrClosingFence (fencedExpression, el, doc, FALSE);
}
}
/*----------------------------------------------------------------------
MathMLScriptShift
The MathML attribute attr (superscriptshift or subscriptshift) is associated
with element el (a msub, msup or msubsup).
If value is not NULL, generate the corresponding Thot VertPos rule for the
Subscript or Superscript child of el.
If value is NULL, remove the Thot VertPos rule.
-----------------------------------------------------------------------*/
void MathMLScriptShift (Document doc, Element el, char *value, int attr)
{
ElementType elType;
Element script, child;
int scrType;
PresentationValue pval;
PresentationContext ctxt;
/* get the Superscript or Subscript child of el */
if (attr == MathML_ATTR_superscriptshift)
scrType = MathML_EL_Superscript;
else if (attr == MathML_ATTR_subscriptshift)
scrType = MathML_EL_Subscript;
else
return;
script = NULL;
child = TtaGetFirstChild (el);
while (!script && child)
{
elType = TtaGetElementType (child);
if (elType.ElTypeNum == scrType)
script = child;
else
TtaNextSibling (&child);
}
if (script)
/* Superscript or Subscript element found */
{
ctxt = TtaGetSpecificStyleContext (doc);
if (!value)
/* remove the presentation rule */
{
ctxt->destroy = TRUE;
pval.typed_data.value = 0;
TtaSetStylePresentation (PRVertPos, script, NULL, ctxt, pval);
}
else
{
ctxt->destroy = FALSE;
/* parse the attribute value (a number followed by a unit) */
value = TtaSkipBlanks (value);
value = ParseCSSUnit (value, &pval);
if (pval.typed_data.unit != STYLE_UNIT_INVALID)
{
/* the specific presentation to be created is not a CSS rule */
ctxt->cssSpecificity = 0;
if (attr == MathML_ATTR_superscriptshift)
pval.typed_data.value = - pval.typed_data.value;
TtaSetStylePresentation (PRVertPos, script, NULL, ctxt, pval);
}
}
TtaFreeMemory (ctxt);
}
}
/*----------------------------------------------------------------------
SetScriptShift
If element el (which is a msup, msub or msubsup) has an attribute
att (which is subscriptshift or superscriptshift), generate the
corresponding Thot presentation rule.
----------------------------------------------------------------------*/
static void SetScriptShift (Element el, Document doc, int att)
{
AttributeType attrType;
ElementType elType;
Attribute attr;
char *value;
int length;
elType = TtaGetElementType (el);
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = att;
attr = TtaGetAttribute (el, attrType);
if (attr)
{
length = TtaGetTextAttributeLength (attr);
if (length > 0)
{
value = TtaGetMemory (length+1);
value[0] = EOS;
TtaGiveTextAttributeValue (attr, value, &length);
MathMLScriptShift (doc, el, value, att);
TtaFreeMemory (value);
}
}
}
/*----------------------------------------------------------------------
DeleteIntRowAlign
Remove attribute IntRowAlign from element row if there is no rowalign_mtr
attribut on this element.
-----------------------------------------------------------------------*/
static void DeleteIntRowAlign (Element row, Document doc)
{
ElementType elType;
AttributeType attrType;
Attribute attr;
elType = TtaGetElementType (row);
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = MathML_ATTR_rowalign_mtr;
attr = TtaGetAttribute (row, attrType);
if (!attr)
{
attrType.AttrTypeNum = MathML_ATTR_IntRowAlign;
attr = TtaGetAttribute (row, attrType);
if (attr)
TtaRemoveAttribute (row, attr, doc);
}
}
/*----------------------------------------------------------------------
SetIntRowAlign
Set attribute IntRowAlign for element row unless this element already has
a rowalign_mtr attribute
-----------------------------------------------------------------------*/
static void SetIntRowAlign (Element row, int val, Document doc)
{
ElementType elType;
AttributeType attrType;
Attribute attr;
elType = TtaGetElementType (row);
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = MathML_ATTR_rowalign_mtr;
attr = TtaGetAttribute (row, attrType);
if (!attr)
{
attrType.AttrTypeNum = MathML_ATTR_IntRowAlign;
attr = TtaGetAttribute (row, attrType);
if (!attr)
{
attr = TtaNewAttribute (attrType);
TtaAttachAttribute (row, attr, doc);
}
TtaSetAttributeValue (attr, val, row, doc);
}
}
/*----------------------------------------------------------------------
HandleRowalignAttribute
An attribute rowalign has been created, updated (if !delete) or deleted
(if delete) for element el in document doc. Update the IntRowAlign
attributes of all enclosed mrow elements accordingly.
----------------------------------------------------------------------*/
void HandleRowalignAttribute (Attribute attr, Element el, Document doc,
ThotBool delete)
{
char *value;
char *ptr;
int length, val;
ElementType elType;
Element row;
elType = TtaGetElementType (el);
if (elType.ElTypeNum != MathML_EL_MTABLE ||
strcmp (TtaGetSSchemaName (elType.ElSSchema), "MathML"))
/* ignore rowalign attribute on mstyle elements */
/* process it only on mtable elements */
return;
value = NULL;
if (!delete)
{
length = TtaGetTextAttributeLength (attr);
if (length > 0)
{
value = TtaGetMemory (length+1);
value[0] = EOS;
TtaGiveTextAttributeValue (attr, value, &length);
}
}
/* if attribute rowalign is created or updated but has no value, don't
do anything */
if (!delete && !value)
return;
ptr = value;
val = 0;
elType.ElTypeNum = MathML_EL_TableRow;
row = TtaSearchTypedElement (elType, SearchInTree, el);
while (row)
{
elType = TtaGetElementType (row);
/* skip comments and other non row elements */
if ((elType.ElTypeNum == MathML_EL_MTR ||
elType.ElTypeNum == MathML_EL_MLABELEDTR) &&
strcmp (TtaGetSSchemaName (elType.ElSSchema), "MathML") == 0)
{
if (delete)
DeleteIntRowAlign (row, doc);
else
{
if (*ptr != EOS)
{
/* get next word in the attribute value */
ptr = TtaSkipBlanks (ptr);
/* process that word */
if (*ptr != EOS && *ptr != ' ')
{
if (!strncasecmp (ptr, "top", 3))
val = MathML_ATTR_IntRowAlign_VAL_IntTop;
else if (!strncasecmp (ptr, "bottom", 6))
val = MathML_ATTR_IntRowAlign_VAL_IntBottom;
else if (!strncasecmp (ptr, "center", 6))
val = MathML_ATTR_IntRowAlign_VAL_IntCenter;
else if (!strncasecmp (ptr, "baseline", 8))
val = MathML_ATTR_IntRowAlign_VAL_IntBaseline;
else if (!strncasecmp (ptr, "axis", 4))
val = MathML_ATTR_IntRowAlign_VAL_IntAxis;
else
val = 0;
/* skip the word that has been processed */
while (*ptr != EOS && *ptr != ' ')
ptr++;
}
}
if (val > 0)
SetIntRowAlign (row, val, doc);
}
}
TtaNextSibling (&row);
}
if (value)
TtaFreeMemory (value);
}
/*----------------------------------------------------------------------
DeleteIntColAlign
Remove attribute IntColAlign from element cell if there is no columnalign_mtd
attribut on this element.
-----------------------------------------------------------------------*/
static void DeleteIntColAlign (Element cell, Document doc)
{
ElementType elType;
AttributeType attrType;
Attribute attr;
elType = TtaGetElementType (cell);
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = MathML_ATTR_columnalign_mtd;
attr = TtaGetAttribute (cell, attrType);
if (!attr)
{
attrType.AttrTypeNum = MathML_ATTR_IntColAlign;
attr = TtaGetAttribute (cell, attrType);
if (attr)
TtaRemoveAttribute (cell, attr, doc);
}
}
/*----------------------------------------------------------------------
SetIntColAlign
Set attribute IntColAlign for element cell unless this element already has
a columnalign_mtd attribute
-----------------------------------------------------------------------*/
static void SetIntColAlign (Element cell, int val, Document doc)
{
ElementType elType;
AttributeType attrType;
Attribute attr;
elType = TtaGetElementType (cell);
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = MathML_ATTR_columnalign_mtd;
attr = TtaGetAttribute (cell, attrType);
if (!attr)
{
attrType.AttrTypeNum = MathML_ATTR_IntColAlign;
attr = TtaGetAttribute (cell, attrType);
if (!attr)
{
attr = TtaNewAttribute (attrType);
TtaAttachAttribute (cell, attr, doc);
}
TtaSetAttributeValue (attr, val, cell, doc);
}
}
/*----------------------------------------------------------------------
RowWithoutColalignAttr
if skip: if element row has a columnalign attribute, get the next sibling row
element without a columnalign attribute and return its first cell
if not skip: always return the first cell in the row, and the columnalign
attribute of that row if there is one.
-----------------------------------------------------------------------*/
static void RowWithoutColalignAttr (Element *row, Element *cell,
Attribute *attr, ThotBool skip)
{
ElementType elType;
AttributeType attrType;
elType = TtaGetElementType (*row);
attrType.AttrSSchema = elType.ElSSchema;
attrType.AttrTypeNum = MathML_ATTR_columnalign;
*cell = NULL;
*attr = NULL;
while (*row != NULL && *cell == NULL)
{
elType = TtaGetElementType (*row);
if ((elType.ElTypeNum != MathML_EL_MTR &&
elType.ElTypeNum != MathML_EL_MLABELEDTR) ||
strcmp (TtaGetSSchemaName (elType.ElSSchema), "MathML"))
/* not a row. Skip it */
TtaNextSibling (row);
else
{
/* skip that row if it has a columnalign attribute */
*attr = TtaGetAttribute (*row, attrType);
if (skip && *attr != NULL)
{
TtaNextSibling (row);
*attr = NULL;
}
else
/* it's a row without a columnalign attribute */
*cell = TtaGetFirstChild (*row);
}
}
}
/*----------------------------------------------------------------------
HandleColalignAttribute
An attribute columnalign has been created, updated (if !delete) or deleted
(if delete) for element el in document doc. Update the IntColAlign
attributes of all concerned cells accordingly.
If allRows is TRUE, process also rows that have their own columnalign
attribute, according to that attribute, otherwise skip those rows.
----------------------------------------------------------------------*/
void HandleColalignAttribute (Attribute attr, Element el, Document doc,
ThotBool delete, ThotBool allRows)
{
char *value, *localValue;
char *ptr;
int length, val;
ElementType elType;
Element cell, row;
Attribute localAttr;
ThotBool fullTable;
elType = TtaGetElementType (el);
if ((elType.ElTypeNum != MathML_EL_MTABLE &&
elType.ElTypeNum != MathML_EL_MTR &&
elType.ElTypeNum != MathML_EL_MLABELEDTR) ||
strcmp (TtaGetSSchemaName (elType.ElSSchema), "MathML"))
/* ignore columnalign attribute on mstyle elements */
/* process it only on mtable elements */
return;
fullTable = (elType.ElTypeNum == MathML_EL_MTABLE);
value = NULL;
localValue = NULL;
if (!delete)
{
length = TtaGetTextAttributeLength (attr);
if (length > 0)
{
value = TtaGetMemory (length+1);
value[0] = EOS;
TtaGiveTextAttributeValue (attr, value, &length);
}
}
/* if attribute columnalign is created or updated but has no value, don't
do anything */
if (!delete && !value)
return;
ptr = value;
val = 0;
/* get the first cell within the element */
elType.ElTypeNum = MathML_EL_MTD;
cell = TtaSearchTypedElement (elType, SearchInTree, el);
if (cell && fullTable)
{
elType.ElTypeNum = MathML_EL_TableRow;
row = TtaGetTypedAncestor (cell, elType);
RowWithoutColalignAttr (&row, &cell, &localAttr, !allRows);
if (localAttr)
{
length = TtaGetTextAttributeLength (localAttr);
if (length > 0)
{
if (localValue)
TtaFreeMemory (localValue);
localValue = TtaGetMemory (length+1);
localValue[0] = EOS;
TtaGiveTextAttributeValue (localAttr, localValue, &length);
ptr = localValue;
}
}
}
while (cell)
{
elType = TtaGetElementType (cell);
/* skip comments and other non cell elements */
if (elType.ElTypeNum == MathML_EL_MTD &&
strcmp (TtaGetSSchemaName (elType.ElSSchema), "MathML") == 0)
{
if (delete)
DeleteIntColAlign (cell, doc);
else
{
if (*ptr != EOS)
{
/* get next word in the attribute value */
ptr = TtaSkipBlanks (ptr);
/* process that word */
if (*ptr != EOS && *ptr != ' ')
{
if (!strncasecmp (ptr, "left", 4))
val = MathML_ATTR_IntColAlign_VAL_IntLeft;
else if (!strncasecmp (ptr, "center", 6))
val = MathML_ATTR_IntColAlign_VAL_IntCenter;
else if (!strncasecmp (ptr, "right", 5))
val = MathML_ATTR_IntColAlign_VAL_IntRight;
else
val = 0;
/* skip the word that has been processed */
while (*ptr != EOS && *ptr != ' ')
ptr++;
}
}
if (val > 0)
SetIntColAlign (cell, val, doc);
}
}
TtaNextSibling (&cell);
if (!cell && fullTable && row)
/* no more sibling cell. If the columnalign attribute is for the
full table, get the first cell in the next row */
{
TtaNextSibling (&row);
if (row)
{
/* parse value of columnalign attribute again from the beginning */
ptr = value;
RowWithoutColalignAttr (&row, &cell, &localAttr, !allRows);
if (localAttr)
{
length = TtaGetTextAttributeLength (localAttr);
if (length > 0)
{
if (localValue)
TtaFreeMemory (localValue);
localValue = TtaGetMemory (length+1);
localValue[0] = EOS;
TtaGiveTextAttributeValue (localAttr, localValue, &length);
ptr = localValue;
}
}
}
}
}
if (value)
TtaFreeMemory (value);
if (localValue)
TtaFreeMemory (localValue);
}
/*----------------------------------------------------------------------
HandleRowlinesAttribute
An attribute rowlines has been created, updated or deleted (if delete
is TRUE) for element el in document doc. Update attribute MLineBelow
of all cells accordingly.
----------------------------------------------------------------------*/
void HandleRowlinesAttribute (Attribute attr, Element el, Document doc,
ThotBool delete)
{
char *value;
char *ptr, *spanPtr;
int length, val, rowspan, i, cellVal;
ElementType elType, rowType, cellType;
Element row, nextRow, cell;
ThotBool stop;
AttributeType attrType, rowspanType;
Attribute intAttr, rowspanAttr;
elType = TtaGetElementType (el);
if (elType.ElTypeNum != MathML_EL_MTABLE ||
strcmp (TtaGetSSchemaName (elType.ElSSchema), "MathML"))
/* ignore rowlines attribute on mstyle elements */
/* process it only on mtable elements */
return;
value = NULL;
if (!delete)
{
length = TtaGetTextAttributeLength (attr);
if (length > 0)
{
value = TtaGetMemory (length+1);
value[0] = EOS;
TtaGiveTextAttributeValue (attr, value, &length);
}
}
/* if attribute rowlines is created or updated but has no value, don't
do anything */
if (!delete && !value)
return;
ptr = value;
val = 0;
attrType.AttrSSchema = elType.ElSSchema;
rowspanType.AttrSSchema = elType.ElSSchema;
rowspanType.AttrTypeNum = MathML_ATTR_rowspan_;
/* check all rows within the table */
elType.ElTypeNum = MathML_EL_TableRow;
row = TtaSearchTypedElement (elType, SearchInTree, el);
while (row)
{
/* get the next row to check if the current row is the last one */
nextRow = row;
stop = FALSE;
do
{
TtaNextSibling (&nextRow);
if (!nextRow)
stop = TRUE;
else
{
rowType = TtaGetElementType (nextRow);
/* skip comments and other non mrow elements */
if ((rowType.ElTypeNum == MathML_EL_MTR ||
rowType.ElTypeNum == MathML_EL_MLABELEDTR) &&
!strcmp (TtaGetSSchemaName (rowType.ElSSchema), "MathML"))
/* it's the next mrow */
stop = TRUE;
}
}
while (!stop);
if (!nextRow)
/* row is the last in the table. It must not have a line
at the bottom. Delete it if there is one */
val = 0;
else
{
if (delete)
val = 0;
else
if (*ptr != EOS)
{
/* get next word in the attribute value */
ptr = TtaSkipBlanks (ptr);
/* process that word */
if (*ptr != EOS && *ptr != ' ')
{
if (!strncasecmp (ptr, "none", 4))
val = 0;
else if (!strncasecmp (ptr, "solid", 5))
val = MathML_ATTR_MLineBelow_VAL_solid_;
else if (!strncasecmp (ptr, "dashed", 6))
val = MathML_ATTR_MLineBelow_VAL_dashed_;
else
val = 0;
/* skip the word that has been processed */
while (*ptr != EOS && *ptr != ' ')
ptr++;
}
}
}
/* get the first cell of that row (ignoring Label cells) */
elType.ElTypeNum = MathML_EL_MTD;
cell = TtaSearchTypedElement (elType, SearchInTree, row);
/* update attribute MLineBelow for all cells in that row */
while (cell)
{
cellType = TtaGetElementType (cell);
/* skip comments and other non mtd elements */
if (cellType.ElTypeNum == MathML_EL_MTD &&
!strcmp (TtaGetSSchemaName (cellType.ElSSchema), "MathML"))
/* that's a mtd element. Process it */
{
/* is there a rowspan attribute on that cell? */
rowspanAttr = TtaGetAttribute (cell, rowspanType);
if (!rowspanAttr)
rowspan = 1;
else
rowspan = TtaGetAttributeValue (rowspanAttr);
/* by default, use the value for the current row */
cellVal = val;
if (!delete)
{
/* skip rowspan-1 words in the value of attribute rowlines */
if (rowspan > 1)
{
spanPtr = ptr;
for (i = 1; i < rowspan && *spanPtr != EOS; i++)
{
spanPtr = TtaSkipBlanks (spanPtr);
if (*spanPtr != EOS && *spanPtr != ' ')
{
if (!strncasecmp (spanPtr, "none", 4))
cellVal = 0;
else if (!strncasecmp (spanPtr, "solid", 5))
cellVal = MathML_ATTR_MLineBelow_VAL_solid_;
else if (!strncasecmp (spanPtr, "dashed", 6))
cellVal = MathML_ATTR_MLineBelow_VAL_dashed_;
else
cellVal = 0;
}
/* skip the word that has been processed */
while (*spanPtr != EOS && *spanPtr != ' ')
spanPtr++;
}
}
}
if (rowspan == 1)
attrType.AttrTypeNum = MathML_ATTR_MLineBelow;
else
attrType.AttrTypeNum = MathML_ATTR_MLineBelowExt;
intAttr = TtaGetAttribute (cell, attrType);
if (cellVal == 0)
{
if (intAttr)
/* remove attribute MLineBelow */
TtaRemoveAttribute (cell, intAttr, doc);
}
else
/* set attribute MLineBelow */
{
if (!intAttr)
{
intAttr = TtaNewAttribute (attrType);
TtaAttachAttribute (cell, intAttr, doc);
}
TtaSetAttributeValue (intAttr, cellVal, cell, doc);
}
}
TtaNextSibling (&cell);
}
row = nextRow;
}
if (value)
TtaFreeMemory (value);
}
/*----------------------------------------------------------------------
HandleColumnlinesAttribute
An attribute columnlines has been created, updated or deleted (if delete
is TRUE) for element el in document doc. Update attribute MLineOnTheRight
of all cells accordingly.
----------------------------------------------------------------------*/
void HandleColumnlinesAttribute (Attribute attr, Element el, Document doc,
ThotBool delete)
{
char *value;
char *ptr;
int length, val, colspan, rowspan, i;
ElementType elType;
Element row, cell, nextCell;
ThotBool stop;
AttributeType attrType, colspanType, rowspanType;
Attribute intAttr, spanAttr;
elType = TtaGetElementType (el);
if (elType.ElTypeNum != MathML_EL_MTABLE ||
strcmp (TtaGetSSchemaName (elType.ElSSchema), "MathML"))
/* ignore rowlines attribute on mstyle elements */
/* process it only on mtable elements */
return;
value = NULL;
if (!delete)
{
length = TtaGetTextAttributeLength (attr);
if (length > 0)
{
value = TtaGetMemory (length+1);
value[0] = EOS;
TtaGiveTextAttributeValue (attr, value, &length);
}
}
/* if attribute columnlines is created or updated but has no value, don't
do anything */
if (!delete && !value)
return;
val = 0;
attrType.AttrSSchema = elType.ElSSchema;
colspanType.AttrSSchema = elType.ElSSchema;
colspanType.AttrTypeNum = MathML_ATTR_columnspan;
rowspanType.AttrSSchema = elType.ElSSchema;
rowspanType.AttrTypeNum = MathML_ATTR_rowspan_;
/* check all cells in all rows in the table */
elType.ElTypeNum = MathML_EL_TableRow;
row = TtaSearchTypedElement (elType, SearchInTree, el);
while (row)
{
elType = TtaGetElementType (row);
if ((elType.ElTypeNum == MathML_EL_MTR ||
elType.ElTypeNum == MathML_EL_MLABELEDTR) &&
strcmp (TtaGetSSchemaName (elType.ElSSchema), "MathML") == 0)
/* that's a table row. check all its cells */
{
/* start from the beginning of the columnlines attribute */
ptr = value;
val = 0;
/* get the first cell of that row (ignoring Label cells) */
elType.ElTypeNum = MathML_EL_MTD;
cell = TtaSearchTypedElement (elType, SearchInTree, row);
while (cell)
{
/* get the next cell in the current row to check if the current
cell is the last one in the row */
nextCell = cell;
stop = FALSE;
do
{
TtaNextSibling (&nextCell);
if (!nextCell)
stop = TRUE;
else
{
elType = TtaGetElementType (nextCell);
/* skip comments and other non mtd elements */
if (elType.ElTypeNum == MathML_EL_MTD &&
strcmp (TtaGetSSchemaName (elType.ElSSchema), "MathML") == 0)
/* it's the next cell */
stop = TRUE;
}
}
while (!stop);
/* is there a rowspan attribute on that cell? */
spanAttr = TtaGetAttribute (cell, rowspanType);
if (!spanAttr)
rowspan = 1;
else
rowspan = TtaGetAttributeValue (spanAttr);
if (!nextCell)
/* it's the last cell in the row. It must not have a line
on its right edge. Delete it if there is noe. */
val = 0;
else
/* set the attribute MLineOnTheRight for this cell */
{
if (delete)
val = 0;
else
if (*ptr != EOS)
{
/* is there a columnspan attribute on that cell? */
spanAttr = TtaGetAttribute (cell, colspanType);
if (!spanAttr)
colspan = 1;
else
colspan = TtaGetAttributeValue (spanAttr);
/* skip (colspan - 1) words in the attribute */
for (i = 1; i <= colspan && *ptr != EOS; i++)
{
/* get next word in the attribute value */
ptr = TtaSkipBlanks (ptr);
/* process that word */
if (*ptr != EOS && *ptr != ' ')
{
if (!strncasecmp (ptr, "none", 4))
val = 0;
else if (!strncasecmp (ptr, "solid", 5))
val = MathML_ATTR_MLineOnTheRight_VAL_solid_;
else if (!strncasecmp (ptr, "dashed", 6))
val = MathML_ATTR_MLineOnTheRight_VAL_dashed_;
else
val = 0;
/* skip the word that has been processed */
while (*ptr != EOS && *ptr != ' ')
ptr++;
}
}
}
}
if (rowspan == 1)
attrType.AttrTypeNum = MathML_ATTR_MLineOnTheRight;
else
attrType.AttrTypeNum = MathML_ATTR_MLineOnTheRightExt;
intAttr = TtaGetAttribute (cell, attrType);
if (val == 0)
{
if (intAttr)
/* remove attribute MLineOnTheRight */
TtaRemoveAttribute (cell, intAttr, doc);
}
else
/* set attribute MLineOnTheRight */
{
if (!intAttr)
{
intAttr = TtaNewAttribute (attrType);
TtaAttachAttribute (cell, intAttr, doc);
}
TtaSetAttributeValue (intAttr, val, cell, doc);
}
cell = nextCell;
}
}
TtaNextSibling (&row);
}
if (value)
TtaFreeMemory (value);
}
/*----------------------------------------------------------------------
MathMLElementComplete
Check the Thot structure of the MathML element el.
----------------------------------------------------------------------*/
void MathMLElementComplete (ParserData *context, Element el, int *error)
{
Document doc;
ElementType elType, parentType;
Element child, parent, new, prev, next;
AttributeType attrType;
Attribute attr;
SSchema MathMLSSchema;
ThotBool ok;
ok = TRUE;
*error = 0;
doc = context->doc;
elType = TtaGetElementType (el);
MathMLSSchema = GetMathMLSSchema (doc);
if (elType.ElSSchema == MathMLSSchema)
{
switch (elType.ElTypeNum)
{
case MathML_EL_MathML:
/* Create placeholders within the MathML element */
CreatePlaceholders (TtaGetFirstChild (el), doc);
break;
case MathML_EL_MI:
SetFontstyleAttr (el, doc);
break;
case MathML_EL_MO:
SetIntAddSpaceAttr (el, doc);
SetIntVertStretchAttr (el, doc, 0, NULL);
/* if the MO element is a child of a MROW (or equivalent) and if it
contains a fence character, transform this MO into MF and
transform the fence character into a Thot SYMBOL */
CheckFence (el, doc);
break;
case MathML_EL_MSPACE:
break;
case MathML_EL_MROW:
/* Create placeholders within the MROW */
CreatePlaceholders (TtaGetFirstChild (el), doc);
break;
case MathML_EL_MFRAC:
case MathML_EL_BevelledMFRAC:
/* end of a fraction. Create a Numerator and a Denominator */
ok = CheckMathSubExpressions (el, MathML_EL_Numerator,
MathML_EL_Denominator, 0, doc);
break;
case MathML_EL_MSQRT:
/* end of a Square Root */
/* Create placeholders within the element */
CreatePlaceholders (TtaGetFirstChild (el), doc);
/* Create a SqrtBase that contains all children of the MSQRT */
CreateWrapper (el, MathML_EL_SqrtBase, doc);
break;
case MathML_EL_MROOT:
/* end of a Root. Create a RootBase and an Index */
ok = CheckMathSubExpressions (el, MathML_EL_RootBase,
MathML_EL_Index, 0, doc);
break;
case MathML_EL_MENCLOSE:
/* Create placeholders within the element */
CreatePlaceholders (TtaGetFirstChild (el), doc);
break;
case MathML_EL_MSTYLE:
case MathML_EL_MERROR:
case MathML_EL_MPADDED:
case MathML_EL_MPHANTOM:
/* Create placeholders within the element */
CreatePlaceholders (TtaGetFirstChild (el), doc);
break;
case MathML_EL_MFENCED:
TransformMFENCED (el, doc);
break;
case MathML_EL_MSUB:
/* end of a MSUB. Create Base and Subscript */
ok = CheckMathSubExpressions (el, MathML_EL_Base,
MathML_EL_Subscript, 0, doc);
SetScriptShift (el, doc, MathML_ATTR_subscriptshift);
SetIntVertStretchAttr (el, doc, MathML_EL_Base, NULL);
break;
case MathML_EL_MSUP:
/* end of a MSUP. Create Base and Superscript */
ok = CheckMathSubExpressions (el, MathML_EL_Base,
MathML_EL_Superscript, 0, doc);
SetScriptShift (el, doc, MathML_ATTR_superscriptshift);
SetIntVertStretchAttr (el, doc, MathML_EL_Base, NULL);
break;
case MathML_EL_MSUBSUP:
/* end of a MSUBSUP. Create Base, Subscript, and Superscript */
ok = CheckMathSubExpressions (el, MathML_EL_Base,
MathML_EL_Subscript,
MathML_EL_Superscript, doc);
SetScriptShift (el, doc, MathML_ATTR_subscriptshift);
SetScriptShift (el, doc, MathML_ATTR_superscriptshift);
SetIntVertStretchAttr (el, doc, MathML_EL_Base, NULL);
break;
case MathML_EL_MUNDER:
/* end of a MUNDER. Create UnderOverBase, and Underscript */
ok = CheckMathSubExpressions (el, MathML_EL_UnderOverBase,
MathML_EL_Underscript, 0, doc);
SetIntHorizStretchAttr (el, doc);
SetIntVertStretchAttr (el, doc, MathML_EL_UnderOverBase, NULL);
break;
case MathML_EL_MOVER:
/* end of a MOVER. Create UnderOverBase, and Overscript */
ok = CheckMathSubExpressions (el, MathML_EL_UnderOverBase,
MathML_EL_Overscript, 0, doc);
SetIntHorizStretchAttr (el, doc);
SetIntVertStretchAttr (el, doc, MathML_EL_UnderOverBase, NULL);
break;
case MathML_EL_MUNDEROVER:
/* end of a MUNDEROVER. Create UnderOverBase, Underscript, and
Overscript */
ok = CheckMathSubExpressions (el, MathML_EL_UnderOverBase,
MathML_EL_Underscript,
MathML_EL_Overscript, doc);
SetIntHorizStretchAttr (el, doc);
SetIntVertStretchAttr (el, doc, MathML_EL_UnderOverBase, NULL);
break;
case MathML_EL_MMULTISCRIPTS:
/* end of a MMULTISCRIPTS. Create all elements defined in the
MathML S schema */
BuildMultiscript (el, doc);
break;
case MathML_EL_MTABLE:
/* end of a MTABLE. Create all elements defined in the MathML S
schema */
CheckMTable (el, doc, TRUE);
/* if the table has a rowalign attribute, process it */
attrType.AttrSSchema = MathMLSSchema;
attrType.AttrTypeNum = MathML_ATTR_rowalign;
attr = TtaGetAttribute (el, attrType);
if (attr)
HandleRowalignAttribute (attr, el, doc, FALSE);
/* if the table has a columnalign attribute, process it */
attrType.AttrTypeNum = MathML_ATTR_columnalign;
attr = TtaGetAttribute (el, attrType);
if (attr)
HandleColalignAttribute (attr, el, doc, FALSE, FALSE);
/* if the table has a rowlines attribute, process it */
attrType.AttrSSchema = MathMLSSchema;
attrType.AttrTypeNum = MathML_ATTR_rowlines;
attr = TtaGetAttribute (el, attrType);
if (attr)
HandleRowlinesAttribute (attr, el, doc, FALSE);
/* if the table has a columnlines attribute, process it */
attrType.AttrTypeNum = MathML_ATTR_columnlines;
attr = TtaGetAttribute (el, attrType);
if (attr)
HandleColumnlinesAttribute (attr, el, doc, FALSE);
break;
case MathML_EL_MTR:
/* if the row has a columnalign attribute, process it */
attrType.AttrSSchema = MathMLSSchema;
attrType.AttrTypeNum = MathML_ATTR_columnalign;
attr = TtaGetAttribute (el, attrType);
if (attr)
HandleColalignAttribute (attr, el, doc, FALSE, TRUE);
break;
case MathML_EL_MLABELEDTR:
/* if the row has a columnalign attribute, process it */
attrType.AttrSSchema = MathMLSSchema;
attrType.AttrTypeNum = MathML_ATTR_columnalign;
attr = TtaGetAttribute (el, attrType);
if (attr)
HandleColalignAttribute (attr, el, doc, FALSE, TRUE);
break;
case MathML_EL_MTD:
/* Create placeholders within the table cell */
CreatePlaceholders (TtaGetFirstChild (el), doc);
break;
case MathML_EL_MACTION:
/* Create placeholders within the MACTION element */
CreatePlaceholders (TtaGetFirstChild (el), doc);
break;
default:
break;
}
parent = TtaGetParent (el);
if (parent)
{
parentType = TtaGetElementType (parent);
if (parentType.ElSSchema != elType.ElSSchema)
/* root of a MathML tree, Create a MathML element if there is no */
if (elType.ElTypeNum != MathML_EL_MathML)
{
elType.ElSSchema = MathMLSSchema;
elType.ElTypeNum = MathML_EL_MathML;
new = TtaNewElement (doc, elType);
TtaInsertSibling (new, el, TRUE, doc);
next = el;
TtaNextSibling (&next);
TtaRemoveTree (el, doc);
TtaInsertFirstChild (&el, new, doc);
prev = el;
while (next != NULL)
{
child = next;
TtaNextSibling (&next);
TtaRemoveTree (child, doc);
TtaInsertSibling (child, prev, FALSE, doc);
prev = child;
}
/* Create placeholders within the MathML element */
CreatePlaceholders (el, doc);
}
}
}
if (!ok)
/* send an error message */
*error = 1;
}
/*----------------------------------------------------------------------
UnknownMathMLNameSpace
The element doesn't belong to a supported namespace
----------------------------------------------------------------------*/
void UnknownMathMLNameSpace (ParserData *context,
Element *unknownEl,
char* content)
{
ElementType elType;
Element elText;
/* Create a new Invalid_element */
elType.ElSSchema = GetXMLSSchema (MATH_TYPE, context->doc);
elType.ElTypeNum = MathML_EL_Unknown_namespace;
*unknownEl = TtaNewElement (context->doc, elType);
if (*unknownEl != NULL)
{
XmlSetElemLineNumber (*unknownEl);
InsertXmlElement (unknownEl);
context->lastElementClosed = TRUE;
elType.ElTypeNum = MathML_EL_TEXT_UNIT;
elText = TtaNewElement (context->doc, elType);
XmlSetElemLineNumber (elText);
TtaInsertFirstChild (&elText, *unknownEl, context->doc);
TtaSetTextContent (elText, content, context->language, context->doc);
TtaSetAccessRight (elText, ReadOnly, context->doc);
}
}
/*----------------------------------------------------------------------
SetFontfamily
-----------------------------------------------------------------------*/
void SetFontfamily (Document doc, Element el, char *value)
{
#define buflen 50
char css_command[buflen+20];
sprintf (css_command, "font-family: %s", value);
ParseHTMLSpecificStyle (el, css_command, doc, 0, FALSE);
}
/*----------------------------------------------------------------------
MathMLlinethickness
The MathML attribute linthickness is associated with element el. Generate
the corresponding style property for this element.
-----------------------------------------------------------------------*/
void MathMLlinethickness (Document doc, Element el, char *value)
{
#define buflen 50
char css_command[buflen+20];
if (strcmp (value, "thin") == 0)
strcpy (value, "1pt");
else if (strcmp (value, "medium") == 0)
strcpy (value, "1pt");
else if (strcmp (value, "thick") == 0)
strcpy (value, "2pt");
sprintf (css_command, "stroke-width: %s", value);
ParseHTMLSpecificStyle (el, css_command, doc, 0, FALSE);
}
/*----------------------------------------------------------------------
MathMLAttrToStyleProperty
The MathML attribute attr is associated with element el. Generate
the corresponding style property for this element.
-----------------------------------------------------------------------*/
void MathMLAttrToStyleProperty (Document doc, Element el, char *value,
int attr)
{
char css_command[buflen+20];
int i;
switch (attr)
{
case MathML_ATTR_fontsize:
sprintf (css_command, "font-size: %s", value);
break;
case MathML_ATTR_mathsize:
if (strcmp (value, "small") == 0)
strcpy (value, "80%");
else if (strcmp (value, "normal") == 0)
strcpy (value, "100%");
else if (strcmp (value, "big") == 0)
strcpy (value, "125%");
sprintf (css_command, "font-size: %s", value);
break;
case MathML_ATTR_lspace:
case MathML_ATTR_rspace:
if (attr == MathML_ATTR_lspace)
strcpy (css_command, "padding-left: ");
else
strcpy (css_command, "padding-right: ");
/* is the value a named space? */
if (strcmp (value, "veryverythinmathspace") == 0)
strcat (css_command, "0.0555556em");
else if (strcmp (value, "verythinmathspace") == 0)
strcat (css_command, "0.111111em");
else if (strcmp (value, "thinmathspace") == 0)
strcat (css_command, "0.166667em");
else if (strcmp (value, "mediummathspace") == 0)
strcat (css_command, "0.222222em");
else if (strcmp (value, "thickmathspace") == 0)
strcat (css_command, "0.277778em");
else if (strcmp (value, "verythickmathspace") == 0)
strcat (css_command, "0.333333em");
else if (strcmp (value, "veryverythickmathspace") == 0)
strcat (css_command, "0.388889em");
else
{
strcat (css_command, value);
/* does the value contain an unit at the end? */
i = strlen (value) - 1;
if ((value[i] <= '9' && value[i] >= '0') ||
value[i] == '.')
/* it's just a number. Add the (implicit) unit: em */
strcat (css_command, "em");
}
break;
}
ParseHTMLSpecificStyle (el, css_command, doc, 0, FALSE);
}
/*----------------------------------------------------------------------
MathMLSetScriptLevel
A scriptlevel attribute with value value is associated with element el.
Generate the corresponding style property for this element.
-----------------------------------------------------------------------*/
void MathMLSetScriptLevel (Document doc, Element el, char *value)
{
PresentationValue pval;
PresentationContext ctxt;
ThotBool relative;
int percentage;
ctxt = TtaGetSpecificStyleContext (doc);
if (!value)
/* remove the presentation rule */
{
ctxt->destroy = TRUE;
pval.typed_data.value = 0;
TtaSetStylePresentation (PRSize, el, NULL, ctxt, pval);
}
else
{
ctxt->destroy = FALSE;
/* parse the attribute value (an optional sign and an integer) */
value = TtaSkipBlanks (value);
relative = (value[0] == '-' || value[0] == '+');
value = ParseCSSUnit (value, &pval);
if (pval.typed_data.unit != STYLE_UNIT_REL &&
pval.typed_data.real)
/* this is an error: it should be an integer without any unit name */
/* error */;
else
{
if (relative)
{
percentage = 100;
if (pval.typed_data.value == 0)
/* scriptlevel="+0" */
percentage = 100;
else if (pval.typed_data.value == 1)
/* scriptlevel="+1" */
percentage = 71;
else if (pval.typed_data.value == 2)
/* scriptlevel="+2" */
percentage = 50;
else if (pval.typed_data.value >= 3)
/* scriptlevel="+3" or more */
percentage = 35;
else if (pval.typed_data.value == -1)
/* scriptlevel="-1" */
percentage = 141;
else if (pval.typed_data.value == -2)
/* scriptlevel="-2" */
percentage = 200;
else if (pval.typed_data.value <= -3)
/* scriptlevel="-3" or less */
percentage = 282;
pval.typed_data.value = percentage;
pval.typed_data.unit = STYLE_UNIT_PERCENT;
/* the specific presentation to be created is not a CSS rule */
ctxt->cssSpecificity = 0;
TtaSetStylePresentation (PRSize, el, NULL, ctxt, pval);
}
else
/* absolute value */
{
/**** ****/;
}
}
}
TtaFreeMemory (ctxt);
}
/*----------------------------------------------------------------------
MathMLSpacingAttr
The MathML attribute attr (height, width or depth) is associated
with element el (a mspace or mpadding).
If value is not NULL, generate the corresponding Thot presentation rule for
the element.
If value is NULL, remove the corresponding Thot presentation rule.
-----------------------------------------------------------------------*/
void MathMLSpacingAttr (Document doc, Element el, char *value, int attr)
{
ElementType elType;
PresentationValue pval;
PresentationContext ctxt;
int ruleType;
/* provisionally, handles only mspace elements */
elType = TtaGetElementType (el);
if (elType.ElTypeNum != MathML_EL_MSPACE &&
elType.ElTypeNum != MathML_EL_MPADDED &&
elType.ElTypeNum != MathML_EL_MTABLE)
return;
switch (attr)
{
case MathML_ATTR_width_:
ruleType = PRWidth;
break;
case MathML_ATTR_height_:
ruleType = PRPaddingTop;
break;
case MathML_ATTR_depth_:
ruleType = PRPaddingBottom;
break;
default:
return;
}
ctxt = TtaGetSpecificStyleContext (doc);
if (!value || (strcmp (value, "auto") == 0))
/* remove the presentation rule */
{
ctxt->destroy = TRUE;
pval.typed_data.value = 0;
TtaSetStylePresentation (ruleType, el, NULL, ctxt, pval);
}
else
{
ctxt->destroy = FALSE;
/* parse the attribute value (a number followed by a unit) */
value = TtaSkipBlanks (value);
value = ParseCSSUnit (value, &pval);
/***** we should accept namedspace for width *****/
if (pval.typed_data.unit != STYLE_UNIT_INVALID)
{
/* the specific presentation to be created is not a CSS rule */
ctxt->cssSpecificity = 0;
TtaSetStylePresentation (ruleType, el, NULL, ctxt, pval);
}
}
TtaFreeMemory (ctxt);
}
/*----------------------------------------------------------------------
MathMLSetDisplayAttr
The MathML attribute display is associated with element el.
Generate the corresponding Thot presentation rule for
the element.
----------------------------------------------------------------------*/
void MathMLSetDisplayAttr (Element el, Attribute attr, Document doc,
ThotBool delete)
{
int val;
val = TtaGetAttributeValue (attr);
if (val == MathML_ATTR_display_VAL_block)
ParseHTMLSpecificStyle (el, "display: block", doc, 0, delete);
else if (val == MathML_ATTR_display_VAL_inline_)
ParseHTMLSpecificStyle (el, "display: inline", doc, 0, delete);
}
/*----------------------------------------------------------------------
MathMLAttributeComplete
The XML parser has completed parsing attribute attr (as well as its value)
that is associated with element el in document doc.
----------------------------------------------------------------------*/
void MathMLAttributeComplete (Attribute attr, Element el, Document doc)
{
AttributeType attrType, depAttrType;
int attrKind;
ElementType elType;
char *value;
int val, length;
Attribute intAttr;
/* first get the type of that attribute */
TtaGiveAttributeType (attr, &attrType, &attrKind);
if (attrType.AttrTypeNum == MathML_ATTR_bevelled)
/* it's a bevelled attribute */
{
val = TtaGetAttributeValue (attr);
if (val == MathML_ATTR_bevelled_VAL_true)
/* bevelled = true. Transform MFRAC into BevelledMFRAC */
{
elType = TtaGetElementType (el);
if (elType.ElTypeNum == MathML_EL_MFRAC)
ChangeTypeOfElement (el, doc, MathML_EL_BevelledMFRAC);
}
}
else if (attrType.AttrTypeNum == MathML_ATTR_rowalign_mtr)
{
/* create an equivalent IntRowAlign attribute on the same element */
attrType.AttrTypeNum = MathML_ATTR_IntRowAlign;
intAttr = TtaGetAttribute (el, attrType);
if (!intAttr)
/* no IntRowAlign attribute, create one */
{
intAttr = TtaNewAttribute (attrType);
TtaAttachAttribute (el, intAttr, doc);
}
val = TtaGetAttributeValue (attr);
TtaSetAttributeValue (intAttr, val, el, doc);
}
else if (attrType.AttrTypeNum == MathML_ATTR_columnalign_mtd)
{
/* create an equivalent IntColAlign attribute on the same element */
attrType.AttrTypeNum = MathML_ATTR_IntColAlign;
intAttr = TtaGetAttribute (el, attrType);
if (!intAttr)
/* no IntColAlign attribute, create one */
{
intAttr = TtaNewAttribute (attrType);
TtaAttachAttribute (el, intAttr, doc);
}
val = TtaGetAttributeValue (attr);
TtaSetAttributeValue (intAttr, val, el, doc);
}
/* don't handle attributes columnalign, rowalign, columnlines and rowlines
now: the table or the row is not complete yet. Handle them when the
element is complete.
*/
else if (attrType.AttrTypeNum == MathML_ATTR_display)
/* it's a display attribute */
MathMLSetDisplayAttr (el, attr, doc, FALSE);
else if (attrType.AttrTypeNum == MathML_ATTR_Language)
{
if (el == TtaGetRootElement (doc))
/* it's the lang attribute on the root element */
/* set the RealLang attribute */
{
depAttrType.AttrSSchema = attrType.AttrSSchema ;
depAttrType.AttrTypeNum = MathML_ATTR_RealLang;
if (!TtaGetAttribute (el, depAttrType))
/* it's not present. Add it */
{
intAttr = TtaNewAttribute (depAttrType);
TtaAttachAttribute (el, intAttr, doc);
TtaSetAttributeValue (intAttr, MathML_ATTR_RealLang_VAL_Yes_,
el, doc);
}
}
}
else if (attrType.AttrTypeNum == MathML_ATTR_color ||
attrType.AttrTypeNum == MathML_ATTR_mathcolor ||
attrType.AttrTypeNum == MathML_ATTR_background_ ||
attrType.AttrTypeNum == MathML_ATTR_mathbackground ||
attrType.AttrTypeNum == MathML_ATTR_fontsize ||
attrType.AttrTypeNum == MathML_ATTR_mathsize ||
attrType.AttrTypeNum == MathML_ATTR_fontfamily ||
attrType.AttrTypeNum == MathML_ATTR_linethickness ||
attrType.AttrTypeNum == MathML_ATTR_lspace ||
attrType.AttrTypeNum == MathML_ATTR_rspace ||
attrType.AttrTypeNum == MathML_ATTR_scriptlevel ||
attrType.AttrTypeNum == MathML_ATTR_width_ ||
attrType.AttrTypeNum == MathML_ATTR_height_ ||
attrType.AttrTypeNum == MathML_ATTR_depth_ )
{
length = TtaGetTextAttributeLength (attr);
if (length >= buflen)
length = buflen - 1;
if (length > 0)
{
value = TtaGetMemory (buflen);
value[0] = EOS;
TtaGiveTextAttributeValue (attr, value, &length);
switch (attrType.AttrTypeNum)
{
case MathML_ATTR_color:
/* deprecated attribute */
/* if the same element has a mathcolor attribute, ignore
the color attribute */
depAttrType.AttrSSchema = attrType.AttrSSchema ;
depAttrType.AttrTypeNum = MathML_ATTR_mathcolor;
if (!TtaGetAttribute (el, depAttrType))
HTMLSetForegroundColor (doc, el, value);
break;
case MathML_ATTR_mathcolor:
HTMLSetForegroundColor (doc, el, value);
break;
case MathML_ATTR_background_:
/* deprecated attribute */
/* if the same element has a mathbackground attribute, ignore
the background attribute */
depAttrType.AttrSSchema = attrType.AttrSSchema;
depAttrType.AttrTypeNum = MathML_ATTR_mathbackground;
if (!TtaGetAttribute (el, depAttrType))
HTMLSetBackgroundColor (doc, el, value);
break;
case MathML_ATTR_mathbackground:
HTMLSetBackgroundColor (doc, el, value);
break;
case MathML_ATTR_fontfamily:
SetFontfamily (doc, el, value);
break;
case MathML_ATTR_linethickness:
MathMLlinethickness (doc, el, value);
break;
case MathML_ATTR_fontsize:
/* deprecated attribute */
/* if the same element has a mathsize attribute, ignore
the fontsize attribute */
depAttrType.AttrSSchema = attrType.AttrSSchema;
depAttrType.AttrTypeNum = MathML_ATTR_mathsize;
if (!TtaGetAttribute (el, depAttrType))
MathMLAttrToStyleProperty (doc, el, value,
attrType.AttrTypeNum);
break;
case MathML_ATTR_mathsize:
case MathML_ATTR_lspace:
case MathML_ATTR_rspace:
MathMLAttrToStyleProperty (doc, el, value,attrType.AttrTypeNum);
break;
case MathML_ATTR_scriptlevel:
MathMLSetScriptLevel (doc, el, value);
break;
case MathML_ATTR_width_:
case MathML_ATTR_height_:
case MathML_ATTR_depth_:
MathMLSpacingAttr (doc, el, value, attrType.AttrTypeNum);
break;
default:
break;
}
TtaFreeMemory (value);
}
}
}
/*----------------------------------------------------------------------
MathMLGetDTDName
----------------------------------------------------------------------*/
void MathMLGetDTDName (char *DTDname, char *elementName)
{
/* no other DTD allowed within MathML elements */
strcpy (DTDname, "");
}
/* end of module */
Webmaster