Files
DocumentServer-v-9.2.0/sdkjs/common/libfont/file.js
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

1934 lines
51 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (c) Copyright Ascensio System SIA 2010-2024
*
* 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 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* 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)
{
//window.measureTime = 0;
//window.rasterTime = 0;
var AscFonts = window['AscFonts'];
var AscCommon = window['AscCommon'];
AscFonts.FT_Load_Mode = {
FT_LOAD_DEFAULT : 0,
FT_LOAD_NO_SCALE : 1 << 0,
FT_LOAD_NO_HINTING : 1 << 1,
FT_LOAD_RENDER : 1 << 2,
FT_LOAD_NO_BITMAP : 1 << 3,
FT_LOAD_VERTICAL_LAYOUT : 1 << 4,
FT_LOAD_FORCE_AUTOHINT : 1 << 5,
FT_LOAD_CROP_BITMAP : 1 << 6,
FT_LOAD_PEDANTIC : 1 << 7,
FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH : 1 << 9,
FT_LOAD_NO_RECURSE : 1 << 10,
FT_LOAD_IGNORE_TRANSFORM : 1 << 11,
FT_LOAD_MONOCHROME : 1 << 12,
FT_LOAD_LINEAR_DESIGN : 1 << 13,
FT_LOAD_NO_AUTOHINT : 1 << 15,
FT_LOAD_COLOR : 1 << 20,
FT_LOAD_COMPUTE_METRICS : 1 << 21,
FT_LOAD_BITMAP_METRICS_ONLY : 1 << 22
};
AscFonts.FT_Render_Mode = {
FT_RENDER_MODE_NORMAL : 0,
FT_RENDER_MODE_LIGHT : 1,
FT_RENDER_MODE_MONO : 2,
FT_RENDER_MODE_LCD : 3,
FT_RENDER_MODE_LCD_V : 4,
FT_RENDER_MODE_MAX : 5
};
function FT_LOAD_TARGET(val) { return (val & 15) << 16; }
AscFonts.FT_Load_Target_Mode = {
FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET(AscFonts.FT_Render_Mode.FT_RENDER_MODE_NORMAL),
FT_LOAD_TARGET_LIGHT : FT_LOAD_TARGET(AscFonts.FT_Render_Mode.FT_RENDER_MODE_LIGHT),
FT_LOAD_TARGET_MONO : FT_LOAD_TARGET(AscFonts.FT_Render_Mode.FT_RENDER_MODE_MONO),
FT_LOAD_TARGET_LCD : FT_LOAD_TARGET(AscFonts.FT_Render_Mode.FT_RENDER_MODE_LCD),
FT_LOAD_TARGET_LCD_V : FT_LOAD_TARGET(AscFonts.FT_Render_Mode.FT_RENDER_MODE_LCD_V)
};
AscFonts.LOAD_MODE_DEFAULT =
AscFonts.FT_Load_Mode.FT_LOAD_DEFAULT |
AscFonts.FT_Load_Mode.FT_LOAD_NO_HINTING |
AscFonts.FT_Load_Mode.FT_LOAD_LINEAR_DESIGN |
AscFonts.FT_Load_Mode.FT_LOAD_NO_AUTOHINT;
AscFonts.LOAD_MODE_HINTING =
AscFonts.FT_Load_Mode.FT_LOAD_DEFAULT |
AscFonts.FT_Load_Mode.FT_LOAD_LINEAR_DESIGN |
AscFonts.FT_Load_Mode.FT_LOAD_NO_AUTOHINT;
AscFonts.isUseBitmapStrikes = function(symbol)
{
if (!AscFonts.mRanges)
{
AscFonts.mRanges = [];
AscFonts.mRanges.push(0x1100); AscFonts.mRanges.push(0x11FF);
AscFonts.mRanges.push(0x2E80); AscFonts.mRanges.push(0x9FFF);
AscFonts.mRanges.push(0xAC00); AscFonts.mRanges.push(0xD7AF);
AscFonts.mRanges.push(0xF900); AscFonts.mRanges.push(0xFAFF);
AscFonts.mRanges.push(0xFF00); AscFonts.mRanges.push(0xFFEF);
AscFonts.mRanges.push(0x20000); AscFonts.mRanges.push(0x2A6DF);
AscFonts.mRanges.push(0x2F800); AscFonts.mRanges.push(0x2FA1F);
}
if (symbol < AscFonts.mRanges[0])
return false;
var _m = AscFonts.mRanges;
var _l = AscFonts.mRanges.length;
for (var i = 0; i < _l; i += 2)
{
if (symbol >= _m[i] && symbol <= _m[i + 1])
return true;
}
return false;
};
var raster_memory = AscFonts.raster_memory;
var FONT_ITALIC_ANGLE = 0.3090169943749;
var REND_MODE = AscFonts.FT_Render_Mode.FT_RENDER_MODE_NORMAL;
var EGlyphState =
{
glyphstateNormal : 0, // символ отрисовался в нужном шрифте
glyphstateDefault : 1, // символ отрисовался в дефолтовом шрифте
glyphstateMiss : 2 // символ не отрисовался
};
function get_raster_bounds_safe(rasterBitmap)
{
if (!rasterBitmap)
return {dist_l: 0, dist_t: 0, dist_r: 0, dist_b: 0};
return get_raster_bounds(rasterBitmap.data, rasterBitmap.width, rasterBitmap.rows, rasterBitmap.pitch);
}
function get_raster_bounds(data, width, height, stride)
{
var ret = {dist_l: 0, dist_t: 0, dist_r: 0, dist_b: 0};
// left
var bIsBreak = false;
for (var i = 0; i < width; i++)
{
var _ind = i * 4 + 3;
for (var j = 0; j < height; j++, _ind += stride)
{
if (data[_ind] != 0)
{
bIsBreak = true;
break;
}
}
if (bIsBreak)
break;
ret.dist_l++;
}
// right
bIsBreak = false;
for (var i = width - 1; i >= 0; i--)
{
var _ind = i * 4 + 3;
for (var j = 0; j < height; j++, _ind += stride)
{
if (data[_ind] != 0)
{
bIsBreak = true;
break;
}
}
if (bIsBreak)
break;
ret.dist_r++;
}
// top
var bIsBreak = false;
for (var j = 0; j < height; j++)
{
var _ind = j * stride + 3;
for (var i = 0; i < width; i++, _ind += 4)
{
if (data[_ind] != 0)
{
bIsBreak = true;
break;
}
}
if (bIsBreak)
break;
ret.dist_t++;
}
// bottom
var bIsBreak = false;
for (var j = height - 1; j >= 0; j--)
{
var _ind = j * stride + 3;
for (var i = 0; i < width; i++, _ind += 4)
{
if (data[_ind] != 0)
{
bIsBreak = true;
break;
}
}
if (bIsBreak)
break;
ret.dist_b++;
}
// clear
if (null != raster_memory.m_oBuffer)
{
var nIndexDst = 3;
var nPitch = 4 * (raster_memory.width - width);
var dst = raster_memory.m_oBuffer.data;
for (var j = 0; j < height; j++)
{
for (var i = 0; i < width; i++)
{
dst[nIndexDst] = 0;
nIndexDst += 4;
}
nIndexDst += nPitch;
}
}
return ret;
}
function CGlyphData()
{
this.m_oCanvas = null;
this.m_oContext = null;
this.R = 0;
this.G = 0;
this.B = 0;
this.RasterData = null;
this.TempImage = null;
}
CGlyphData.prototype =
{
// not used (old devices)
checkColorAppleDevices : function(r, g, b, w, h)
{
if ((r == this.R) && (g == this.G) && (b == this.B))
return;
this.R = r;
this.G = g;
this.B = b;
// full repaint
this.TempImage = document.createElement("canvas");
this.TempImage.width = w;
this.TempImage.height = h;
var ctxD = AscCommon.AscBrowser.getContext2D(this.TempImage);
var pixDst = null;
if (this.m_oCanvas != null)
{
pixDst = this.m_oContext.getImageData(0, 0, w, h);
var dataPx = pixDst.data;
var cur = 0;
var cnt = w * h;
for (var i = 0; i < cnt; i++)
{
dataPx[cur++] = r;
dataPx[cur++] = g;
dataPx[cur++] = b;
cur++;
}
}
else
{
var _raster = this.RasterData;
var _x = _raster.Line.Height * _raster.Index;
var _y = _raster.Line.Y;
pixDst = _raster.Chunk.CanvasCtx.getImageData(_x, _y, w, h);
var dataPx = pixDst.data;
var cur = 0;
var cnt = w * h;
for (var i = 0; i < cnt; i++)
{
dataPx[cur++] = r;
dataPx[cur++] = g;
dataPx[cur++] = b;
cur++;
}
}
ctxD.putImageData(pixDst, 0, 0, 0, 0, w, h);
},
checkColorMozillaLinux : function(r, g, b, w, h)
{
if ((r == this.R) && (g == this.G) && (b == this.B))
return;
this.R = r;
this.G = g;
this.B = b;
if (this.m_oCanvas != null)
{
this.m_oContext.fillStyle = (this.R == 0xFF && this.G == 0xFF && this.B == 0xFF) ? "rgb(255,255,254)" : "rgb(" + this.R + "," + this.G + "," + this.B + ")";
this.m_oContext.fillRect(0, 0, w, h);
}
else
{
var _raster = this.RasterData;
_raster.Chunk.CanvasCtx.fillStyle = (this.R == 0xFF && this.G == 0xFF && this.B == 0xFF) ? "rgb(255,255,254)" : "rgb(" + this.R + "," + this.G + "," + this.B + ")";
var _x = _raster.Line.Height * _raster.Index;
var _y = _raster.Line.Y;
this.RasterData.Chunk.CanvasCtx.fillRect(_x, _y, w, h);
}
},
checkColorNormal : function(r, g, b, w, h)
{
if ((r == this.R) && (g == this.G) && (b == this.B))
return;
this.R = r;
this.G = g;
this.B = b;
if (this.m_oCanvas != null)
{
this.m_oContext.fillStyle = "rgb(" + this.R + "," + this.G + "," + this.B + ")";
this.m_oContext.fillRect(0, 0, w, h);
}
else
{
var _raster = this.RasterData;
_raster.Chunk.CanvasCtx.fillStyle = "rgb(" + this.R + "," + this.G + "," + this.B + ")";
var _x = _raster.Line.Height * _raster.Index;
var _y = _raster.Line.Y;
this.RasterData.Chunk.CanvasCtx.fillRect(_x, _y, w, h);
}
},
checkColor : undefined,
init: function (width, height)
{
if (width == 0 || height == 0)
return;
this.m_oCanvas = document.createElement('canvas');
this.m_oCanvas.width = (width == 0) ? 1 : width;
this.m_oCanvas.height = (height == 0) ? 1 : height;
this.m_oContext = AscCommon.AscBrowser.getContext2D(this.m_oCanvas);
this.m_oContext.globalCompositeOperation = "source-in";
}
};
CGlyphData.prototype.checkColor = (AscCommon.AscBrowser.isMozilla && AscCommon.AscBrowser.isLinuxOS) ? CGlyphData.prototype.checkColorMozillaLinux : CGlyphData.prototype.checkColorNormal;
function CGlyphBitmap()
{
this.nX = 0; // Сдвиг по X начальной точки для рисования символа
this.nY = 0; // Сдвиг по Y начальной точки для рисования символа
this.nWidth = 0; // Ширина символа
this.nHeight = 0; // Высота символа
this.oGlyphData = new CGlyphData();
}
CGlyphBitmap.prototype =
{
fromAlphaMask: function (font_manager)
{
var bIsCanvas = false;
var _chunk_size = (font_manager.RasterMemory == null) ? 0 : font_manager.RasterMemory.ChunkHeapSize;
if (Math.max(this.nWidth, this.nHeight) > (_chunk_size / 10))
bIsCanvas = true;
var _x = 0;
var _y = 0;
var ctx = null;
if (bIsCanvas)
{
this.oGlyphData.init(this.nWidth, this.nHeight);
ctx = this.oGlyphData.m_oContext;
}
else
{
this.oGlyphData.RasterData = font_manager.RasterMemory.Alloc(this.nWidth, this.nHeight);
ctx = this.oGlyphData.RasterData.Chunk.CanvasCtx;
_x = this.oGlyphData.RasterData.Line.Height * this.oGlyphData.RasterData.Index;
_y = this.oGlyphData.RasterData.Line.Y;
}
if (true)
{
if (this.nWidth > 0 && this.nHeight > 0)
ctx.putImageData(raster_memory.m_oBuffer, _x, _y, 0, 0, this.nWidth, this.nHeight);
}
else
{
var gamma = 1.1;
var nIndexDst = 3;
var nPitch = 4 * (raster_memory.width - this.nWidth);
var dst = raster_memory.m_oBuffer.data;
for (var j = 0; j < this.nHeight; j++)
{
for (var i = 0; i < this.nWidth; i++)
{
dst[nIndexDst] = Math.min((dst[nIndexDst] * gamma) >> 0, 255);
nIndexDst += 4;
}
nIndexDst += nPitch;
}
if (this.nWidth > 0 && this.nHeight > 0)
ctx.putImageData(raster_memory.m_oBuffer, _x, _y, 0, 0, this.nWidth, this.nHeight);
}
if (null != raster_memory.m_oBuffer)
{
var nIndexDst = 3;
var nPitch = 4 * (raster_memory.width - this.nWidth);
var dst = raster_memory.m_oBuffer.data;
for (var j = 0; j < this.nHeight; j++)
{
for (var i = 0; i < this.nWidth; i++)
{
dst[nIndexDst] = 0;
nIndexDst += 4;
}
nIndexDst += nPitch;
}
}
},
draw: function (context2D, x, y)
{
var nW = this.nWidth;
var nH = this.nHeight;
if (null != this.oGlyphData.TempImage)
{
context2D.drawImage(this.oGlyphData.TempImage, 0, 0, nW, nH, x, y, nW, nH);
this.oGlyphData.TempImage = null;
}
else if (null != this.oGlyphData.m_oCanvas)
{
// своя память
context2D.drawImage(this.oGlyphData.m_oCanvas, 0, 0, nW, nH, x, y, nW, nH);
}
else
{
var _raster = this.oGlyphData.RasterData;
var _x = _raster.Line.Height * _raster.Index;
var _y = _raster.Line.Y;
context2D.drawImage(_raster.Chunk.CanvasImage, _x, _y, nW, nH, x, y, nW, nH);
}
},
drawCrop: function (context2D, x, y, w, h, cx)
{
if (null != this.oGlyphData.TempImage)
{
context2D.drawImage(this.oGlyphData.TempImage, cx, 0, w, h, x, y, w, h);
this.oGlyphData.TempImage = null;
}
else if (null != this.oGlyphData.m_oCanvas)
{
// своя память
context2D.drawImage(this.oGlyphData.m_oCanvas, cx, 0, w, h, x, y, w, h);
}
else
{
var _raster = this.oGlyphData.RasterData;
var _x = _raster.Line.Height * _raster.Index;
var _y = _raster.Line.Y;
context2D.drawImage(_raster.Chunk.CanvasImage, _x + cx, _y, w, h, x, y, w, h);
}
},
drawCropInRect: function (context2D, x, y, clipRect)
{
var _x = x;
var _y = y;
var _r = x + this.nWidth;
var _b = y + this.nHeight;
var _dstX = 0;
var _dstY = 0;
var _dstW = this.nWidth;
var _dstH = this.nHeight;
if (_x < clipRect.l)
{
_dstX = clipRect.l - _x;
_x += _dstX;
_dstW -= _dstX;
}
if (_y < clipRect.t)
{
_dstY = clipRect.t - _y;
_y += _dstY;
_dstH -= _dstY;
}
if (_r > clipRect.r)
{
_dstW -= (_r - clipRect.r);
}
if (_b > clipRect.b)
{
_dstH -= (_b - clipRect.b);
}
if (_dstW <= 0 || _dstH <= 0)
return;
if (null != this.oGlyphData.TempImage)
{
context2D.drawImage(this.oGlyphData.TempImage, _dstX, _dstY, _dstW, _dstH, _x, _y, _dstW, _dstH);
this.oGlyphData.TempImage = null;
}
else if (null != this.oGlyphData.m_oCanvas)
{
// своя память
context2D.drawImage(this.oGlyphData.m_oCanvas, _dstX, _dstY, _dstW, _dstH, _x, _y, _dstW, _dstH);
}
else
{
var _raster = this.oGlyphData.RasterData;
var __x = _raster.Line.Height * _raster.Index;
var __y = _raster.Line.Y;
context2D.drawImage(_raster.Chunk.CanvasImage, __x + _dstX, __y + _dstY, _dstW, _dstH, _x, _y, _dstW, _dstH);
}
},
Free: function ()
{
if (null != this.oGlyphData.RasterData)
{
this.oGlyphData.RasterData.Chunk.Free(this.oGlyphData.RasterData);
}
}
};
function CBBox()
{
this.fMinX = 0;
this.fMaxX = 0;
this.fMinY = 0;
this.fMaxY = 0;
this.rasterDistances = null;
}
function CMetrics()
{
this.fWidth = 0;
this.fHeight = 0;
this.fHoriBearingX = 0;
this.fHoriBearingY = 0;
this.fHoriAdvance = 0;
this.fVertBearingX = 0;
this.fVertBearingY = 0;
this.fVertAdvance = 0;
}
function CFontCacheSizes()
{
this.ushUnicode; // Значение символа в юникоде
this.eState; // Есть ли символ в шрифте/стандартном шрифте
this.nCMapIndex; // Номер таблицы 'cmap', в которой был найден данный символ
this.ushGID;
this.fAdvanceX;
this.oBBox = new CBBox();
this.oMetrics = new CMetrics();
this.bBitmap = false;
this.oBitmap = null;
}
function CCMapIndex()
{
this.index = 0;
}
function CGlyphVectorPainter()
{
// сдвиг
this.X = 0;
this.Y = 0;
// scale
this.KoefX = 25.4 / 72;
this.KoefY = 25.4 / 72;
this.NeedClosed = false;
this.shift = 0;
this.delta = 0;
this.CurX = 0;
this.CurY = 0;
}
CGlyphVectorPainter.prototype =
{
start: function ()
{
},
_move_to: function(x, y, worker)
{
if (this.NeedClosed)
{
worker._z();
this.NeedClosed = false;
}
this.CurX = this.X + this.KoefX * (x / 64.0);
this.CurY = this.Y - this.KoefY * (y / 64.0);
worker._m(this.CurX, this.CurY);
return 0;
},
move_to: function (to, worker)
{
return this._move_to(to.x, to.y, worker);
},
_line_to: function (x, y, worker)
{
this.CurX = this.X + this.KoefX * (x / 64.0);
this.CurY = this.Y - this.KoefY * (y / 64.0);
worker._l(this.CurX, this.CurY);
this.NeedClosed = true;
return 0;
},
line_to: function (to, worker)
{
return this._line_to(to.x, to.y, worker);
},
_conic_to: function (control_x, control_y, to_x, to_y, worker)
{
var dX0 = this.CurX;
var dY0 = this.CurY;
var dXc = this.X + this.KoefX * (control_x / 64.0);
var dYc = this.Y - this.KoefY * (control_y / 64.0);
var dX3 = this.X + this.KoefX * (to_x / 64.0);
var dY3 = this.Y - this.KoefY * (to_y / 64.0);
// Строим кривую Безье второго порядка, с помощью кривой Безье третего порядка. Если p0, pC, p3 -
// начальная, контрольная и конечная точки, соответственно, для кривой Безье второго порядка. Тогда
// для этой же кривой, рассматриваемой как кривая Безье третьего порядка, точки p0, p1, p2, p3 будут
// начальной, две контрольные, конечная точки. Где p1 и p2 рассчитываются по следующим формулам:
// p1 = (1/3) * (p0 + 2pС)
// p2 = (1/3) * (2pС + p3)
var dX1 = (1.0 / 3.0) * (dX0 + 2 * dXc);
var dY1 = (1.0 / 3.0) * (dY0 + 2 * dYc);
var dX2 = (1.0 / 3.0) * (2 * dXc + dX3);
var dY2 = (1.0 / 3.0) * (2 * dYc + dY3);
worker._c(dX1, dY1, dX2, dY2, dX3, dY3);
this.CurX = dX3;
this.CurY = dY3;
this.NeedClosed = true;
return 0;
},
conic_to: function (control, to, worker)
{
return this._conic_to(control.x, control.y, to.x, to.y, worker);
},
_cubic_to: function (control1_x, control1_y, control2_x, control2_y, to_x, to_y, worker)
{
this.CurX = this.X + this.KoefX * (to_x / 64.0);
this.CurY = this.Y - this.KoefY * (to_y / 64.0);
worker._c(
this.X + this.KoefX * (control1_x / 64.0),
this.Y - this.KoefY * (control1_y / 64.0),
this.X + this.KoefX * (control2_x / 64.0),
this.Y - this.KoefY * (control2_y / 64.0),
this.CurX,
this.CurY);
this.NeedClosed = true;
return 0;
},
cubic_to: function (control1, control2, to, worker)
{
return this._cubic_to(control1.x, control1.y, control2.x, control2.y, to.x, to.y, worker);
},
end: function (worker)
{
if (this.NeedClosed)
{
worker._z();
this.NeedClosed = false;
}
}
};
function CFontFile()
{
this.m_arrdFontMatrix = ("undefined" == typeof Float64Array) ? new Array(6) : new Float64Array(6);
this.m_arrdTextMatrix = ("undefined" == typeof Float64Array) ? new Array(6) : new Float64Array(6);
this.m_bAntiAliasing = true;
this.m_bUseKerning = false;
this.m_fSize = 1.0; // Размер шрифта
this.m_unHorDpi = 0; // Горизонтальное разрешение
this.m_unVerDpi = 0; // Вертикальное разрешение
this.m_bNeedDoItalic = false;
this.m_bNeedDoBold = false;
this.m_fCharSpacing = 0.0;
this.m_oBox = new AscFonts.CGlyphBounds(); // Glyph box
this.m_nError = 0;
this.m_pFace = null;
this.m_pFaceInfo = null;
this.m_pHBFont = 0;
this.m_dUnitsKoef = 1.0;
this.m_nDefaultChar = -1;
this.m_nSymbolic = -1;
this.m_dTextScale = 0;
this.m_bStringGID = false;
this.m_nNum_charmaps = 0;
this.m_lAscender = 0;
this.m_lDescender = 0;
this.m_lLineHeight = 0;
this.m_lUnits_Per_Em = 0;
this.m_arrCacheSizes = [];
this.m_arrCacheSizesGid = [];
this.m_oFontManager = null;
this.HintsSupport = true;
this.HintsSubpixelSupport = true;
this.m_bIsTransform = true; // !IsIdentity matrix transform
this.fixed_sizes = undefined;
this.Picker = new CFontLoaderBySymbol();
this.FT_Load_Glyph_Wrapper = function(pFace, unGID, _LOAD_MODE)
{
var err = AscFonts.FT_Load_Glyph(pFace, unGID, _LOAD_MODE);
if (0 != err && this.HintsSupport)
{
var err2 = AscFonts.FT_Load_Glyph(pFace, unGID, AscFonts.LOAD_MODE_DEFAULT);
if (err2 != 0)
return err;
this.HintsSupport = false;
return err2;
}
return err;
};
this.ResetFontMatrix = function()
{
var m = this.m_arrdFontMatrix;
if (this.m_bNeedDoItalic)
{
m[0] = 1;
m[1] = 0;
m[2] = FONT_ITALIC_ANGLE;
m[3] = 1;
m[4] = 0;
m[5] = 0;
}
else
{
m[0] = 1;
m[1] = 0;
m[2] = 0;
m[3] = 1;
m[4] = 0;
m[5] = 0;
}
this.UpdateMatrix();
};
this.ResetTextMatrix = function()
{
var m = this.m_arrdTextMatrix;
m[0] = 1;
m[1] = 0;
m[2] = 0;
m[3] = 1;
m[4] = 0;
m[5] = 0;
this.CheckTextMatrix();
};
this.CheckTextMatrix = function()
{
this.m_bIsTransform = true;
var m = this.m_arrdTextMatrix;
if ((m[0] == 1) && (m[1] == 0) && (m[2] == 0) && (m[3] == 1))
{
this.m_bIsTransform = false;
this.UpdateMatrix();
}
};
this.UpdateMatrix = function()
{
var m = this.m_arrdFontMatrix;
var t = this.m_arrdTextMatrix;
var xx = ((m[0] * t[0] + m[1] * t[2]) * 65536) >> 0;
var yx = ((m[0] * t[1] + m[1] * t[3]) * 65536) >> 0;
var xy = ((m[2] * t[0] + m[3] * t[2]) * 65536) >> 0;
var yy = ((m[2] * t[1] + m[3] * t[3]) * 65536) >> 0;
AscFonts.FT_Set_Transform(this.m_pFace, xx, yx, xy, yy);
};
this.SetSizeAndDpi = function (dSize, unHorDpi, unVerDpi)
{
var dpiX = (unHorDpi + 0.5) >> 0;
var dpiY = (unVerDpi + 0.5) >> 0;
var dOldSize = this.m_fSize;
var dNewSize = dSize;
var dKoef = dNewSize / dOldSize;
var isResize = (dKoef > 1.001 || dKoef < 0.999) ? true : false;
if (isResize || dpiX != this.m_unHorDpi || dpiY != this.m_unVerDpi)
{
this.m_unHorDpi = dpiX;
this.m_unVerDpi = dpiY;
if (isResize)
{
this.m_fSize = dNewSize;
this.UpdateMatrix();
}
this.m_dUnitsKoef = this.m_unHorDpi / 72.0 * this.m_fSize;
// Выставляем размер шрифта (dSize) и DPI
this.m_nError = AscFonts.FT_Set_Char_Size(this.m_pFace, 0, (dNewSize * 64) >> 0, dpiX, dpiY);
this.ClearCache();
}
};
this.ClearCache = function()
{
this.Destroy();
this.ClearCacheNoAttack();
if (this.Picker)
this.Picker.ClearCache();
};
this.ClearCacheNoAttack = function()
{
this.m_arrCacheSizes = [];
this.m_arrCacheSizesGid = [];
if (this.Picker)
this.Picker.ClearCacheNoAttack();
};
this.Destroy = function()
{
if (this.m_oFontManager != null && this.m_oFontManager.RasterMemory != null)
{
var _arr = this.m_arrCacheSizes;
for (var i in _arr)
{
if (_arr[i].oBitmap != null)
_arr[i].oBitmap.Free();
}
_arr = this.m_arrCacheSizesGid;
for (var i in _arr)
{
if (_arr[i].oBitmap != null)
_arr[i].oBitmap.Free();
}
}
};
this.SetTextMatrix = function(fA, fB, fC, fD, fE, fF)
{
var m = this.m_arrdTextMatrix;
var b1 = (m[0] == fA && m[1] == -fB && m[2] == -fC && m[3] == fD);
if (b1 && m[4] == fE && m[5] == fF)
return false;
m[0] = fA;
m[1] = -fB;
m[2] = -fC;
m[3] = fD;
m[4] = fE;
m[5] = fF;
if (!b1)
{
this.ClearCache();
}
this.CheckTextMatrix();
return true;
};
this.SetFontMatrix = function(fA, fB, fC, fD, fE, fF)
{
var m = this.m_arrdFontMatrix;
if (this.m_bNeedDoItalic)
{
m[0] = fA;
m[1] = fB;
m[2] = fC + fA * FONT_ITALIC_ANGLE;
m[3] = fD + fB * FONT_ITALIC_ANGLE;
m[4] = fE;
m[5] = fF;
}
else
{
m[0] = fA;
m[1] = fB;
m[2] = fC;
m[3] = fD;
m[4] = fE;
m[5] = fF;
}
this.ClearCache();
};
this.GetGIDByUnicode = function(glyph)
{
var unGID = AscFonts.FT_SetCMapForCharCode(this.m_pFace, glyph);
if (unGID > 0)
return unGID;
if (-1 != this.m_nSymbolic && glyph < 0xF000)
unGID = AscFonts.FT_SetCMapForCharCode(this.m_pFace, glyph + 0xF000);
return unGID;
};
this.ShapeText = function(text, features, script, direction, language)
{
let buffer = [];
for (var iter = text.getUnicodeIterator(); iter.check(); iter.next())
{
buffer.push(iter.value());
}
return this.ShapeCodePointsArray(buffer, features, script, direction, language);
};
this.ShapeCodePointsArray = function(buffer, features, script, direction, language)
{
let segments = [];
let curFont = this;
let currentSegment = null;
for (let nPos = 0, nCount = buffer.length; nPos < nCount; ++nPos)
{
let codePoint = buffer[nPos];
// TODO: Обработать ситуацию, когда сегмент начинается с AscFonts.HB_SCRIPT.HB_SCRIPT_INHERITED
// в такой ситуации нужно ориентироваться на следующий юникод, у которого будет нормальный скрипт
if (AscFonts.HB_SCRIPT.HB_SCRIPT_INHERITED !== AscFonts.hb_get_script_by_unicode(codePoint))
{
let gid = this.GetGIDByUnicode(codePoint);
if (gid <= 0)
{
curFont = this.Picker.GetFontBySymbolWithSize(this, codePoint);
if (!curFont)
curFont = this;
}
else
{
curFont = this;
}
}
if (null == currentSegment || currentSegment.font !== curFont)
{
currentSegment = {
font: curFont,
text: AscCommon.encodeSurrogateChar(codePoint)
};
segments.push(currentSegment);
}
else
{
currentSegment.text += AscCommon.encodeSurrogateChar(codePoint);
}
}
for (let i = 0, len = segments.length; i < len; i++)
{
segments[i].glyphs = AscFonts.HB_Shape(segments[i].font, segments[i].text, features, script, direction, language);
// change to id???
segments[i].font = segments[i].font.m_pFaceInfo.family_name;
}
return segments;
};
this.CacheGlyph = function(glyph_index_or_unicode, isRaster, isRasterDistances, workerVector, workerVectorX, workerVectorY, isFromPicker)
{
var oSizes = new CFontCacheSizes();
oSizes.ushUnicode = glyph_index_or_unicode;
var nUnicodeForHintTest = this.m_bStringGID ? 0 : glyph_index_or_unicode;
var unGID = this.m_bStringGID ? glyph_index_or_unicode : AscFonts.FT_SetCMapForCharCode(this.m_pFace, glyph_index_or_unicode);
if (unGID <= 0 && !this.m_bStringGID)
{
if (-1 != this.m_nSymbolic && glyph_index_or_unicode < 0xF000)
unGID = AscFonts.FT_SetCMapForCharCode(this.m_pFace, glyph_index_or_unicode + 0xF000);
}
if (unGID <= 0)
{
if (isFromPicker === true)
return null;
if (!this.m_bStringGID && this.Picker)
{
// пробуем подобрать нужный шрифт
var oSizesCheck = this.Picker.LoadSymbol(this, glyph_index_or_unicode, isRaster, isRasterDistances, workerVector, workerVectorX, workerVectorY);
if (oSizesCheck)
return oSizesCheck;
}
if (this.m_nDefaultChar >= 0)
{
unGID = this.m_nDefaultChar;
oSizes.eState = EGlyphState.glyphstateDefault;
}
else
{
oSizes.eState = EGlyphState.glyphstateMiss;
oSizes.ushGID = -1;
oSizes.fAdvanceX = (AscFonts.FT_GetFaceMaxAdvanceX(this.m_pFace) >> 6) / 2.0;
return oSizes;
}
}
else
{
oSizes.eState = EGlyphState.glyphstateNormal;
}
oSizes.ushGID = unGID;
oSizes.nCMapIndex = 0; // TODO:???
//var measure_time_start = performance.now();
var load_mode = this.GetCharLoadMode(nUnicodeForHintTest);
if (!isRaster || this.m_bNeedDoBold || this.m_bNeedDoItalic)
load_mode |= AscFonts.FT_Load_Mode.FT_LOAD_NO_BITMAP;
else if (this.m_bStringGID)
{
if (!this.codePointsForGid || !this.codePointsForGid[0] || !AscFonts.isUseBitmapStrikes(this.codePointsForGid[0]))
load_mode |= AscFonts.FT_Load_Mode.FT_LOAD_NO_BITMAP;
}
else if (!AscFonts.isUseBitmapStrikes(glyph_index_or_unicode))
load_mode |= AscFonts.FT_Load_Mode.FT_LOAD_NO_BITMAP;
else
{
if (Math.abs(this.m_arrdTextMatrix[1]) > 0.001 || Math.abs(this.m_arrdTextMatrix[2]) > 0.001)
load_mode |= AscFonts.FT_Load_Mode.FT_LOAD_NO_BITMAP;
}
if (this.FT_Load_Glyph_Wrapper(this.m_pFace, unGID, load_mode))
{
oSizes.fAdvanceX = (AscFonts.FT_GetFaceMaxAdvanceX(this.m_pFace) >> 6) / 2.0;
return oSizes;
}
var _painter = null;
if (undefined !== workerVector)
{
_painter = new CGlyphVectorPainter();
_painter.KoefX = 25.4 / this.m_unHorDpi;
_painter.KoefY = 25.4 / this.m_unVerDpi;
if (workerVectorX !== undefined)
_painter.X = workerVectorX;
if (workerVectorY !== undefined)
_painter.Y = workerVectorY;
}
var measureInfo = AscFonts.FT_Glyph_Get_Measure(this.m_pFace, workerVector, _painter);
if ((null == measureInfo) || (undefined !== workerVector))
return oSizes;
//window.measureTime += (performance.now() - measure_time_start);
var isDisableNeedBold = ((this.m_pFaceInfo.os2_version != 0xFFFF) && (this.m_pFaceInfo.os2_usWeightClass >= 800)) ? true : false;
oSizes.fAdvanceX = (measureInfo.linearHoriAdvance * this.m_dUnitsKoef / this.m_lUnits_Per_Em);
if (this.m_bNeedDoBold && this.m_oFontManager.IsAdvanceNeedBoldFonts && !isDisableNeedBold)
oSizes.fAdvanceX += 1;
oSizes.oBBox.fMinX = (measureInfo.bbox_xMin >> 6);
oSizes.oBBox.fMaxX = (measureInfo.bbox_xMax >> 6);
oSizes.oBBox.fMinY = (measureInfo.bbox_yMin >> 6);
oSizes.oBBox.fMaxY = (measureInfo.bbox_yMax >> 6);
var dstM = oSizes.oMetrics;
dstM.fWidth = (measureInfo.width >> 6);
dstM.fHeight = (measureInfo.height >> 6);
dstM.fHoriBearingX = (measureInfo.horiBearingX >> 6);
dstM.fHoriBearingY = (measureInfo.horiBearingY >> 6);
dstM.fHoriAdvance = (measureInfo.horiAdvance >> 6);
dstM.fVertBearingX = (measureInfo.vertBearingX >> 6);
dstM.fVertBearingY = (measureInfo.vertBearingY >> 6);
dstM.fVertAdvance = (measureInfo.vertAdvance >> 6);
if (isFromPicker && (0 == dstM.fHoriAdvance && 0 == measureInfo.width))
{
if (this.m_bStringGID)
return null;
switch (glyph_index_or_unicode)
{
// список допустимых символов нулевой ширины
case 0xFEFF:
{
return oSizes;
}
default:
break;
}
return null;
}
if (!isRaster)
{
if (isRasterDistances)
{
var rasterInfo = AscFonts.FT_Glyph_Get_Raster(this.m_pFace, REND_MODE);
if (rasterInfo)
{
var rasterBitmap = AscFonts.FT_Get_Glyph_Render_Buffer(this.m_pFace, rasterInfo, false);
oSizes.oBBox.rasterDistances = get_raster_bounds_safe(rasterBitmap);
}
}
return oSizes;
}
//measure_time_start = performance.now();
oSizes.bBitmap = true;
var rasterInfo = AscFonts.FT_Glyph_Get_Raster(this.m_pFace, REND_MODE);
if (!rasterInfo || rasterInfo.pitch == 0)
return oSizes;
//window.rasterTime += (performance.now() - measure_time_start);
oSizes.oBitmap = new CGlyphBitmap();
oSizes.oBitmap.nX = rasterInfo.left;
oSizes.oBitmap.nY = rasterInfo.top;
oSizes.oBitmap.nWidth = rasterInfo.width;
oSizes.oBitmap.nHeight = rasterInfo.rows;
var rasterBitmap = AscFonts.FT_Get_Glyph_Render_Buffer(this.m_pFace, rasterInfo, true);
if (this.m_bNeedDoBold && this.m_bAntiAliasing && !isDisableNeedBold)
{
var extraPixels = AscCommon.AscBrowser.retinaPixelRatio >> 0;
if (extraPixels < 1)
extraPixels = 1;
oSizes.oBitmap.nWidth += extraPixels;
var _width_im = oSizes.oBitmap.nWidth;
var _height = oSizes.oBitmap.nHeight;
var nY, nX;
var pDstBuffer;
var _input = raster_memory.m_oBuffer.data;
while (extraPixels > 0)
{
--extraPixels;
for (nY = 0, pDstBuffer = 0; nY < _height; ++nY, pDstBuffer += (raster_memory.pitch))
{
var _pos_x = pDstBuffer + ((_width_im - extraPixels) << 2) - 1;
// последние - просто копируем
_input[_pos_x] = _input[_pos_x - 4];
_pos_x -= 4;
for (nX = _width_im - extraPixels - 2; nX > 0; --nX, _pos_x -= 4)
{
// сдвигаем все вправо
_input[_pos_x] = Math.min(255, _input[_pos_x - 4] + _input[_pos_x]);
}
}
}
}
oSizes.oBitmap.fromAlphaMask(this.m_oFontManager);
return oSizes;
};
this.GetString = function(pString)
{
if (pString.GetLength() <= 0)
return true;
var unPrevGID = 0;
var fPenX = 0, fPenY = 0;
// Сначала мы все рассчитываем исходя только из матрицы шрифта FontMatrix
if (this.m_bIsTransform)
this.UpdateMatrix();
var _cache_array = (this.m_bStringGID === false) ? this.m_arrCacheSizes : this.m_arrCacheSizesGid;
for (var nIndex = 0; nIndex < pString.GetLength(); ++nIndex)
{
var pCurGlyph = pString.GetAt(nIndex);
var ushUnicode = pCurGlyph.lUnicode;
var charSymbolObj = _cache_array[ushUnicode];
if (undefined == charSymbolObj)
{
_cache_array[ushUnicode] = this.CacheGlyph(ushUnicode, false);
charSymbolObj = _cache_array[ushUnicode];
}
var unGID = charSymbolObj.ushGID;
var eState = charSymbolObj.eState;
if (EGlyphState.glyphstateMiss == eState)
{
pString.SetStartPoint(nIndex, fPenX, fPenY);
pString.SetBBox(nIndex, 0, 0, 0, 0);
pString.SetState(nIndex, EGlyphState.glyphstateMiss);
fPenX += charSymbolObj.fAdvanceX + this.m_fCharSpacing;
unPrevGID = 0;
continue;
}
else if (EGlyphState.glyphstateDefault == eState)
{
pString.SetState(nIndex, EGlyphState.glyphstateDefault);
// kerning face!!!
}
else // if ( glyphstateNormal == eState )
{
pString.SetState(nIndex, EGlyphState.glyphstateNormal);
// kerning face!!!
}
/*
if (0 != this.m_nNum_charmaps)
{
var nCharmap = pFace.charmap;
var nCurCMapIndex = AscFonts.FT_Get_Charmap_Index(nCharmap);
if (nCurCMapIndex != _cmap_index)
{
_cmap_index = Math.max(0, _cmap_index);
nCharmap = pFace.charmaps[_cmap_index];
AscFonts.FT_Set_Charmap(pFace, nCharmap);
}
}
*/
if (this.m_bUseKerning && unPrevGID && (nIndex > 0 && pString.GetAt(nIndex).eState == pString.GetAt(nIndex - 1).eState))
{
fPenX += this.GetKerning(unPrevGID, unGID);
}
var fX = pString.m_fX + fPenX;
var fY = pString.m_fY + fPenY;
// Начальную точку рассчитываем сразу исходя из глобальной матрицы
var fXX = (pString.m_arrCTM[4] + fX * pString.m_arrCTM[0] + fY * pString.m_arrCTM[2] - pString.m_fX);
var fYY = (pString.m_arrCTM[5] + fX * pString.m_arrCTM[1] + fY * pString.m_arrCTM[3] - pString.m_fY);
pString.SetStartPoint(nIndex, fXX, fYY);
var _metrics = charSymbolObj.oMetrics;
pString.SetMetrics(nIndex, _metrics.fWidth, _metrics.fHeight, _metrics.fHoriAdvance, _metrics.fHoriBearingX, _metrics.fHoriBearingY, _metrics.fVertAdvance, _metrics.fVertBearingX, _metrics.fVertBearingY);
pString.SetBBox(nIndex, charSymbolObj.oBBox.fMinX, charSymbolObj.oBBox.fMaxY, charSymbolObj.oBBox.fMaxX, charSymbolObj.oBBox.fMinY);
fPenX += charSymbolObj.fAdvanceX + this.m_fCharSpacing;
unPrevGID = unGID;
}
pString.m_fEndX = fPenX + pString.m_fX;
pString.m_fEndY = fPenY + pString.m_fY;
};
this.GetString2 = function(pString)
{
if (pString.GetLength() <= 0)
return true;
if (this.m_bIsTransform)
this.UpdateMatrix();
var unPrevGID = 0;
var fPenX = 0, fPenY = 0;
var _cache_array = (this.m_bStringGID === false) ? this.m_arrCacheSizes : this.m_arrCacheSizesGid;
for (var nIndex = 0; nIndex < pString.GetLength(); ++nIndex)
{
var pCurGlyph = pString.GetAt(nIndex);
var ushUnicode = pCurGlyph.lUnicode;
var charSymbolObj = _cache_array[ushUnicode];
if (undefined == charSymbolObj || null == charSymbolObj.oBitmap)
{
_cache_array[ushUnicode] = this.CacheGlyph(ushUnicode, true);
charSymbolObj = _cache_array[ushUnicode];
}
var nCMapIndex = charSymbolObj.nCMapIndex;
var unGID = charSymbolObj.ushGID;
var eState = charSymbolObj.eState;
if (EGlyphState.glyphstateMiss == eState)
{
pString.SetStartPoint(nIndex, fPenX, fPenY);
pString.SetBBox(nIndex, 0, 0, 0, 0);
pString.SetState(nIndex, EGlyphState.glyphstateMiss);
fPenX += charSymbolObj.fAdvanceX + this.m_fCharSpacing;
unPrevGID = 0;
continue;
}
else if (EGlyphState.glyphstateDefault == eState)
{
pString.SetState(nIndex, EGlyphState.glyphstateDefault);
// kerning face!!!
}
else
{
pString.SetState(nIndex, EGlyphState.glyphstateNormal);
// kerning face!!!
}
/*
if (0 != this.m_nNum_charmaps)
{
var nCharmap = pFace.charmap;
var nCurCMapIndex = AscFonts.FT_Get_Charmap_Index(nCharmap);
if (nCurCMapIndex != nCMapIndex)
{
nCMapIndex = Math.max(0, nCMapIndex);
nCharmap = this.m_pFace.charmaps[nCMapIndex];
AscFonts.FT_Set_Charmap(this.m_pFace, nCharmap);
}
}
*/
if (this.m_bUseKerning && unPrevGID && (nIndex > 0 && pString.GetAt(nIndex).eState == pString.GetAt(nIndex - 1).eState))
{
fPenX += this.GetKerning(unPrevGID, unGID);
}
var fX = pString.m_fX + fPenX;
var fY = pString.m_fY + fPenY;
// Начальную точку рассчитываем сразу исходя из глобальной матрицы
var fXX = (pString.m_arrCTM[4] + fX * pString.m_arrCTM[0] + fY * pString.m_arrCTM[2] - pString.m_fX);
var fYY = (pString.m_arrCTM[5] + fX * pString.m_arrCTM[1] + fY * pString.m_arrCTM[3] - pString.m_fY);
pString.SetStartPoint(nIndex, fXX, fYY);
pCurGlyph.oMetrics = charSymbolObj.oMetrics;
pString.SetBBox(nIndex, charSymbolObj.oBBox.fMinX, charSymbolObj.oBBox.fMaxY, charSymbolObj.oBBox.fMaxX, charSymbolObj.oBBox.fMinY);
fPenX += charSymbolObj.fAdvanceX + this.m_fCharSpacing;
pCurGlyph.bBitmap = charSymbolObj.bBitmap;
pCurGlyph.oBitmap = charSymbolObj.oBitmap;
unPrevGID = unGID;
}
pString.m_fEndX = fPenX + pString.m_fX;
pString.m_fEndY = fPenY + pString.m_fY;
};
this.GetString2C = function(pString)
{
// Сначала мы все рассчитываем исходя только из матрицы шрифта FontMatrix
if (this.m_bIsTransform)
this.UpdateMatrix();
var pCurGlyph = pString.m_pGlyphsBuffer[0];
var ushUnicode = pCurGlyph.lUnicode;
var _cache_array = (this.m_bStringGID === false) ? this.m_arrCacheSizes : this.m_arrCacheSizesGid;
var charSymbolObj = _cache_array[ushUnicode];
if (undefined == charSymbolObj || (null == charSymbolObj.oBitmap && charSymbolObj.bBitmap === false))
{
_cache_array[ushUnicode] = this.CacheGlyph(ushUnicode, true);
charSymbolObj = _cache_array[ushUnicode];
}
if (!charSymbolObj)
return;
var eState = charSymbolObj.eState;
pCurGlyph.eState = charSymbolObj.eState;
if (EGlyphState.glyphstateMiss == eState)
{
pCurGlyph.fX = 0;
pCurGlyph.fY = 0;
pCurGlyph.fLeft = 0;
pCurGlyph.fTop = 0;
pCurGlyph.fRight = 0;
pCurGlyph.fBottom = 0;
return;
}
// кернинга нету пока.
var fX = pString.m_fX;
var fY = pString.m_fY;
var _m = pString.m_arrCTM;
// Начальную точку рассчитываем сразу исходя из глобальной матрицы
pCurGlyph.fX = (_m[4] + fX * _m[0] + fY * _m[2] - pString.m_fX);
pCurGlyph.fY = (_m[5] + fX * _m[1] + fY * _m[3] - pString.m_fY);
//pString.SetMetrics(nIndex, charSymbolObj.oMetrics.fWidth, charSymbolObj.oMetrics.fHeight, charSymbolObj.oMetrics.fHoriAdvance, charSymbolObj.oMetrics.fHoriBearingX, charSymbolObj.oMetrics.fHoriBearingY, charSymbolObj.oMetrics.fVertAdvance, charSymbolObj.oMetrics.fVertBearingX, charSymbolObj.oMetrics.fVertBearingY);
pCurGlyph.oMetrics = charSymbolObj.oMetrics;
/*
pCurGlyph.fLeft = charSymbolObj.oBBox.fMinX;
pCurGlyph.fTop = charSymbolObj.oBBox.fMaxY;
pCurGlyph.fRight = charSymbolObj.oBBox.fMaxX;
pCurGlyph.fBottom = charSymbolObj.oBBox.fMinY;
*/
pCurGlyph.bBitmap = charSymbolObj.bBitmap;
pCurGlyph.oBitmap = charSymbolObj.oBitmap;
pString.m_fEndX = charSymbolObj.fAdvanceX + this.m_fCharSpacing + pString.m_fX;
pString.m_fEndY = pString.m_fY;
};
this.GetChar = function(lUnicode, is_raster_distances)
{
var Result = undefined;
var ushUnicode = lUnicode;
// Сначала мы все рассчитываем исходя только из матрицы шрифта FontMatrix
if (this.m_bIsTransform)
this.UpdateMatrix();
var _cache_array = (this.m_bStringGID === false) ? this.m_arrCacheSizes : this.m_arrCacheSizesGid;
var charSymbolObj = _cache_array[ushUnicode];
if (undefined == charSymbolObj)
{
_cache_array[ushUnicode] = this.CacheGlyph(ushUnicode, false, is_raster_distances);
charSymbolObj = _cache_array[ushUnicode];
}
return charSymbolObj;
};
this.GetCharPath = function(lUnicode, worker, x, y)
{
var pFace = this.m_pFace;
var pCurentGliph = pFace.glyph;
var Result;
var ushUnicode = lUnicode;
// Сначала мы все рассчитываем исходя только из матрицы шрифта FontMatrix
if (this.m_bIsTransform)
this.UpdateMatrix();
// no really cashe
this.CacheGlyph(ushUnicode, false, false, worker, x, y);
};
this.GetStringPath = function(string, worker)
{
var _len = string.GetLength();
if (_len <= 0)
return true;
for (var nIndex = 0; nIndex < _len; ++nIndex)
{
var _glyph = string.m_pGlyphsBuffer[nIndex];
var _x = string.m_fX + 25.4 * _glyph.fX / this.m_unHorDpi;
var _y = string.m_fY + 25.4 * _glyph.fY / this.m_unVerDpi;
worker._s();
this.GetCharPath(_glyph.lUnicode, worker, _x, _y);
worker.df();
worker._e();
}
};
this.GetCharLoadMode = function(code)
{
if (this.HintsSupport && this.HintsSubpixelSupport)
{
// -----------------------------------------------------------------
// заглушки
if (code === 95 && this.m_pFaceInfo.family_name === "Wingdings 3")
return AscFonts.LOAD_MODE_DEFAULT;
// -----------------------------------------------------------------
return this.m_oFontManager.LOAD_MODE;
}
return AscFonts.LOAD_MODE_DEFAULT;
};
this.GetKerning = function(unPrevGID, unGID)
{
var delta = AscFonts.FT_GetKerningX(this.m_pFace, unPrevGID, unGID);
return (delta >> 6);
};
this.SetStringGID = function(bGID)
{
if (this.m_bStringGID == bGID)
return;
this.m_bStringGID = bGID;
};
this.GetStringGID = function()
{
return this.m_bStringGID;
};
this.SetCharSpacing = function(fCharSpacing)
{
this.m_fCharSpacing = fCharSpacing;
};
this.GetCharSpacing = function()
{
return this.m_fCharSpacing;
};
this.GetStyleName = function()
{
return this.m_pFaceInfo.style_name;
};
this.GetFamilyName = function()
{
return this.m_pFaceInfo.family_name;
};
this.UpdateStyles = function(bBold, bItalic)
{
var sStyle = this.GetStyleName();
// Смотрим какой стиль у исходного шрифта
var bSrcBold = (-1 != sStyle.indexOf("Bold"));
var bSrcItalic = (-1 != sStyle.indexOf("Italic"));
this.SetNeedBold(bBold && !bSrcBold);
this.SetNeedItalic(bItalic && !bSrcItalic);
};
this.IsBold = function()
{
if (this.m_bNeedDoBold)
return true;
return (-1 != this.m_pFaceInfo.style_name.indexOf("Bold")) ? true : false;
};
this.IsItalic = function()
{
if (this.m_bNeedDoItalic)
return true;
return (-1 != this.m_pFaceInfo.style_name.indexOf("Italic")) ? true : false;
};
this.SetNeedItalic = function(value)
{
if (this.m_bNeedDoItalic != value)
{
this.ClearCache();
this.m_bNeedDoItalic = value;
this.ResetFontMatrix();
}
};
this.SetNeedBold = function(value)
{
if (this.m_bNeedDoBold != value)
{
this.ClearCache();
this.m_bNeedDoBold = value;
}
};
this.IsSuccess = function()
{
return (0 == this.m_nError);
};
this.GetAscender = function()
{
return this.m_lAscender;
};
this.GetDescender = function()
{
return this.m_lDescender;
};
this.GetHeight = function()
{
return this.m_lLineHeight;
};
this.Units_Per_Em = function()
{
return this.m_lUnits_Per_Em;
};
this.CheckHintsSupport = function()
{
this.HintsSupport = true;
this.HintsSubpixelSupport = true;
};
this.cellGetMetrics = function()
{
var face = this.m_pFaceInfo;
var ret = [];
ret.push(face.units_per_EM);
if (face.os2_version != 0xFFFF)
{
ret.push(face.os2_usWinAscent);
ret.push(-face.os2_usWinDescent);
}
else
{
ret.push(face.header_yMax);
ret.push(face.header_yMin);
}
return ret;
};
this.GetLimitsY = function()
{
return {
min : this.m_pFaceInfo.header_yMin,
max : this.m_pFaceInfo.header_yMax
};
};
this.SetFace = function(face, fontManager)
{
this.m_pFace = face;
this.m_pFaceInfo = new AscFonts.CFaceInfo();
this.m_pFaceInfo.load(this.m_pFace);
this.m_lUnits_Per_Em = this.m_pFaceInfo.units_per_EM;
this.m_lAscender = this.m_pFaceInfo.ascender;
this.m_lDescender = this.m_pFaceInfo.descender;
this.m_lLineHeight = this.m_pFaceInfo.height;
if (fontManager.IsUseWinOS2Params && this.m_pFaceInfo.os2_version != 0xFFFF)
{
if (fontManager.Mode === AscFonts.TextMeasureMode.Cell)
{
/*
// что-то типо этого в экселе... пока выключаем
var _addidive = (0.15 * font.m_lLineHeight) >> 0;
font.m_lAscender += ((_addidive + 1) >> 1);
font.m_lDescender -= (_addidive >> 1);
font.m_lLineHeight += _addidive;
*/
var _winAscent = this.m_pFaceInfo.os2_usWinAscent;
var _winDescent = -this.m_pFaceInfo.os2_usWinDescent;
// experimantal: for cjk fonts lineheight *= 1.3
if ((this.m_pFaceInfo.os2_ulUnicodeRange2 & 0x2DF00000) != 0)
{
var _addidive = (0.3 * (_winAscent - _winDescent)) >> 0;
_winAscent += ((_addidive + 1) >> 1);
_winDescent -= (_addidive >> 1);
}
// TODO:
// https://www.microsoft.com/typography/otspec/recom.htm - hhea, not typo!!!
if (this.m_pFaceInfo.height < (_winAscent - _winDescent))
{
this.m_lAscender = _winAscent;
this.m_lDescender = _winDescent;
this.m_lLineHeight = _winAscent - _winDescent;
}
}
else
{
// Здесь все подобрано после многочисленных тестов, если будет что-то меняться, то все шрифты
// надо проверять заново
let faceInfo = this.m_pFaceInfo;
let nAscent = faceInfo.os2_usWinAscent;
let nDescent = -faceInfo.os2_usWinDescent;
let nLineGap = 0;
if (faceInfo.os2_fsSelection & 128 || faceInfo.family_name === "Cambria Math")
{
nAscent = faceInfo.os2_sTypoAscender;
nDescent = faceInfo.os2_sTypoDescender;
nLineGap = faceInfo.os2_sTypoLineGap;
}
if (AscFonts.TextMeasureMode.Word === fontManager.Mode
&& faceInfo.os2_ulCodePageRange1 & 0x1e0000)
{
this.m_lLineHeight = ((nAscent - nDescent) * 1.3) | 0;
this.m_lDescender = (nDescent - (nAscent - nDescent) * 0.15) | 0;
this.m_lAscender = this.m_lLineHeight + this.m_lDescender;
}
else
{
this.m_lLineHeight = Math.max(this.m_lLineHeight, nAscent - nDescent + nLineGap);
this.m_lAscender = nAscent;
this.m_lDescender = nDescent;
}
}
}
this.m_nNum_charmaps = this.m_pFaceInfo.num_charmaps;
this.m_nDefaultChar = this.m_pFaceInfo.os2_usDefaultChar;
this.m_nSymbolic = this.m_pFaceInfo.os2_nSymbolic;
this.m_nError = AscFonts.FT_Set_Char_Size(face, 0, this.m_fSize * 64, 0, 0);
this.ResetTextMatrix();
this.ResetFontMatrix();
if (true === fontManager.m_bUseKerning)
{
this.m_bUseKerning = ((this.m_pFaceInfo.face_flags & 64) != 0 ? true : false);
}
if (0 != this.m_pFaceInfo.monochromeSizes.length)
{
this.fixed_sizes = [];
for (var i = this.m_pFaceInfo.monochromeSizes.length - 1; i >= 0; i--)
{
this.fixed_sizes[this.m_pFaceInfo.monochromeSizes[i] >> 6] = true;
}
}
}
}
CFontFile.prototype["GetFace"] = function()
{
return this.m_pFace;
};
CFontFile.prototype["GetHBFont"] = function()
{
return this.m_pHBFont;
};
CFontFile.prototype["SetHBFont"] = function(font)
{
this.m_pHBFont = font;
};
function CFontLoaderBySymbol()
{
this.FontFiles = {};
this.GetFontBySymbol = function(pFontFile, symbol)
{
var fontManager = pFontFile.m_oFontManager;
var name = AscFonts.FontPickerByCharacter.getFontBySymbol(symbol);
if (undefined === name || name == "")
return null;
var _fontFilePick = this.FontFiles[name];
if (!_fontFilePick)
{
var _font_info = AscFonts.g_font_infos[AscFonts.g_map_font_index[name]];
var _style = AscFonts.FontStyle.FontStyleRegular;
if (pFontFile.IsBold())
_style |= AscFonts.FontStyle.FontStyleBold;
if (pFontFile.IsItalic())
_style |= AscFonts.FontStyle.FontStyleItalic;
_fontFilePick = _font_info.LoadFont(AscCommon.g_font_loader, fontManager, pFontFile.m_fSize, _style, pFontFile.m_unHorDpi, pFontFile.m_unVerDpi, undefined, true);
if (!_fontFilePick)
return null;
_fontFilePick.CheckHintsSupport();
this.FontFiles[name] = _fontFilePick;
}
return _fontFilePick;
};
this.GetFontBySymbolWithSize = function(pFontFile, symbol)
{
var _fontFilePick = this.GetFontBySymbol(pFontFile, symbol);
if (!_fontFilePick)
return null;
_fontFilePick.SetSizeAndDpi(pFontFile.m_fSize, pFontFile.m_unHorDpi, pFontFile.m_unVerDpi);
var s = pFontFile.m_arrdTextMatrix;
var d = _fontFilePick.m_arrdTextMatrix;
d[0] = s[0];
d[1] = s[1];
d[2] = s[2];
d[3] = s[3];
d[4] = s[4];
d[5] = s[5];
_fontFilePick.UpdateMatrix();
return _fontFilePick;
};
this.LoadSymbol = function(pFontFile, symbol, isRaster, isRasterDistances, workerVector, workerVectorX, workerVectorY, isFromPicker)
{
var _fontFilePick = this.GetFontBySymbolWithSize(pFontFile, symbol);
if (!_fontFilePick)
return null;
return _fontFilePick.CacheGlyph(symbol, isRaster, isRasterDistances, workerVector, workerVectorX, workerVectorY, true);
};
this.ClearCache = function()
{
if (this.FontClearCache_checker)
return;
this.FontClearCache_checker = true;
for (var font in this.FontFiles)
this.FontFiles[font].ClearCache();
delete this.FontClearCache_checker;
};
this.ClearCacheNoAttack = function()
{
if (this.FontClearCacheNoAttack_checker)
return;
this.FontClearCacheNoAttack_checker = true;
for (var font in this.FontFiles)
this.FontFiles[font].ClearCacheNoAttack();
delete this.FontClearCacheNoAttack_checker;
};
}
window['AscFonts'].EGlyphState = EGlyphState;
window['AscFonts'].CFontFile = CFontFile;
})(window);