UNPKG

nehan

Version:

Html layout engine for paged-media written in Typescript

202 lines 7.33 kB
import { Utils, BasicStyle, Config, CssCascade, Lexer, } from "./public-api"; ; export var FontSizeKeyword; (function (FontSizeKeyword) { FontSizeKeyword["XX_SMALL"] = "xx-small"; FontSizeKeyword["X_SMALL"] = "x-small"; FontSizeKeyword["SMALL"] = "small"; FontSizeKeyword["MEDIUM"] = "medium"; FontSizeKeyword["LARGE"] = "large"; FontSizeKeyword["X_LARGE"] = "x-large"; FontSizeKeyword["XX_LARGE"] = "xx-large"; })(FontSizeKeyword || (FontSizeKeyword = {})); export var FontSizeKeywordRelative; (function (FontSizeKeywordRelative) { FontSizeKeywordRelative["SMALLER"] = "smaller"; FontSizeKeywordRelative["LARGER"] = "larger"; })(FontSizeKeywordRelative || (FontSizeKeywordRelative = {})); export const FontSizeKeywords = Utils.Enum.toValueArray(FontSizeKeyword); export const FontSizeKeywordsRelative = Utils.Enum.toValueArray(FontSizeKeywordRelative); export const FontSizeKeywordSize = { "xx-small": 8, "x-small": 10, "small": 13, "medium": 16, "large": 18, "x-large": 24, "xx-large": 33 }; export const FontSizeKeywordRelativeSize = { "smaller": "0.8em", "larger": "1.2em", }; class FontShorthandLexer extends Lexer { normalize(src) { return src.trim(); } peekQuotedString() { const match = FontShorthandLexer.rexQuotedString.exec(this.buff); if (match) { const token = match[0]; this.stepBuff(token.length); return token; } return ""; } peekUntilSpace() { const spacePos = this.buff.indexOf(" "); if (spacePos < 0) { const token = this.buff; this.stepBuff(this.buff.length); return token; } const token = this.buff.substring(0, spacePos); this.stepBuff(spacePos + 1); return token; } createToken() { return this.peekQuotedString() || this.peekUntilSpace(); } } FontShorthandLexer.rexQuotedString = /^'[^']+'/; class FontShorthandParser { constructor(lexer) { this.lexer = lexer; } parseFontSize(fontSize) { if (fontSize.indexOf("/") < 0) { return fontSize; } return fontSize.split("/")[0].trim(); } parseLineHeight(fontSize) { if (fontSize.indexOf("/") < 0) { return "normal"; } return fontSize.split("/")[1].trim(); } inferOptPropByValue(value, index) { if (/^[1-9]00$/.test(value)) { return "font-weight"; } if (value.indexOf("condensed") >= 0 || value.indexOf("expanded") >= 0) { return "font-stretch"; } const optProps = ["font-style", "font-variant", "font-weight", "font-stretch"]; switch (value) { case "normal": return optProps[index] || "font-style"; case "italic": case "oblique": return "font-style"; case "none": case "small-caps": return "font-variant"; case "bold": case "lighter": case "bolder": return "font-weight"; default: break; } console.error(`invalid optinal value for shorthanded font css:${value}`); return "font-style"; } parse() { const src = this.lexer.src; const tokens = this.lexer.tokens; if (tokens.length < 2) { console.warn(`invalid font shorthand, both font-size and font-family must be specified: ${src}`); return []; } if (tokens.length === 2) { const fontSize = this.parseFontSize(tokens[0]); const fontFamily = tokens[1]; const lineHeight = this.parseLineHeight(tokens[0]); return [ { prop: "font-family", value: fontFamily }, { prop: "font-size", value: fontSize }, { prop: "line-height", value: lineHeight } ]; } if (2 < tokens.length && tokens.length < 6) { const optValues = tokens.slice(0, -2); const fontSize = this.parseFontSize(tokens[tokens.length - 2]); const lineHeight = this.parseLineHeight(tokens[tokens.length - 2]); const fontFamily = tokens[tokens.length - 1]; let propValues = [ { prop: "font-family", value: fontFamily }, { prop: "font-size", value: fontSize }, { prop: "line-height", value: lineHeight } ]; optValues.forEach((value, index) => { const prop = this.inferOptPropByValue(value, index); propValues.push({ prop, value }); }); return propValues; } const fontStyle = tokens[0]; const fontVariant = tokens[1]; const fontWeight = tokens[2]; const fontStretch = tokens[3]; const fontSize = this.parseFontSize(tokens[4]); const lineHeight = this.parseLineHeight(tokens[4]); const fontFamily = tokens[5]; return [ { prop: "font-style", value: fontStyle }, { prop: "font-variant", value: fontVariant }, { prop: "font-weight", value: fontWeight }, { prop: "font-stretch", value: fontStretch }, { prop: "font-family", value: fontFamily }, { prop: "font-size", value: fontSize }, { prop: "line-height", value: lineHeight } ]; } } export class Font { constructor() { this.style = BasicStyle.getInitialValue("font-style"); this.variant = BasicStyle.getInitialValue("font-variant"); this.weight = BasicStyle.getInitialValue("font-weight"); this.stretch = BasicStyle.getInitialValue("font-stretch"); this.size = Config.defaultFontSize; this.lineHeight = String(Config.defaultLineHeight); this.family = Config.defaultFontFamily; } get css() { return [ this.style, this.variant, this.weight, this.stretch, [this.size + "px", this.lineHeight].join("/"), this.family ].join(" "); } get lineExtent() { if (this.lineHeight.indexOf("px") >= 0) { return Utils.atoi(this.lineHeight); } return Math.floor(parseFloat(this.lineHeight) * this.size); } static parseShorthand(text) { const lexer = new FontShorthandLexer(text.value); const parser = new FontShorthandParser(lexer); const propValue = parser.parse(); return propValue; } static load(element) { let font = new Font(); font.style = CssCascade.getValue(element, "font-style"); font.variant = CssCascade.getValue(element, "font-variant"); font.weight = CssCascade.getValue(element, "font-weight"); font.stretch = CssCascade.getValue(element, "font-stretch"); font.family = CssCascade.getValue(element, "font-family"); font.size = Utils.atoi(CssCascade.getValue(element, "font-size"), Config.defaultFontSize); font.lineHeight = CssCascade.getValue(element, "line-height"); return font; } acceptCssEvaluator(visitor) { return visitor.visitFont(this); } } //# sourceMappingURL=font.js.map