You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
6.3 KiB
230 lines
6.3 KiB
2 years ago
|
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: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
|
||
|
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)));
|
||
|
}
|
||
|
//# sourceMappingURL=foreign-content.js.map
|