'use strict'; const defaultValue = require("default-value"); const parser = require("../parser"); const findAlignment = require("../parser/find-alignment"); const generateStyle = require("../parser/generate-style"); const measureText = require("../render/measure-text"); const layoutItems = require("./layout-items"); const drawDebugLine = require("./draw-debug-line"); const sum = require("../util/sum"); const min = require("../util/min"); const max = require("../util/max"); const last = require("../util/last"); module.exports = function layoutFormattedText(text, options) { let lines; if (options.tags === true) { lines = parser(text).map((lineItems) => { return { items: lineItems }; }); } else { lines = text.split("\n").map((line) => { let lineMeasurements = measureText(line, options.defaultStyle); return { items: [{ text: line }] }; }); } let processedLines = lines.map((line) => { let processedItems = line.items.map((item) => { let style; if (item.tags != null) { style = Object.assign({}, options.defaultStyle, generateStyle(item.tags, options.classes)); } else { style = options.defaultStyle; } return Object.assign(item, { style: style, measurements: measureText(item.text, style) }); }); let height = max(processedItems.map(item => item.measurements.height)); return Object.assign(line, { alignment: defaultValue((line.items.length > 0) ? findAlignment(line.items[0]) : null, options.defaultStyle.alignment), items: processedItems, height: height, adjustedHeight: height * options.lineHeight * 1.13, width: sum(processedItems.map(item => item.measurements.width)), minAscender: min(processedItems.map(item => item.measurements.ascender)), maxDescender: max(processedItems.map(item => item.measurements.descender)) }); }); let startHeightCorrection, endHeightCorrection; if (options.trimVerticalWhitespace) { startHeightCorrection = -(lines[0].adjustedHeight / 2) - (lines[0].minAscender / 2); endHeightCorrection = -(last(lines).adjustedHeight / 2) - (last(lines).minAscender / 2); } else { startHeightCorrection = 0; endHeightCorrection = 0; } let totalTextWidth = Math.ceil(max(lines.map(line => line.width))); let {positionedItems, debugLines} = layoutItems(lines, { initialY: startHeightCorrection, totalTextWidth: totalTextWidth }); let combinedLineHeights = sum(lines.map(line => line.adjustedHeight)); return { width: totalTextWidth, height: Math.ceil(combinedLineHeights + startHeightCorrection + endHeightCorrection + last(lines).maxDescender), items: positionedItems, drawDebugLines: function drawDebugLines(context) { debugLines.forEach((debugLine) => { let width; if (debugLine.x1 != null) { width = [debugLine.x1, debugLine.x2]; } else { width = this.width; } drawDebugLine(context, debugLine.lineNumber, debugLine.y, width, debugLine.color); }); } } };