| import { TAG_ID as $, NS, ATTRS, getTagID } from './html.js'; |
| //MIME types |
| const MIME_TYPES = { |
| TEXT_HTML: 'text/html', |
| APPLICATION_XML: 'application/xhtml+xml', |
| }; |
| //Attributes |
| const DEFINITION_URL_ATTR = 'definitionurl'; |
| const ADJUSTED_DEFINITION_URL_ATTR = 'definitionURL'; |
| const SVG_ATTRS_ADJUSTMENT_MAP = new Map([ |
| 'attributeName', |
| 'attributeType', |
| 'baseFrequency', |
| 'baseProfile', |
| 'calcMode', |
| 'clipPathUnits', |
| 'diffuseConstant', |
| 'edgeMode', |
| 'filterUnits', |
| 'glyphRef', |
| 'gradientTransform', |
| 'gradientUnits', |
| 'kernelMatrix', |
| 'kernelUnitLength', |
| 'keyPoints', |
| 'keySplines', |
| 'keyTimes', |
| 'lengthAdjust', |
| 'limitingConeAngle', |
| 'markerHeight', |
| 'markerUnits', |
| 'markerWidth', |
| 'maskContentUnits', |
| 'maskUnits', |
| 'numOctaves', |
| 'pathLength', |
| 'patternContentUnits', |
| 'patternTransform', |
| 'patternUnits', |
| 'pointsAtX', |
| 'pointsAtY', |
| 'pointsAtZ', |
| 'preserveAlpha', |
| 'preserveAspectRatio', |
| 'primitiveUnits', |
| 'refX', |
| 'refY', |
| 'repeatCount', |
| 'repeatDur', |
| 'requiredExtensions', |
| 'requiredFeatures', |
| 'specularConstant', |
| 'specularExponent', |
| 'spreadMethod', |
| 'startOffset', |
| 'stdDeviation', |
| 'stitchTiles', |
| 'surfaceScale', |
| 'systemLanguage', |
| 'tableValues', |
| 'targetX', |
| 'targetY', |
| 'textLength', |
| 'viewBox', |
| 'viewTarget', |
| 'xChannelSelector', |
| 'yChannelSelector', |
| 'zoomAndPan', |
| ].map((attr) => [attr.toLowerCase(), attr])); |
| const XML_ATTRS_ADJUSTMENT_MAP = new Map([ |
| ['xlink:actuate', { prefix: 'xlink', name: 'actuate', namespace: NS.XLINK }], |
| ['xlink:arcrole', { prefix: 'xlink', name: 'arcrole', namespace: NS.XLINK }], |
| ['xlink:href', { prefix: 'xlink', name: 'href', namespace: NS.XLINK }], |
| ['xlink:role', { prefix: 'xlink', name: 'role', namespace: NS.XLINK }], |
| ['xlink:show', { prefix: 'xlink', name: 'show', namespace: NS.XLINK }], |
| ['xlink:title', { prefix: 'xlink', name: 'title', namespace: NS.XLINK }], |
| ['xlink:type', { prefix: 'xlink', name: 'type', namespace: NS.XLINK }], |
| ['xml:lang', { prefix: 'xml', name: 'lang', namespace: NS.XML }], |
| ['xml:space', { prefix: 'xml', name: 'space', namespace: NS.XML }], |
| ['xmlns', { prefix: '', name: 'xmlns', namespace: NS.XMLNS }], |
| ['xmlns:xlink', { prefix: 'xmlns', name: 'xlink', namespace: NS.XMLNS }], |
| ]); |
| //SVG tag names adjustment map |
| export const SVG_TAG_NAMES_ADJUSTMENT_MAP = new Map([ |
| 'altGlyph', |
| 'altGlyphDef', |
| 'altGlyphItem', |
| 'animateColor', |
| 'animateMotion', |
| 'animateTransform', |
| 'clipPath', |
| 'feBlend', |
| 'feColorMatrix', |
| 'feComponentTransfer', |
| 'feComposite', |
| 'feConvolveMatrix', |
| 'feDiffuseLighting', |
| 'feDisplacementMap', |
| 'feDistantLight', |
| 'feFlood', |
| 'feFuncA', |
| 'feFuncB', |
| 'feFuncG', |
| 'feFuncR', |
| 'feGaussianBlur', |
| 'feImage', |
| 'feMerge', |
| 'feMergeNode', |
| 'feMorphology', |
| 'feOffset', |
| 'fePointLight', |
| 'feSpecularLighting', |
| 'feSpotLight', |
| 'feTile', |
| 'feTurbulence', |
| 'foreignObject', |
| 'glyphRef', |
| 'linearGradient', |
| 'radialGradient', |
| 'textPath', |
| ].map((tn) => [tn.toLowerCase(), tn])); |
| //Tags that causes exit from foreign content |
| const EXITS_FOREIGN_CONTENT = new Set([ |
| $.B, |
| $.BIG, |
| $.BLOCKQUOTE, |
| $.BODY, |
| $.BR, |
| $.CENTER, |
| $.CODE, |
| $.DD, |
| $.DIV, |
| $.DL, |
| $.DT, |
| $.EM, |
| $.EMBED, |
| $.H1, |
| $.H2, |
| $.H3, |
| $.H4, |
| $.H5, |
| $.H6, |
| $.HEAD, |
| $.HR, |
| $.I, |
| $.IMG, |
| $.LI, |
| $.LISTING, |
| $.MENU, |
| $.META, |
| $.NOBR, |
| $.OL, |
| $.P, |
| $.PRE, |
| $.RUBY, |
| $.S, |
| $.SMALL, |
| $.SPAN, |
| $.STRONG, |
| $.STRIKE, |
| $.SUB, |
| $.SUP, |
| $.TABLE, |
| $.TT, |
| $.U, |
| $.UL, |
| $.VAR, |
| ]); |
| //Check exit from foreign content |
| export function causesExit(startTagToken) { |
| const tn = startTagToken.tagID; |
| const isFontWithAttrs = tn === $.FONT && |
| startTagToken.attrs.some(({ name }) => name === ATTRS.COLOR || name === ATTRS.SIZE || name === ATTRS.FACE); |
| return isFontWithAttrs || EXITS_FOREIGN_CONTENT.has(tn); |
| } |
| //Token adjustments |
| export function adjustTokenMathMLAttrs(token) { |
| for (let i = 0; i < token.attrs.length; i++) { |
| if (token.attrs[i].name === DEFINITION_URL_ATTR) { |
| token.attrs[i].name = ADJUSTED_DEFINITION_URL_ATTR; |
| break; |
| } |
| } |
| } |
| export function adjustTokenSVGAttrs(token) { |
| for (let i = 0; i < token.attrs.length; i++) { |
| const adjustedAttrName = SVG_ATTRS_ADJUSTMENT_MAP.get(token.attrs[i].name); |
| if (adjustedAttrName != null) { |
| token.attrs[i].name = adjustedAttrName; |
| } |
| } |
| } |
| export function adjustTokenXMLAttrs(token) { |
| for (let i = 0; i < token.attrs.length; i++) { |
| const adjustedAttrEntry = XML_ATTRS_ADJUSTMENT_MAP.get(token.attrs[i].name); |
| if (adjustedAttrEntry) { |
| token.attrs[i].prefix = adjustedAttrEntry.prefix; |
| token.attrs[i].name = adjustedAttrEntry.name; |
| token.attrs[i].namespace = adjustedAttrEntry.namespace; |
| } |
| } |
| } |
| export function adjustTokenSVGTagName(token) { |
| const adjustedTagName = SVG_TAG_NAMES_ADJUSTMENT_MAP.get(token.tagName); |
| if (adjustedTagName != null) { |
| token.tagName = adjustedTagName; |
| token.tagID = getTagID(token.tagName); |
| } |
| } |
| //Integration points |
| function isMathMLTextIntegrationPoint(tn, ns) { |
| return ns === NS.MATHML && (tn === $.MI || tn === $.MO || tn === $.MN || tn === $.MS || tn === $.MTEXT); |
| } |
| function isHtmlIntegrationPoint(tn, ns, attrs) { |
| if (ns === NS.MATHML && tn === $.ANNOTATION_XML) { |
| for (let i = 0; i < attrs.length; i++) { |
| if (attrs[i].name === ATTRS.ENCODING) { |
| const value = attrs[i].value.toLowerCase(); |
| return value === MIME_TYPES.TEXT_HTML || value === MIME_TYPES.APPLICATION_XML; |
| } |
| } |
| } |
| return ns === NS.SVG && (tn === $.FOREIGN_OBJECT || tn === $.DESC || tn === $.TITLE); |
| } |
| export function isIntegrationPoint(tn, ns, attrs, foreignNS) { |
| return (((!foreignNS || foreignNS === NS.HTML) && isHtmlIntegrationPoint(tn, ns, attrs)) || |
| ((!foreignNS || foreignNS === NS.MATHML) && isMathMLTextIntegrationPoint(tn, ns))); |
| } |