/* * (c) Copyright Ascensio System SIA 2010-2015 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, * EU, LV-1021. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ "use strict"; (function (window, undefined) { var asc = window["Asc"]; var asc_calcnpt = asc.calcNearestPt; var asc_debug = asc.outputDebugStr; var asc_typeof = asc.typeOf; var asc_round = asc.round; function LineInfo(tw, th, bl, a, d) { this.tw = tw !== undefined ? tw : 0; this.th = th !== undefined ? th : 0; this.bl = bl !== undefined ? bl : 0; this.a = a !== undefined ? a : 0; this.d = d !== undefined ? d : 0; this.beg = undefined; this.end = undefined; this.startX = undefined; } LineInfo.prototype.assign = function (tw, th, bl, a, d) { if (tw !== undefined) { this.tw = tw; } if (th !== undefined) { this.th = th; } if (bl !== undefined) { this.bl = bl; } if (a !== undefined) { this.a = a; } if (d !== undefined) { this.d = d; } }; function lineMetrics() { this.th = 0; this.bl = 0; this.bl2 = 0; this.a = 0; this.d = 0; } lineMetrics.prototype.clone = function () { var oRes = new lineMetrics(); oRes.th = this.th; oRes.bl = this.bl; oRes.bl2 = this.bl2; oRes.a = this.a; oRes.d = this.d; return oRes; }; function charProperties() { this.c = undefined; this.lm = undefined; this.fm = undefined; this.fsz = undefined; this.font = undefined; this.va = undefined; this.nl = undefined; this.hp = undefined; this.delta = undefined; this.skip = undefined; this.repeat = undefined; this.total = undefined; this.wrd = undefined; } charProperties.prototype.clone = function () { var oRes = new charProperties(); oRes.c = (undefined !== this.c) ? this.c.clone() : undefined; oRes.lm = (undefined !== this.lm) ? this.lm.clone() : undefined; oRes.fm = (undefined !== this.fm) ? this.fm.clone() : undefined; oRes.fsz = (undefined !== this.fsz) ? this.fsz.clone() : undefined; oRes.font = (undefined !== this.font) ? this.font.clone() : undefined; oRes.va = this.va; oRes.nl = this.nl; oRes.hp = this.hp; oRes.delta = this.delta; oRes.skip = this.skip; oRes.repeat = this.repeat; oRes.total = this.total; oRes.wrd = this.wrd; return oRes; }; function StringRender(drawingCtx) { this.drawingCtx = drawingCtx; this.defaultFont = undefined; this.fragments = undefined; this.flags = undefined; this.chars = ""; this.charWidths = []; this.charProps = []; this.lines = []; this.ratio = 1; this.angle = 0; this.fontNeedUpdate = false; this.reNL = /[\r\n]/; this.reTab = /[\t\v\f]/; this.reSpace = /[\n\r\u2028\u2029\t\v\f\u0020\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2008\u2009\u200A\u200B\u205F\u3000]/; this.reReplaceNL = /\r?\n|\r/g; this.reReplaceTab = /[\t\v\f]/g; this.reHypNL = /[\n\r\u2028\u2029]/; this.reHypSp = /[\t\v\f\u0020\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2008\u2009\u200A\u200B\u205F\u3000]/; this.reHyphen = /[\u002D\u00AD\u2010\u2012\u2013\u2014]/; return this; } StringRender.prototype.setDefaultFont = function (font) { this.defaultFont = font; return this; }; StringRender.prototype.setDefaultFontFromFmt = function (fmt) { if (asc_typeof(fmt.fn) !== "string" || !(fmt.fs > 0)) { throw "Can not make font from {fmt.fn=" + fmt.fn + ", fmt.fs=" + fmt.fs + "}"; } this.defaultFont = this._makeFont(fmt); return this; }; StringRender.prototype.setString = function (str, flags) { this.fragments = []; if (asc_typeof(str) === "string") { this.fragments.push({ text: str, format: {} }); } else { for (var i = 0; i < str.length; ++i) { this.fragments.push({ text: str[i].text, format: str[i].format }); } } this.flags = flags; this._reset(); this.drawingCtx.setFont(this.defaultFont, this.angle); return this; }; StringRender.prototype.rotateAtPoint = function (drawingCtx, angle, x, y, dx, dy) { var m = new asc.Matrix(); m.rotate(angle, 0); var mbt = new asc.Matrix(); if (null === drawingCtx) { mbt.translate(x + dx, y + dy); this.drawingCtx.setTextTransform(m.sx, m.shy, m.shx, m.sy, m.tx, m.ty); this.drawingCtx.setTransform(mbt.sx, mbt.shy, mbt.shx, mbt.sy, mbt.tx, mbt.ty); this.drawingCtx.updateTransforms(); } else { mbt.translate((x + dx) * vector_koef, (y + dy) * vector_koef); mbt.multiply(m, 0); drawingCtx.setTransform(mbt.sx, mbt.shy, mbt.shx, mbt.sy, mbt.tx, mbt.ty); } return this; }; StringRender.prototype.resetTransform = function (drawingCtx) { if (null === drawingCtx) { this.drawingCtx.resetTransforms(); } else { var m = new asc.Matrix(); drawingCtx.setTransform(m.sx, m.shy, m.shx, m.sy, m.tx, m.ty); } this.angle = 0; this.fontNeedUpdate = true; }; StringRender.prototype.getTransformBound = function (angle, x, y, w, h, textW, alignHorizontal, alignVertical, maxWidth) { this.angle = 0; this.fontNeedUpdate = true; var dx = 0, dy = 0, sx = 0, sw = 0; var tm = this._doMeasure(maxWidth); var mul = (90 - (Math.abs(angle))) / 90; var posh = (angle === 90 || angle === -90) ? textW : Math.abs(Math.sin(angle * Math.PI / 180) * textW); var posv = (angle === 90 || angle === -90) ? 0 : Math.abs(Math.cos(angle * Math.PI / 180) * textW); if ("bottom" === alignVertical) { if (angle < 0) { if ("left" === alignHorizontal) { dx = (1 - mul) * tm.height; sw = x + posv + (mul * 0.5) * tm.height; } else { if ("center" === alignHorizontal) { dx = (w + tm.height - posv) * 0.5; sx = x + (w - posv) * 0.5 - (mul * 0.5) * tm.height; sw = x + (w + posv) * 0.5 + (mul * 0.5) * tm.height; } else { if ("right" === alignHorizontal) { dx = w - posv; sx = x + dx - (mul * 0.5) * tm.height; } } } } else { if ("left" === alignHorizontal) { sw = x + posv + (mul * 0.5) * tm.height; } else { if ("center" === alignHorizontal) { dx = (w - tm.height - posv) * 0.5; sx = x + (w - posv) * 0.5 - (mul * 0.5) * tm.height; sw = x + (w + posv) * 0.5 + (mul * 0.5) * tm.height; } else { if ("right" === alignHorizontal) { dx = w - posv - (1 - mul) * tm.height; sx = x + dx; } } } } if (posh < h) { if (angle < 0) { dy = h - (posh + mul * tm.height); } else { dy = h - mul * tm.height; } } else { if (angle > 0) { dy = h - mul * tm.height; } } } else { if ("center" === alignVertical) { if (angle < 0) { if ("left" === alignHorizontal) { dx = (1 - mul * 0.5) * tm.height; sw = x + posv + (mul * 0.5) * tm.height; } else { if ("center" === alignHorizontal) { dx = (w + tm.height - posv) * 0.5; sx = x + (w - posv) * 0.5 - (mul * 0.5) * tm.height; sw = x + (w + posv) * 0.5 + (mul * 0.5) * tm.height; } else { if ("right" === alignHorizontal) { dx = w - (mul * 0.5) * tm.height - posv; sx = x + dx - (mul * 0.5) * tm.height; } } } } else { if ("left" === alignHorizontal) { sw = x + posv + (mul * 0.5) * tm.height; } else { if ("center" == alignHorizontal) { dx = (w - tm.height - posv) * 0.5; sx = x + (w - posv) * 0.5 - (mul * 0.5) * tm.height; sw = x + (w + posv) * 0.5 + (mul * 0.5) * tm.height; } else { if ("right" === alignHorizontal) { dx = w - posv - tm.height; sx = x + dx; sx = x + dx - (mul * 0.5) * tm.height; } } } } if (posh < h) { if (angle < 0) { dy = (h - posh) * 0.5; } else { dy = (h + posh) * 0.5; } } else { if (angle > 0) { dy = h - mul * tm.height; } } } else { if ("top" === alignVertical) { if (angle < 0) { if ("left" === alignHorizontal) { dx = (1 - mul * 0.5) * tm.height; sw = x + posv + (mul * 0.5) * tm.height; } else { if ("c" === alignHorizontal) { dx = (w + tm.height - posv) * 0.5; sx = x + (w - posv) * 0.5 - (mul * 0.5) * tm.height; sw = x + (w + posv) * 0.5 + (mul * 0.5) * tm.height; } else { if ("right" === alignHorizontal) { dx = w - (mul * 0.5) * tm.height - posv; sx = x + dx - (mul * 0.5) * tm.height; } } } } else { if ("left" === alignHorizontal) { sw = x + posv + (mul * 0.5) * tm.height; } else { if ("c" === alignHorizontal) { dx = (w - tm.height - posv) * 0.5; sx = x + (w - posv) * 0.5 - (mul * 0.5) * tm.height; sw = x + (w + posv) * 0.5 + (mul * 0.5) * tm.height; } else { if ("right" === alignHorizontal) { dx = w - posv - tm.height; sx = x + dx; sx = x + dx - (mul * 0.5) * tm.height; } } } dy = Math.min(h + tm.height * mul, posh); } } } } var bound = { dx: dx, dy: dy, x: x, y: y, sx: sx, sw: sw, height: 0 }; if (angle === 90 || angle === -90) { bound.height = textW; } else { bound.height = Math.abs(Math.sin(angle / 180 * Math.PI) * textW) + (mul) * tm.height; bound.height = asc_calcnpt(bound.height, 96); } return bound; }; StringRender.prototype.measure = function (maxWidth) { return this._doMeasure(maxWidth); }; StringRender.prototype.render = function (x, y, maxWidth, textColor) { this._doRender(undefined, x, y, maxWidth, textColor); return this; }; StringRender.prototype.renderForPrint = function (drawingCtx, x, y, maxWidth, textColor) { this._doRender(drawingCtx, x, y, maxWidth, textColor); return this; }; StringRender.prototype.measureString = function (str, flags, maxWidth) { if (str !== undefined) { this.setString(str, flags); } return this._doMeasure(maxWidth); }; StringRender.prototype.renderString = function (str, flags, x, y, maxWidth, textColor) { if (str !== undefined) { this.setString(str, flags); } if (this.charWidths.length < 1 && null === this._doMeasure(maxWidth)) { asc_debug("log", "Warning: can not measure '", str, "'"); return this; } this._doRender(undefined, x, y, maxWidth, textColor); return this; }; StringRender.prototype.getWidestCharWidth = function () { return this.charWidths.reduce(function (p, c) { return p < c ? c : p; }, 0); }; StringRender.prototype._reset = function () { this.chars = ""; this.charWidths = []; this.charProps = []; this.lines = []; this.ratio = 1; }; StringRender.prototype._filterText = function (fragment, wrap) { var s = fragment; if (s.search(this.reNL) >= 0) { s = s.replace(this.reReplaceNL, wrap ? "\n" : "\u00B6"); } if (s.search(this.reTab) >= 0) { s = s.replace(this.reReplaceTab, wrap ? " " : "\u2192"); } return s; }; StringRender.prototype._makeFont = function (format) { if (format !== undefined && asc_typeof(format.fn) === "string") { var fsz = format.fs > 0 ? format.fs : this.defaultFont.FontSize; return new asc.FontProperties(format.fn, fsz, format.b, format.i, format.u, format.s); } return this.defaultFont; }; StringRender.prototype._calcCharsWidth = function (startCh, endCh) { for (var w = 0, i = startCh; i <= endCh; ++i) { w += this.charWidths[i]; } return w * this.ratio; }; StringRender.prototype._calcLineWidth = function (startPos, endPos) { var wrap = this.flags && this.flags.wrapText; var wrapNL = this.flags && this.flags.wrapOnlyNL; var isAtEnd, j, chProp, tw; if (endPos === undefined || endPos < 0) { for (j = startPos + 1; j < this.chars.length; ++j) { chProp = this.charProps[j]; if (chProp && (chProp.nl || chProp.hp)) { break; } } endPos = j - 1; } for (j = endPos, tw = 0, isAtEnd = true; j >= startPos; --j) { if (isAtEnd) { if ((wrap || wrapNL) && this.reSpace.test(this.chars[j])) { continue; } isAtEnd = false; } tw += this.charWidths[j]; } return tw * this.ratio; }; StringRender.prototype._calcLineMetrics = function (f, va, fm, ppi) { var l = new lineMetrics(); var hpt = f * 1.275; var fpx = f * ppi / 72; var topt = 72 / ppi; var h; var a = asc_round(fpx) * topt; var d; var a_2 = asc_round(fpx / 2) * topt; var h_2_3; var a_2_3 = asc_round(fpx * 2 / 3) * topt; var d_2_3; var x = a_2 + a_2_3; if (va === "superscript") { h = asc_calcnpt(hpt, ppi); d = h - a; l.th = x + d; l.bl = x; l.bl2 = a_2_3; l.a = fm.ascender + a_2; l.d = fm.descender - a_2; } else { if (va === "subscript") { h_2_3 = asc_calcnpt(hpt * 2 / 3, ppi); d_2_3 = h_2_3 - a_2_3; l.th = x + d_2_3; l.bl = a; l.bl2 = x; l.a = fm.ascender + a - x; l.d = fm.descender + x - a; } else { var _a = Math.max(0, fm.nat_y1 * f / fm.nat_scale); var _d = Math.max(0, (-fm.nat_y2) * f / fm.nat_scale); var _aa = asc_calcnpt(_a, ppi); var _dd = asc_calcnpt(_d, ppi); l.th = _aa + _dd; l.bl = _aa; l.a = _aa; l.d = _dd; } } return l; }; StringRender.prototype.calcDelta = function (vnew, vold) { return vnew > vold ? vnew - vold : 0; }; StringRender.prototype._calcTextMetrics = function (dontCalcRepeatChars) { var self = this, i = 0, p, p_, lm, beg = 0; var l = new LineInfo(), TW = 0, TH = 0, BL = 0, CL = 0; var ppi = this.drawingCtx.getPPIY(); function addLine(b, e) { if (-1 !== b) { l.tw += self._calcLineWidth(b, e - 1); } l.beg = b; l.end = e - 1; self.lines.push(l); if (TW < l.tw) { TW = l.tw; } BL = TH + l.bl; TH += l.th; } if (0 >= this.chars.length) { p = this.charProps[0]; if (p && p.font) { lm = this._calcLineMetrics(p.fsz !== undefined ? p.fsz : p.font.FontSize, p.va, p.fm, ppi); l.assign(0, lm.th, lm.bl, lm.a, lm.d); addLine(-1, -1); l.beg = l.end = 0; } } else { for (; i < this.chars.length; ++i) { p = this.charProps[i]; if (p && p.font) { lm = this._calcLineMetrics(p.fsz !== undefined ? p.fsz : p.font.FontSize, p.va, p.fm, ppi); if (i === 0) { l.assign(0, lm.th, lm.bl, lm.a, lm.d); } else { l.th += this.calcDelta(lm.bl, l.bl) + this.calcDelta(lm.th - lm.bl, l.th - l.bl); l.bl += this.calcDelta(lm.bl, l.bl); l.a += this.calcDelta(lm.a, l.a); l.d += this.calcDelta(lm.d, l.d); } p.lm = lm; p_ = p; } if (dontCalcRepeatChars && p && p.repeat) { l.tw -= this._calcCharsWidth(i, i + p.total); } if (p && (p.nl || p.hp)) { addLine(beg, i); beg = i; lm = this._calcLineMetrics(p_.fsz !== undefined ? p_.fsz : p_.font.FontSize, p_.va, p_.fm, ppi); l = new LineInfo(0, lm.th, lm.bl, lm.a, lm.d); } } } if (beg < i) { addLine(beg, i); } if (this.lines.length > 0) { CL = (this.lines[0].bl - this.lines[0].a + BL + l.d) / 2; } return new asc.TextMetrics(TW, TH, 0, BL, 0, 0, CL); }; StringRender.prototype._getRepeatCharPos = function () { var charProp; for (var i = 0; i < this.chars.length; ++i) { charProp = this.charProps[i]; if (charProp && charProp.repeat) { return i; } } return -1; }; StringRender.prototype._insertRepeatChars = function (maxWidth) { var self = this, width, w, pos, charProp; function shiftCharPropsLeft(fromPos, delta) { var length = self.charProps.length; for (var i = fromPos; i < length; ++i) { var p = self.charProps[i]; if (p) { delete self.charProps[i]; self.charProps[i + delta] = p; } } } function shiftCharPropsRight(fromPos, delta) { for (var i = self.charProps.length - 1; i >= fromPos; --i) { var p = self.charProps[i]; if (p) { delete self.charProps[i]; self.charProps[i + delta] = p; } } } function insertRepeatChars() { if (0 === charProp.total) { return; } var repeatEnd = pos + charProp.total; self.chars = "" + self.chars.slice(0, repeatEnd) + self.chars.slice(pos, pos + 1) + self.chars.slice(repeatEnd); self.charWidths = [].concat(self.charWidths.slice(0, repeatEnd), self.charWidths.slice(pos, pos + 1), self.charWidths.slice(repeatEnd)); shiftCharPropsRight(pos + 1, 1); } function removeRepeatChar() { self.chars = "" + self.chars.slice(0, pos) + self.chars.slice(pos + 1); self.charWidths = [].concat(self.charWidths.slice(0, pos), self.charWidths.slice(pos + 1)); delete self.charProps[pos]; shiftCharPropsLeft(pos + 1, -1); } width = this._calcTextMetrics(true).width; pos = this._getRepeatCharPos(); if (-1 === pos) { return; } w = this._calcCharsWidth(pos, pos); charProp = this.charProps[pos]; while (charProp.total * w + width + w <= maxWidth) { insertRepeatChars(); charProp.total += 1; } if (0 === charProp.total) { removeRepeatChar(); } this.lines = []; }; StringRender.prototype._getCharPropAt = function (index) { var prop = this.charProps[index]; if (!prop) { prop = this.charProps[index] = new charProperties(); } return prop; }; StringRender.prototype._measureChars = function (maxWidth) { var self = this; var ctx = this.drawingCtx; var wrap = this.flags && this.flags.wrapText && !this.flags.isNumberFormat; var wrapNL = this.flags && this.flags.wrapOnlyNL; var hasRepeats = false; var i, j, fr, fmt, text, p, p_ = {}, pIndex, va, f, f_, eq, startCh; var tw = 0, nlPos = 0, hpPos = undefined, isSP_ = true, delta = 0; function measureFragment(s) { var j, ch, chw, chPos, isNL, isSP, isHP, tm; for (chPos = self.chars.length, j = 0; j < s.length; ++j, ++chPos) { ch = s.charAt(j); tm = ctx.measureChar(ch, 1); chw = tm.width; isNL = self.reHypNL.test(ch); isSP = !isNL ? self.reHypSp.test(ch) : false; if (wrap || wrapNL) { isHP = !isSP && !isNL ? self.reHyphen.test(ch) : false; if (isNL) { nlPos = chPos + 1; self._getCharPropAt(nlPos).nl = true; self._getCharPropAt(nlPos).delta = delta; ch = " "; chw = 0; tw = 0; hpPos = undefined; } else { if (isSP || isHP) { hpPos = chPos + 1; } } if (wrap && tw + chw > maxWidth && chPos !== nlPos && !isSP) { nlPos = hpPos !== undefined ? hpPos : chPos; self._getCharPropAt(nlPos).hp = true; self._getCharPropAt(nlPos).delta = delta; tw = self._calcCharsWidth(nlPos, chPos - 1); hpPos = undefined; } } if (isSP_ && !isSP && !isNL) { self._getCharPropAt(chPos).wrd = true; } tw += chw; self.charWidths.push(chw); self.chars += ch; isSP_ = isSP || isNL; delta = tm.widthBB - tm.width; } } this._reset(); for (i = 0, f_ = ctx.getFont(); i < this.fragments.length; ++i) { startCh = this.charWidths.length; fr = this.fragments[i]; fmt = fr.format; text = this._filterText(fr.text, wrap || wrapNL); f = this._makeFont(fmt); pIndex = this.chars.length; p = this.charProps[pIndex]; p = p ? p.clone() : new charProperties(); va = fmt.va !== undefined ? fmt.va.toLowerCase() : ""; if (va === "subscript" || va === "superscript") { p.va = va; p.fsz = f.FontSize; f.FontSize *= 2 / 3; p.font = f; } eq = f.isEqual(f_); if (!eq || f.Underline !== f_.Underline || f.Strikeout !== f_.Strikeout || fmt.c !== p_.c) { if (!eq) { ctx.setFont(f, this.angle); } p.font = f; f_ = f; } if (i === 0) { p.font = f; } if (p.font) { p.fm = ctx.getFontMetrics(); p.c = fmt.c; this.charProps[pIndex] = p; p_ = p; } if (fmt.skip) { this._getCharPropAt(pIndex).skip = text.length; } if (fmt.repeat) { if (hasRepeats) { throw "Repeat should occur no more than once"; } this._getCharPropAt(pIndex).repeat = true; this._getCharPropAt(pIndex).total = 0; hasRepeats = true; } if (text.length < 1) { continue; } measureFragment(text); for (j = startCh; f_.Italic && j < this.charWidths.length; ++j) { if (this.charProps[j] && this.charProps[j].delta && j > 0) { if (this.charWidths[j - 1] > 0) { this.charWidths[j - 1] += this.charProps[j].delta; } else { if (j > 1) { this.charWidths[j - 2] += this.charProps[j].delta; } } } } } if (0 !== this.chars.length && this.charProps[this.chars.length] !== undefined) { delete this.charProps[this.chars.length]; } else { if (f_.Italic) { this.charWidths[this.charWidths.length - 1] += delta; } } if (hasRepeats) { if (maxWidth === undefined) { throw "Undefined width of cell width Numeric Format"; } this._insertRepeatChars(maxWidth); } return this._calcTextMetrics(); }; StringRender.prototype._doMeasure = function (maxWidth) { var tm = this._measureChars(maxWidth); if (this.flags && this.flags.shrinkToFit && tm.width > maxWidth) { this.ratio = maxWidth / tm.width; tm.width = maxWidth; } return tm; }; StringRender.prototype._doRender = function (drawingCtx, x, y, maxWidth, textColor) { var self = this; var ctx = (undefined !== drawingCtx) ? drawingCtx : this.drawingCtx; var ppix = ctx.getPPIX(); var ppiy = ctx.getPPIY(); var shrink = this.flags && this.flags.shrinkToFit; var align = this.flags ? this.flags.textAlign.toLowerCase() : ""; var i, j, p, p_, f, f_, strBeg; var n = 0, l = this.lines[0], x1 = l ? initX(0) : 0, y1 = y, dx = l ? computeWordDeltaX() : 0; function initX(startPos) { var x_ = x; if (align === "right") { x_ = asc_calcnpt(x + maxWidth - self._calcLineWidth(startPos), ppix, -1); } else { if (align === "center") { x_ = asc_calcnpt(x + 0.5 * (maxWidth - asc_calcnpt(self._calcLineWidth(startPos), ppix)), ppix, 0); } } l.startX = x_; return x_; } function computeWordDeltaX() { if (align !== "justify" || n === self.lines.length - 1) { return 0; } for (var i = l.beg, c = 0; i <= l.end; ++i) { var p = self.charProps[i]; if (p && p.wrd) { ++c; } } return c > 1 ? (maxWidth - l.tw) / (c - 1) : 0; } function renderFragment(begin, end, prop, angle) { var dh = prop && prop.lm && prop.lm.bl2 > 0 ? prop.lm.bl2 - prop.lm.bl : 0; var dw = self._calcCharsWidth(strBeg, end - 1); var so = prop.font.Strikeout; var ul = Asc.EUnderline.underlineNone !== prop.font.Underline; var isSO = so === true; var fsz, x2, y, lw, dy, i, b, x_, cp, w_1px, h_1px; if (align !== "justify" || dx < 1e-06) { ctx.fillText(self.chars.slice(begin, end), x1, y1 + l.bl + dh, undefined, self.charWidths.slice(begin, end), angle); } else { for (i = b = begin, x_ = x1; i < end; ++i) { cp = self.charProps[i]; if (cp && cp.wrd && i > b) { ctx.fillText(self.chars.slice(b, i), x_, y1 + l.bl + dh, undefined, self.charWidths.slice(b, i), angle); x_ += self._calcCharsWidth(b, i - 1) + dx; dw += dx; b = i; } } if (i > b) { ctx.fillText(self.chars.slice(b, i), x_, y1 + l.bl + dh, undefined, self.charWidths.slice(b, i), angle); } } if (isSO || ul) { x2 = asc_calcnpt(x1 + dw, ppix); fsz = prop.font.FontSize * self.ratio; lw = asc_round(fsz * ppiy / 72 / 18) || 1; ctx.setStrokeStyle(prop.c || textColor).setLineWidth(lw).beginPath(); w_1px = asc_calcnpt(0, ppix, 1); h_1px = asc_calcnpt(0, ppiy, 1); dy = (lw / 2); dy = dy >> 0; if (ul) { y = asc_calcnpt(y1 + l.bl + prop.lm.d * 0.4, ppiy); ctx.lineHor(x1, y + dy * h_1px, x2 + w_1px); } if (isSO) { dy += 1; y = asc_calcnpt(y1 + l.bl - prop.lm.a * 0.275, ppiy); ctx.lineHor(x1, y - dy * h_1px, x2 + w_1px); } ctx.stroke(); } return dw; } for (i = 0, strBeg = 0, f_ = ctx.getFont(); i < this.chars.length; ++i) { p = this.charProps[i]; if (p && (p.font || p.nl || p.hp || p.skip > 0)) { if (strBeg < i) { x1 += renderFragment(strBeg, i, p_, this.angle); strBeg = i; } if (p.font) { f = p.font.clone(); if (shrink) { f.FontSize *= this.ratio; } if (!f.isEqual(f_) || this.fontNeedUpdate) { ctx.setFont(f, this.angle); f_ = f; this.fontNeedUpdate = false; } ctx.setFillStyle(p.c || textColor); p_ = p; } if (p.skip > 0) { j = i + p.skip - 1; x1 += this._calcCharsWidth(i, j); strBeg = j + 1; i = j; continue; } if (p.nl || p.hp) { y1 += l.th; l = self.lines[++n]; x1 = initX(i); dx = computeWordDeltaX(); } } } if (strBeg < i) { renderFragment(strBeg, i, p_, this.angle); } }; StringRender.prototype.getInternalState = function () { return { defaultFont: this.defaultFont !== undefined ? this.defaultFont.clone() : undefined, flags: this.flags, chars: this.chars, charWidths: this.charWidths, charProps: this.charProps, lines: this.lines, ratio: this.ratio }; }; StringRender.prototype.restoreInternalState = function (state) { this.defaultFont = state.defaultFont; this.flags = state.flags; this.chars = state.chars; this.charWidths = state.charWidths; this.charProps = state.charProps; this.lines = state.lines; this.ratio = state.ratio; return this; }; window["Asc"].StringRender = StringRender; })(window);