UNPKG

nehan

Version:

Html layout engine for paged-media written in Typescript

329 lines 16 kB
import { Config, LogicalBoxEdge, } from './public-api'; export class HoriLogicalNodeEvaluator { constructor(pageRoot, cssVisitor, textJustifier) { this.pageRoot = pageRoot; this.cssVisitor = cssVisitor; this.textJustifier = textJustifier; } visitChar(char) { return document.createTextNode(char.text); } visitCharEmpha(char, empha) { const node = document.createElement("div"); const emphaNode = document.createElement("div"); const textNode = document.createElement("div"); emphaNode.appendChild(document.createTextNode(empha.text)); textNode.appendChild(document.createTextNode(char.text)); if (empha.scale < 1.0) { emphaNode.style.fontSize = String(empha.scale) + "em"; emphaNode.style.paddingBottom = String(empha.scale / 2) + "em"; } node.style.display = "inline-block"; node.style.textAlign = "center"; node.appendChild(emphaNode); node.appendChild(textNode); return node; } visitRefChar(refChar) { return document.createTextNode(refChar.text); } visitRefCharEmpha(refChar, empha) { return this.visitCharEmpha(refChar, empha); } visitSpaceChar(spaceChar) { const node = document.createElement("span"); node.style.display = "inline-block"; node.style.width = spaceChar.size.measure + "px"; node.appendChild(document.createTextNode(spaceChar.text)); return node; } visitHalfChar(halfChar) { return document.createTextNode(halfChar.text); } visitMixChar(mixChar) { const node = document.createElement("span"); node.style.display = "inline-block"; node.style.width = "1.25em"; node.appendChild(document.createTextNode(mixChar.text)); return node; } visitDualChar(dualChar) { return document.createTextNode(dualChar.text); } visitDualCharKern(dualChar) { const node = document.createElement("span"); node.style.marginLeft = "-0.5em"; node.appendChild(document.createTextNode(dualChar.text)); return node; } visitSmpUniChar(uniChar) { return document.createTextNode(uniChar.text); } visitTcy(tcy) { return document.createTextNode(tcy.text); } visitWord(word) { return document.createTextNode(word.text); } visitText(textNode) { const node = document.createElement("div"); node.className = "nehan-text"; node.style.display = "inline-block"; node.style.lineHeight = "1"; textNode.children.forEach(char => { const charNode = char.acceptEvaluator(this); if (char.spacing) { const spacingWrap = document.createElement("span"); spacingWrap.style.paddingRight = char.spacing + "px"; spacingWrap.appendChild(charNode); node.appendChild(spacingWrap); } else { node.appendChild(charNode); } }); node.normalize(); return node; } visitRuby(rubyNode) { const node = document.createElement("div"); node.className = "nehan-ruby"; const rbNode = document.createElement("div").appendChild(rubyNode.rb.acceptEvaluator(this)); const rtNode = document.createElement("div").appendChild(rubyNode.rt.acceptEvaluator(this)); rbNode.style.display = "block"; rtNode.style.display = "block"; rtNode.style.lineHeight = "1"; node.appendChild(rtNode); node.appendChild(rbNode); node.style.display = "inline-block"; node.style.textAlign = "center"; rubyNode.size.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); rubyNode.env.color.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); rubyNode.env.element.style.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); return node; } visitLine(lineNode) { const node = document.createElement("div"); node.className = "nehan-line"; node.style.boxSizing = "content-box"; node.style.position = "absolute"; node.style.overflow = "visible"; node.style.top = lineNode.linePos.before + "px"; lineNode.env.font.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); lineNode.env.color.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); lineNode.size.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); const baseLineNode = document.createElement("div"); baseLineNode.className = "nehan-baseline"; baseLineNode.style.position = "absolute"; baseLineNode.style.left = (lineNode.linePos.start + lineNode.baseline.startOffset) + "px"; baseLineNode.style.width = lineNode.size.measure + 2 * lineNode.env.font.size + "px"; baseLineNode.style.height = lineNode.baseline.size.extent + "px"; baseLineNode.style.bottom = lineNode.baseline.blockOffset + "px"; if (lineNode.env.textAlign.isJustify()) { this.textJustifier.justify(lineNode); } node.appendChild(baseLineNode); lineNode.children.forEach(child => { baseLineNode.appendChild(child.acceptEvaluator(this)); }); return node; } visitInline(inlineNode) { const node = this.pageRoot.createElement("span", ["inline"], inlineNode); node.style.marginLeft = inlineNode.edge.margin.start + "px"; node.style.marginRight = inlineNode.edge.margin.end + "px"; inlineNode.env.font.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); inlineNode.env.color.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); inlineNode.env.element.style.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); inlineNode.children.forEach(child => { node.appendChild(child.acceptEvaluator(this)); }); return node; } visitInlineEmpha(inlineNode) { const node = this.pageRoot.createElement("span", ["inline", "empha"], inlineNode); node.style.display = "inline-block"; node.style.marginLeft = inlineNode.edge.margin.start + "px"; node.style.marginRight = inlineNode.edge.margin.end + "px"; inlineNode.env.font.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); inlineNode.env.color.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); inlineNode.env.element.style.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); inlineNode.children.forEach(child => { node.appendChild(child.acceptEvaluator(this)); }); return node; } visitInlineBlock(iblockNode) { const node = this.pageRoot.createElement("span", ["iblock"], iblockNode); node.style.display = "inline-block"; node.style.boxSizing = "content-box"; node.style.position = "relative"; node.style.paddingLeft = iblockNode.env.edge.padding.start + "px"; node.style.paddingRight = iblockNode.env.edge.padding.end + "px"; node.style.marginLeft = iblockNode.env.edge.margin.start + "px"; node.style.marginRight = iblockNode.env.edge.margin.end + "px"; iblockNode.size.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); iblockNode.edge.border.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); iblockNode.env.element.style.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); iblockNode.children.forEach(child => { node.appendChild(child.acceptEvaluator(this)); }); return node; } visitBlock(blockNode) { const node = this.pageRoot.createElement("div", ["block"], blockNode); node.style.boxSizing = "content-box"; node.style.position = (blockNode.env.element.tagName === Config.pageRootTagName) ? "relative" : "absolute"; node.style.paddingLeft = blockNode.env.edge.padding.start + "px"; node.style.paddingRight = blockNode.env.edge.padding.end + "px"; if (blockNode.env.position.isAbsolute()) { blockNode.env.absPos.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); } else { blockNode.layoutPos.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); } blockNode.size.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); blockNode.border.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); blockNode.env.element.style.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); blockNode.children.forEach(child => { node.appendChild(child.acceptEvaluator(this)); }); return node; } visitRootBlock(rootBlockNode) { const node = this.pageRoot.createElement("div", ["root"], rootBlockNode); const edge = LogicalBoxEdge.loadBoxEdge(rootBlockNode.env.element); node.className = "nehan-root"; node.style.width = rootBlockNode.measure + edge.measure + "px"; node.style.height = rootBlockNode.extent + edge.extent + "px"; edge.margin.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); edge.border.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); edge.padding.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); rootBlockNode.env.element.style.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); return node; } visitTableCells(tableCellsNode) { const node = this.pageRoot.createElement("div", ["table-cells"], tableCellsNode); node.style.boxSizing = "content-box"; node.style.position = "absolute"; tableCellsNode.rowPos.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); tableCellsNode.size.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); tableCellsNode.children.forEach(child => { node.appendChild(child.acceptEvaluator(this)); }); return node; } visitBlockImage(imgNode) { const node = this.pageRoot.createElement("img", ["block"], imgNode); node.style.position = "absolute"; node.style.width = imgNode.physicalSize.width + "px"; node.style.height = imgNode.physicalSize.height + "px"; node.setAttribute("src", imgNode.env.element.getAttribute("src") || ""); imgNode.edge.border.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); if (imgNode.env.position.isAbsolute()) { imgNode.env.absPos.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); } else { imgNode.layoutPos.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); } imgNode.env.element.style.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); return node; } visitInlineImage(imgNode) { const node = this.pageRoot.createElement("img", ["inline"], imgNode); node.style.display = "inline"; node.style.width = imgNode.physicalSize.width + "px"; node.style.height = imgNode.physicalSize.height + "px"; node.style.marginLeft = imgNode.edge.margin.start + "px"; node.style.marginRight = imgNode.edge.margin.end + "px"; node.style.verticalAlign = "bottom"; node.setAttribute("src", imgNode.env.element.getAttribute("src") || ""); imgNode.edge.border.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); imgNode.env.element.style.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); return node; } visitBlockVideo(videoNode) { const node = videoNode.env.element.$node.cloneNode(true); node.setAttribute("width", String(videoNode.physicalSize.width)); node.setAttribute("height", String(videoNode.physicalSize.height)); node.removeAttribute("style"); node.style.position = "absolute"; node.style.marginLeft = videoNode.edge.margin.start + "px"; node.style.marginRight = videoNode.edge.margin.end + "px"; node.style.verticalAlign = "bottom"; videoNode.layoutPos.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); videoNode.edge.border.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); videoNode.env.element.style.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); return node; } visitInlineVideo(videoNode) { const node = this.pageRoot.createElement("span", ["inline"], videoNode); node.style.display = "none"; node.style.width = "0"; node.style.height = "0"; node.innerHTML = "Sorry, inline video is not supported yet!"; return node; } visitBlockReFixed(reNodeFixed, fixedDOM) { const node = this.pageRoot.createElement("div", ["block"], reNodeFixed); node.style.position = "absolute"; node.style.width = reNodeFixed.physicalSize.width + "px"; node.style.height = reNodeFixed.physicalSize.height + "px"; node.appendChild(fixedDOM); reNodeFixed.edge.border.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); if (reNodeFixed.env.position.isAbsolute()) { reNodeFixed.env.absPos.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); } else { reNodeFixed.layoutPos.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); } reNodeFixed.env.element.style.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); return node; } visitInlineReFixed(reNodeFixed, fixedDOM) { const node = this.pageRoot.createElement("div", ["inline"], reNodeFixed); node.style.display = "inline-block"; node.style.width = reNodeFixed.physicalSize.width + "px"; node.style.height = reNodeFixed.physicalSize.height + "px"; node.style.marginLeft = reNodeFixed.edge.margin.start + "px"; node.style.marginRight = reNodeFixed.edge.margin.end + "px"; node.appendChild(fixedDOM); reNodeFixed.edge.border.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); reNodeFixed.env.element.style.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); return node; } visitInlineLink(linkNode) { const node = this.pageRoot.createElement("a", ["inline"], linkNode); node.style.marginLeft = linkNode.edge.margin.start + "px"; node.style.marginRight = linkNode.edge.margin.end + "px"; linkNode.env.font.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); linkNode.env.color.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); linkNode.env.element.style.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); linkNode.children.forEach(child => { node.appendChild(child.acceptEvaluator(this)); }); return node; } visitBlockLink(linkNode) { const node = this.pageRoot.createElement("a", ["block"], linkNode); node.style.boxSizing = "content-box"; node.style.position = "absolute"; node.style.paddingLeft = linkNode.env.edge.padding.start + "px"; node.style.paddingRight = linkNode.env.edge.padding.end + "px"; if (linkNode.env.position.isAbsolute()) { linkNode.env.absPos.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); } else { linkNode.layoutPos.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); } linkNode.size.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); linkNode.border.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); linkNode.env.element.style.acceptCssEvaluator(this.cssVisitor).applyTo(node.style); linkNode.children.forEach(child => { const childNode = child.acceptEvaluator(this); node.appendChild(childNode); }); return node; } } //# sourceMappingURL=hori-logical-node-evaluator.js.map