589 lines
13 KiB
JavaScript
589 lines
13 KiB
JavaScript
/*
|
|
* (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) {
|
|
|
|
function CFontManagerEngine()
|
|
{
|
|
this.library = AscFonts.FT_CreateLibrary();
|
|
this.manager = null;
|
|
|
|
this.openFont = function(stream, faceindex)
|
|
{
|
|
var face = AscFonts.FT_Open_Face(this.library, stream, faceindex);
|
|
if (!face)
|
|
return null;
|
|
|
|
var font = new AscFonts.CFontFile();
|
|
font.SetFace(face, this.manager);
|
|
|
|
if (!font.IsSuccess())
|
|
{
|
|
font = null;
|
|
face = null;
|
|
return null;
|
|
}
|
|
|
|
return font;
|
|
};
|
|
|
|
this.setHintsProps = function(bIsHinting, bIsSubpixHinting)
|
|
{
|
|
var REND_MODE_SUBPIX = (bIsHinting && bIsSubpixHinting) ? AscFonts.TT_INTERPRETER_VERSION_40 : AscFonts.TT_INTERPRETER_VERSION_35;
|
|
this.manager.LOAD_MODE = bIsHinting ? AscFonts.LOAD_MODE_HINTING : AscFonts.LOAD_MODE_DEFAULT;
|
|
|
|
AscFonts.FT_Set_TrueType_HintProp(this.library, REND_MODE_SUBPIX);
|
|
};
|
|
|
|
this.destroy = function()
|
|
{
|
|
AscFonts.FT_Done_Library(this.library);
|
|
};
|
|
}
|
|
|
|
function CFontFilesCache()
|
|
{
|
|
this.m_lMaxSize = 1000;
|
|
this.m_lCurrentSize = 0;
|
|
this.Fonts = {};
|
|
|
|
this.LoadFontFile = function(stream_index, name, faceindex, fontManager)
|
|
{
|
|
if (!fontManager._engine)
|
|
{
|
|
fontManager._engine = new CFontManagerEngine();
|
|
fontManager._engine.manager = fontManager;
|
|
fontManager._engine.setHintsProps(fontManager.bIsHinting, fontManager.bIsSubpixHinting);
|
|
}
|
|
|
|
// correct native stream
|
|
if (AscFonts.CreateNativeStreamByIndex)
|
|
AscFonts.CreateNativeStreamByIndex(stream_index);
|
|
|
|
if (!AscFonts.g_fonts_streams[stream_index])
|
|
return null;
|
|
|
|
return fontManager._engine.openFont(AscFonts.g_fonts_streams[stream_index], faceindex);
|
|
};
|
|
|
|
this.LockFont = function(stream_index, fontName, faceIndex, fontSize, _ext, fontManager)
|
|
{
|
|
var key = fontName + faceIndex + fontSize;
|
|
if (undefined !== _ext)
|
|
key += _ext;
|
|
var pFontFile = this.Fonts[key];
|
|
if (pFontFile)
|
|
return pFontFile;
|
|
|
|
pFontFile = this.Fonts[key] = this.LoadFontFile(stream_index, fontName, faceIndex, fontManager);
|
|
return pFontFile;
|
|
};
|
|
}
|
|
|
|
AscFonts.TextMeasureMode = {
|
|
Word : 0,
|
|
Cell : 1,
|
|
Slide : 2
|
|
};
|
|
|
|
// params: { mode: "cell" };
|
|
function CFontManager(params)
|
|
{
|
|
this._engine = null;
|
|
|
|
this.m_pFont = null;
|
|
this.m_oGlyphString = new AscFonts.CGlyphString();
|
|
|
|
this.error = 0;
|
|
|
|
this.fontName = undefined;
|
|
|
|
this.m_fCharSpacing = 0.0;
|
|
this.m_bStringGID = false;
|
|
|
|
this.m_oFontsCache = null;
|
|
|
|
this.m_lUnits_Per_Em = 0;
|
|
this.m_lAscender = 0;
|
|
this.m_lDescender = 0;
|
|
this.m_lLineHeight = 0;
|
|
|
|
this.RasterMemory = null;
|
|
|
|
this.Mode = AscFonts.TextMeasureMode.Word;
|
|
this.IsAdvanceNeedBoldFonts = false;
|
|
|
|
this.IsUseWinOS2Params = true;
|
|
|
|
this.bIsHinting = false;
|
|
this.bIsSubpixHinting = false;
|
|
|
|
this.LOAD_MODE = 40970;
|
|
|
|
this.SetParams(params);
|
|
}
|
|
|
|
CFontManager.prototype =
|
|
{
|
|
SetParams : function(params)
|
|
{
|
|
if (params)
|
|
{
|
|
switch (params.mode)
|
|
{
|
|
case "cell":
|
|
this.Mode = AscFonts.TextMeasureMode.Cell;
|
|
break;
|
|
case "slide":
|
|
this.Mode = AscFonts.TextMeasureMode.Slide;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
this.IsAdvanceNeedBoldFonts = (AscFonts.TextMeasureMode.Cell === this.Mode) ? true : false;
|
|
},
|
|
|
|
AfterLoad : function()
|
|
{
|
|
if (null == this.m_pFont)
|
|
{
|
|
this.m_lUnits_Per_Em = 0;
|
|
this.m_lAscender = 0;
|
|
this.m_lDescender = 0;
|
|
this.m_lLineHeight = 0;
|
|
}
|
|
else
|
|
{
|
|
var f = this.m_pFont;
|
|
this.m_lUnits_Per_Em = f.m_lUnits_Per_Em;
|
|
this.m_lAscender = f.m_lAscender;
|
|
this.m_lDescender = f.m_lDescender;
|
|
this.m_lLineHeight = f.m_lLineHeight;
|
|
|
|
f.CheckHintsSupport();
|
|
}
|
|
},
|
|
|
|
Initialize : function(is_init_raster_memory)
|
|
{
|
|
this.m_oFontsCache = new CFontFilesCache();
|
|
|
|
if (is_init_raster_memory === true)
|
|
{
|
|
AscFonts.registeredFontManagers.push(this);
|
|
this.InitializeRasterMemory();
|
|
}
|
|
},
|
|
|
|
InitializeRasterMemory : function()
|
|
{
|
|
if (AscFonts.use_map_blitting)
|
|
{
|
|
if (!this.RasterMemory)
|
|
{
|
|
this.RasterMemory = new AscFonts.CRasterHeapTotal();
|
|
this.RasterMemory.CreateFirstChuck();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (this.RasterMemory)
|
|
{
|
|
this.RasterMemory = null;
|
|
}
|
|
}
|
|
},
|
|
|
|
ClearFontsRasterCache : function()
|
|
{
|
|
for (var i in this.m_oFontsCache.Fonts)
|
|
{
|
|
if (this.m_oFontsCache.Fonts[i])
|
|
this.m_oFontsCache.Fonts[i].ClearCache();
|
|
}
|
|
this.ClearRasterMemory();
|
|
},
|
|
|
|
ClearRasterMemory : function()
|
|
{
|
|
// быстрая очистка всей памяти (убирание всех дыр)
|
|
if (null == this.RasterMemory || null == this.m_oFontsCache)
|
|
return;
|
|
|
|
var _fonts = this.m_oFontsCache.Fonts;
|
|
for (var i in _fonts)
|
|
{
|
|
if (_fonts[i] !== undefined && _fonts[i] != null)
|
|
_fonts[i].ClearCacheNoAttack();
|
|
}
|
|
|
|
this.RasterMemory.Clear();
|
|
},
|
|
|
|
UpdateSize : function(dOldSize, dDpi, dNewDpi)
|
|
{
|
|
if (0 == dNewDpi)
|
|
dNewDpi = 72.0;
|
|
if (0 == dDpi)
|
|
dDpi = 72.0;
|
|
|
|
return dOldSize * dDpi / dNewDpi;
|
|
},
|
|
|
|
LoadString : function(wsBuffer, fX, fY)
|
|
{
|
|
if (!this.m_pFont)
|
|
return false;
|
|
|
|
this.m_oGlyphString.SetString(wsBuffer, fX, fY);
|
|
this.m_pFont.GetString(this.m_oGlyphString);
|
|
|
|
return true;
|
|
},
|
|
|
|
LoadString2 : function(wsBuffer, fX, fY)
|
|
{
|
|
if (!this.m_pFont)
|
|
return false;
|
|
|
|
this.m_oGlyphString.SetString(wsBuffer, fX, fY);
|
|
this.m_pFont.GetString2(this.m_oGlyphString);
|
|
|
|
return true;
|
|
},
|
|
|
|
LoadString3 : function(gid, fX, fY)
|
|
{
|
|
if (!this.m_pFont)
|
|
return false;
|
|
|
|
this.SetStringGID(true);
|
|
this.m_oGlyphString.SetStringGID (gid, fX, fY);
|
|
this.m_pFont.GetString2(this.m_oGlyphString);
|
|
this.SetStringGID(false);
|
|
|
|
return true;
|
|
},
|
|
|
|
LoadString3C : function(gid, fX, fY, codepoints)
|
|
{
|
|
if (!this.m_pFont)
|
|
return false;
|
|
|
|
this.SetStringGID(true);
|
|
|
|
// это SetString
|
|
var string = this.m_oGlyphString;
|
|
this.m_pFont.codePointsForGid = codepoints;
|
|
|
|
string.m_fX = fX + string.m_fTransX;
|
|
string.m_fY = fY + string.m_fTransY;
|
|
|
|
string.m_nGlyphsCount = 1;
|
|
string.m_nGlyphIndex = 0;
|
|
|
|
var _g = string.GetFirstGlyph();
|
|
_g.bBitmap = false;
|
|
_g.oBitmap = null;
|
|
_g.eState = AscFonts.EGlyphState.glyphstateNormal;
|
|
_g.lUnicode = gid;
|
|
|
|
this.m_pFont.GetString2C(string);
|
|
|
|
this.SetStringGID(false);
|
|
|
|
this.m_pFont.codePointsForGid = undefined;
|
|
return true;
|
|
},
|
|
|
|
LoadString2C : function(wsBuffer, fX, fY)
|
|
{
|
|
if (!this.m_pFont)
|
|
return false;
|
|
|
|
// это SetString
|
|
var string = this.m_oGlyphString;
|
|
|
|
string.m_fX = fX + string.m_fTransX;
|
|
string.m_fY = fY + string.m_fTransY;
|
|
|
|
string.m_nGlyphsCount = 1;
|
|
string.m_nGlyphIndex = 0;
|
|
|
|
var _g = string.GetFirstGlyph();
|
|
_g.bBitmap = false;
|
|
_g.oBitmap = null;
|
|
_g.eState = AscFonts.EGlyphState.glyphstateNormal;
|
|
_g.lUnicode = wsBuffer.charCodeAt(0);
|
|
|
|
this.m_pFont.GetString2C(string);
|
|
return string.m_fEndX;
|
|
},
|
|
|
|
LoadString4C : function(lUnicode, fX, fY)
|
|
{
|
|
if (!this.m_pFont)
|
|
return false;
|
|
|
|
// это SetString
|
|
var string = this.m_oGlyphString;
|
|
|
|
string.m_fX = fX + string.m_fTransX;
|
|
string.m_fY = fY + string.m_fTransY;
|
|
|
|
string.m_nGlyphsCount = 1;
|
|
string.m_nGlyphIndex = 0;
|
|
|
|
var _g = string.GetFirstGlyph();
|
|
_g.bBitmap = false;
|
|
_g.oBitmap = null;
|
|
_g.eState = AscFonts.EGlyphState.glyphstateNormal;
|
|
_g.lUnicode = lUnicode;
|
|
|
|
this.m_pFont.GetString2C(string);
|
|
return string.m_fEndX;
|
|
},
|
|
|
|
LoadStringPathCode : function(code, isGid, fX, fY, worker)
|
|
{
|
|
if (!this.m_pFont)
|
|
return false;
|
|
|
|
this.SetStringGID(isGid);
|
|
|
|
// это SetString
|
|
var string = this.m_oGlyphString;
|
|
|
|
string.m_fX = fX + string.m_fTransX;
|
|
string.m_fY = fY + string.m_fTransY;
|
|
|
|
string.m_nGlyphsCount = 1;
|
|
string.m_nGlyphIndex = 0;
|
|
|
|
var _g = string.GetFirstGlyph();
|
|
_g.bBitmap = false;
|
|
_g.oBitmap = null;
|
|
_g.eState = AscFonts.EGlyphState.glyphstateNormal;
|
|
_g.lUnicode = code;
|
|
|
|
this.m_pFont.GetStringPath(string, worker);
|
|
|
|
this.SetStringGID(false);
|
|
|
|
return true;
|
|
},
|
|
|
|
LoadChar : function(lUnicode)
|
|
{
|
|
if (!this.m_pFont)
|
|
return false;
|
|
|
|
return this.m_pFont.GetChar2(lUnicode);
|
|
},
|
|
|
|
MeasureChar : function(lUnicode, is_raster_distances)
|
|
{
|
|
if (!this.m_pFont)
|
|
return;
|
|
|
|
return this.m_pFont.GetChar(lUnicode, is_raster_distances);
|
|
},
|
|
|
|
GetKerning : function(unPrevGID, unGID)
|
|
{
|
|
if (!this.m_pFont)
|
|
return;
|
|
|
|
return this.m_pFont.GetKerning(unPrevGID, unGID);
|
|
},
|
|
|
|
MeasureString : function()
|
|
{
|
|
var oPoint = new AscFonts.CGlyphRect();
|
|
var len = this.m_oGlyphString.GetLength();
|
|
if (len <= 0)
|
|
return oPoint;
|
|
|
|
var fTop = 0xFFFF, fBottom = -0xFFFF, fLeft = 0xFFFF, fRight = -0xFFFF;
|
|
for (var nIndex = 0; nIndex < len; ++nIndex)
|
|
{
|
|
var oSizeTmp = this.m_oGlyphString.GetBBox (nIndex);
|
|
|
|
if (fBottom < oSizeTmp.fBottom)
|
|
fBottom = oSizeTmp.fBottom;
|
|
|
|
if (fTop > oSizeTmp.fTop)
|
|
fTop = oSizeTmp.fTop;
|
|
|
|
if (fLeft > oSizeTmp.fLeft)
|
|
fLeft = oSizeTmp.fLeft;
|
|
|
|
if (fRight < oSizeTmp.fRight)
|
|
fRight = oSizeTmp.fRight;
|
|
}
|
|
|
|
oPoint.fX = fLeft;
|
|
oPoint.fY = fTop;
|
|
|
|
oPoint.fWidth = Math.abs((fRight - fLeft));
|
|
oPoint.fHeight = Math.abs((fTop - fBottom));
|
|
|
|
return oPoint;
|
|
},
|
|
|
|
MeasureString2 : function()
|
|
{
|
|
var oPoint = new AscFonts.CGlyphRect();
|
|
|
|
if (this.m_oGlyphString.GetLength() <= 0)
|
|
return oPoint;
|
|
|
|
var oSizeTmp = this.m_oGlyphString.GetBBox2();
|
|
|
|
oPoint.fX = oSizeTmp.fLeft;
|
|
oPoint.fY = oSizeTmp.fTop;
|
|
|
|
oPoint.fWidth = Math.abs((oSizeTmp.fRight - oSizeTmp.fLeft));
|
|
oPoint.fHeight = Math.abs((oSizeTmp.fTop - oSizeTmp.fBottom));
|
|
|
|
return oPoint;
|
|
},
|
|
|
|
GetNextChar2 : function()
|
|
{
|
|
return this.m_oGlyphString.GetNext();
|
|
},
|
|
|
|
IsSuccess : function()
|
|
{
|
|
return (0 == this.error);
|
|
},
|
|
|
|
SetTextMatrix : function(fA, fB, fC, fD, fE, fF)
|
|
{
|
|
if (!this.m_pFont)
|
|
return false;
|
|
|
|
if (this.m_pFont.SetTextMatrix (fA, fB, fC, fD, 0, 0))
|
|
this.m_oGlyphString.SetCTM(fA, fB, fC, fD, 0, 0);
|
|
this.m_oGlyphString.SetTrans(fE, fF);
|
|
|
|
return true;
|
|
},
|
|
|
|
SetTextMatrix2 : function(fA, fB, fC, fD, fE, fF)
|
|
{
|
|
if (!this.m_pFont)
|
|
return false;
|
|
|
|
this.m_pFont.SetTextMatrix (fA, fB, fC, fD, 0, 0);
|
|
this.m_oGlyphString.SetCTM(fA, fB, fC, fD, 0, 0);
|
|
this.m_oGlyphString.SetTrans(fE, fF);
|
|
|
|
return true;
|
|
},
|
|
|
|
SetStringGID : function(bStringGID)
|
|
{
|
|
this.m_bStringGID = bStringGID;
|
|
|
|
if (!this.m_pFont)
|
|
return;
|
|
|
|
this.m_pFont.SetStringGID(this.m_bStringGID);
|
|
},
|
|
|
|
SetHintsProps : function(bIsHinting, bIsSubpixHinting)
|
|
{
|
|
this.bIsHinting = bIsHinting;
|
|
this.bIsSubpixHinting = bIsSubpixHinting;
|
|
|
|
if (this._engine)
|
|
this._engine.setHintsProps(bIsHinting, bIsSubpixHinting);
|
|
|
|
this.ClearFontsRasterCache();
|
|
},
|
|
|
|
SetAdvanceNeedBoldFonts : function(value)
|
|
{
|
|
this.IsAdvanceNeedBoldFonts = value;
|
|
},
|
|
|
|
LoadFont : function(fontFile, faceIndex, size, isBold, isItalic, needBold, needItalic, isNoSetupToManager)
|
|
{
|
|
var _ext = "";
|
|
if (needBold)
|
|
_ext += "nbold";
|
|
if (needItalic)
|
|
_ext += "nitalic";
|
|
|
|
var pFontFile = this.m_oFontsCache.LockFont(fontFile.stream_index, fontFile.Id, faceIndex, size, _ext, this);
|
|
if (!pFontFile)
|
|
return null;
|
|
|
|
pFontFile.m_oFontManager = this;
|
|
|
|
pFontFile.SetNeedBold(needBold);
|
|
pFontFile.SetNeedItalic(needItalic);
|
|
|
|
pFontFile.SetStringGID(this.m_bStringGID);
|
|
pFontFile.SetCharSpacing(this.m_fCharSpacing);
|
|
|
|
if (isNoSetupToManager !== true)
|
|
{
|
|
this.m_pFont = pFontFile;
|
|
this.m_oGlyphString.ResetCTM();
|
|
this.AfterLoad();
|
|
}
|
|
|
|
return pFontFile;
|
|
},
|
|
|
|
GetLimitsY : function()
|
|
{
|
|
if (this.m_pFont)
|
|
return this.m_pFont.GetLimitsY();
|
|
return {
|
|
min : 0,
|
|
max : 0
|
|
};
|
|
}
|
|
}
|
|
|
|
window['AscFonts'].CFontManager = CFontManager;
|
|
window['AscFonts'].CFontFilesCache = CFontFilesCache;
|
|
})(window);
|