| 'use strict'; |
| |
| const Tokenizer = require('../tokenizer'); |
| const HTML = require('./html'); |
| |
| //Aliases |
| const $ = HTML.TAG_NAMES; |
| const NS = HTML.NAMESPACES; |
| const ATTRS = HTML.ATTRS; |
| |
| //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 = { |
| attributename: 'attributeName', |
| attributetype: 'attributeType', |
| basefrequency: 'baseFrequency', |
| baseprofile: 'baseProfile', |
| calcmode: 'calcMode', |
| clippathunits: 'clipPathUnits', |
| diffuseconstant: 'diffuseConstant', |
| edgemode: 'edgeMode', |
| filterunits: 'filterUnits', |
| glyphref: 'glyphRef', |
| gradienttransform: 'gradientTransform', |
| gradientunits: 'gradientUnits', |
| kernelmatrix: 'kernelMatrix', |
| kernelunitlength: 'kernelUnitLength', |
| keypoints: 'keyPoints', |
| keysplines: 'keySplines', |
| keytimes: 'keyTimes', |
| lengthadjust: 'lengthAdjust', |
| limitingconeangle: 'limitingConeAngle', |
| markerheight: 'markerHeight', |
| markerunits: 'markerUnits', |
| markerwidth: 'markerWidth', |
| maskcontentunits: 'maskContentUnits', |
| maskunits: 'maskUnits', |
| numoctaves: 'numOctaves', |
| pathlength: 'pathLength', |
| patterncontentunits: 'patternContentUnits', |
| patterntransform: 'patternTransform', |
| patternunits: 'patternUnits', |
| pointsatx: 'pointsAtX', |
| pointsaty: 'pointsAtY', |
| pointsatz: 'pointsAtZ', |
| preservealpha: 'preserveAlpha', |
| preserveaspectratio: 'preserveAspectRatio', |
| primitiveunits: 'primitiveUnits', |
| refx: 'refX', |
| refy: 'refY', |
| repeatcount: 'repeatCount', |
| repeatdur: 'repeatDur', |
| requiredextensions: 'requiredExtensions', |
| requiredfeatures: 'requiredFeatures', |
| specularconstant: 'specularConstant', |
| specularexponent: 'specularExponent', |
| spreadmethod: 'spreadMethod', |
| startoffset: 'startOffset', |
| stddeviation: 'stdDeviation', |
| stitchtiles: 'stitchTiles', |
| surfacescale: 'surfaceScale', |
| systemlanguage: 'systemLanguage', |
| tablevalues: 'tableValues', |
| targetx: 'targetX', |
| targety: 'targetY', |
| textlength: 'textLength', |
| viewbox: 'viewBox', |
| viewtarget: 'viewTarget', |
| xchannelselector: 'xChannelSelector', |
| ychannelselector: 'yChannelSelector', |
| zoomandpan: 'zoomAndPan' |
| }; |
| |
| const XML_ATTRS_ADJUSTMENT_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:base': { prefix: 'xml', name: 'base', namespace: NS.XML }, |
| '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 |
| const SVG_TAG_NAMES_ADJUSTMENT_MAP = (exports.SVG_TAG_NAMES_ADJUSTMENT_MAP = { |
| altglyph: 'altGlyph', |
| altglyphdef: 'altGlyphDef', |
| altglyphitem: 'altGlyphItem', |
| animatecolor: 'animateColor', |
| animatemotion: 'animateMotion', |
| animatetransform: 'animateTransform', |
| clippath: 'clipPath', |
| feblend: 'feBlend', |
| fecolormatrix: 'feColorMatrix', |
| fecomponenttransfer: 'feComponentTransfer', |
| fecomposite: 'feComposite', |
| feconvolvematrix: 'feConvolveMatrix', |
| fediffuselighting: 'feDiffuseLighting', |
| fedisplacementmap: 'feDisplacementMap', |
| fedistantlight: 'feDistantLight', |
| feflood: 'feFlood', |
| fefunca: 'feFuncA', |
| fefuncb: 'feFuncB', |
| fefuncg: 'feFuncG', |
| fefuncr: 'feFuncR', |
| fegaussianblur: 'feGaussianBlur', |
| feimage: 'feImage', |
| femerge: 'feMerge', |
| femergenode: 'feMergeNode', |
| femorphology: 'feMorphology', |
| feoffset: 'feOffset', |
| fepointlight: 'fePointLight', |
| fespecularlighting: 'feSpecularLighting', |
| fespotlight: 'feSpotLight', |
| fetile: 'feTile', |
| feturbulence: 'feTurbulence', |
| foreignobject: 'foreignObject', |
| glyphref: 'glyphRef', |
| lineargradient: 'linearGradient', |
| radialgradient: 'radialGradient', |
| textpath: 'textPath' |
| }); |
| |
| //Tags that causes exit from foreign content |
| const EXITS_FOREIGN_CONTENT = { |
| [$.B]: true, |
| [$.BIG]: true, |
| [$.BLOCKQUOTE]: true, |
| [$.BODY]: true, |
| [$.BR]: true, |
| [$.CENTER]: true, |
| [$.CODE]: true, |
| [$.DD]: true, |
| [$.DIV]: true, |
| [$.DL]: true, |
| [$.DT]: true, |
| [$.EM]: true, |
| [$.EMBED]: true, |
| [$.H1]: true, |
| [$.H2]: true, |
| [$.H3]: true, |
| [$.H4]: true, |
| [$.H5]: true, |
| [$.H6]: true, |
| [$.HEAD]: true, |
| [$.HR]: true, |
| [$.I]: true, |
| [$.IMG]: true, |
| [$.LI]: true, |
| [$.LISTING]: true, |
| [$.MENU]: true, |
| [$.META]: true, |
| [$.NOBR]: true, |
| [$.OL]: true, |
| [$.P]: true, |
| [$.PRE]: true, |
| [$.RUBY]: true, |
| [$.S]: true, |
| [$.SMALL]: true, |
| [$.SPAN]: true, |
| [$.STRONG]: true, |
| [$.STRIKE]: true, |
| [$.SUB]: true, |
| [$.SUP]: true, |
| [$.TABLE]: true, |
| [$.TT]: true, |
| [$.U]: true, |
| [$.UL]: true, |
| [$.VAR]: true |
| }; |
| |
| //Check exit from foreign content |
| exports.causesExit = function(startTagToken) { |
| const tn = startTagToken.tagName; |
| const isFontWithAttrs = |
| tn === $.FONT && |
| (Tokenizer.getTokenAttr(startTagToken, ATTRS.COLOR) !== null || |
| Tokenizer.getTokenAttr(startTagToken, ATTRS.SIZE) !== null || |
| Tokenizer.getTokenAttr(startTagToken, ATTRS.FACE) !== null); |
| |
| return isFontWithAttrs ? true : EXITS_FOREIGN_CONTENT[tn]; |
| }; |
| |
| //Token adjustments |
| exports.adjustTokenMathMLAttrs = function(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; |
| } |
| } |
| }; |
| |
| exports.adjustTokenSVGAttrs = function(token) { |
| for (let i = 0; i < token.attrs.length; i++) { |
| const adjustedAttrName = SVG_ATTRS_ADJUSTMENT_MAP[token.attrs[i].name]; |
| |
| if (adjustedAttrName) { |
| token.attrs[i].name = adjustedAttrName; |
| } |
| } |
| }; |
| |
| exports.adjustTokenXMLAttrs = function(token) { |
| for (let i = 0; i < token.attrs.length; i++) { |
| const adjustedAttrEntry = XML_ATTRS_ADJUSTMENT_MAP[token.attrs[i].name]; |
| |
| if (adjustedAttrEntry) { |
| token.attrs[i].prefix = adjustedAttrEntry.prefix; |
| token.attrs[i].name = adjustedAttrEntry.name; |
| token.attrs[i].namespace = adjustedAttrEntry.namespace; |
| } |
| } |
| }; |
| |
| exports.adjustTokenSVGTagName = function(token) { |
| const adjustedTagName = SVG_TAG_NAMES_ADJUSTMENT_MAP[token.tagName]; |
| |
| if (adjustedTagName) { |
| token.tagName = adjustedTagName; |
| } |
| }; |
| |
| //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); |
| } |
| |
| exports.isIntegrationPoint = function(tn, ns, attrs, foreignNS) { |
| if ((!foreignNS || foreignNS === NS.HTML) && isHtmlIntegrationPoint(tn, ns, attrs)) { |
| return true; |
| } |
| |
| if ((!foreignNS || foreignNS === NS.MATHML) && isMathMLTextIntegrationPoint(tn, ns)) { |
| return true; |
| } |
| |
| return false; |
| }; |