Files
Yajbir Singh f1b860b25c
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

295 lines
9.4 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)
{
/**
* @constructor
*/
function CTextFontInfo(sName, nStyle, nSize)
{
this.Name = undefined !== sName ? sName : "Arial";
this.Style = undefined !== nStyle ? nStyle : 0;
this.Size = undefined !== nSize ? nSize : 10;
}
const DEFAULT_TEXTFONTINFO = new CTextFontInfo();
// Функции для возможной перегрузки
// 1. FlushGrapheme - основная функция, которую нужно ОБЯЗАТЕЛЬНО реализовывать в дочернем классе
// 2. Shape - простая функция для шейпинга текста
// 3. GetFontInfo - получаем информацию о шрифте на момент составления графем
// 4. GetCodePoint - данная функция нужна, чтобы в буфере можно было хранить не сам юникод, а его содержащий класс
// 5. GetLigaturesType - какие лигатуры поддерживать
/**
* @constructor
*/
function CTextShaper()
{
this.Buffer = [];
this.BufferIndex = 0;
this.Script = -1;
this.FontId = -1;
this.FontSubst = false;
this.FontSlot = AscWord.fontslot_None;
this.FontSize = 10;
this.ForceCheckFont = false;
this.Direction = AscFonts.HB_DIRECTION.HB_DIRECTION_LTR;
}
CTextShaper.prototype.ClearBuffer = function()
{
this.Buffer.length = 0;
this.BufferIndex = 0;
this.Script = -1;
this.FontId = -1;
this.FontSlot = AscWord.fontslot_None;
this.Direction = AscFonts.HB_DIRECTION.HB_DIRECTION_LTR;
this.StartString();
};
CTextShaper.prototype.ResetBuffer = function()
{
if (this.IsRtlDirection())
this.BufferIndex = this.Buffer.length;
};
CTextShaper.prototype.StartString = function()
{
AscFonts.HB_StartString();
};
CTextShaper.prototype.AppendToString = function(oItem)
{
let nCodePoint = this.GetCodePoint(oItem);
nCodePoint = this.private_CheckNewSegment(nCodePoint);
this.Buffer.push(oItem);
AscFonts.HB_AppendToString(nCodePoint);
};
CTextShaper.prototype.EndString = function()
{
AscFonts.HB_EndString();
};
CTextShaper.prototype.FlushWord = function()
{
if (this.Buffer.length <= 0)
return this.ClearBuffer();
this.EndString();
let nScript = AscFonts.HB_SCRIPT.HB_SCRIPT_INHERITED === this.Script ? AscFonts.HB_SCRIPT.HB_SCRIPT_COMMON : this.Script;
this.Direction = this.GetDirection(nScript);
this.ResetBuffer();
let oFontInfo = this.GetFontInfo(this.FontSlot);
let nFontId = AscCommon.FontNameMap.GetId(this.FontId.m_pFaceInfo.family_name);
AscCommon.g_oTextMeasurer.SetFontInternal(this.FontId.m_pFaceInfo.family_name, AscFonts.MEASURE_FONTSIZE, oFontInfo.Style);
this.FontSize = oFontInfo.Size;
AscFonts.HB_ShapeString(this, nFontId, oFontInfo.Style, this.FontId, this.GetLigaturesType(nScript), nScript, this.Direction, "en");
// Значит шрифт был подобран, возвращаем назад состояние отрисовщика
if (this.FontId.m_pFaceInfo.family_name !== oFontInfo.Name)
{
AscCommon.g_oTextMeasurer.SetFontInternal(oFontInfo.Name, AscFonts.MEASURE_FONTSIZE, oFontInfo.Style);
this.ForceCheckFont = true;
}
this.ClearBuffer();
};
CTextShaper.prototype.GetLigaturesType = function(textScript)
{
return Asc.LigaturesType.None;
};
CTextShaper.prototype.GetTextScript = function(nUnicode)
{
return AscFonts.hb_get_script_by_unicode(nUnicode);
};
CTextShaper.prototype.GetFontSlot = function(nUnicode)
{
return AscWord.GetFontSlot(nUnicode, AscWord.fonthint_Default, lcid_unknown, false, false);
};
CTextShaper.prototype.GetDirection = function(nScript)
{
return AscFonts.hb_get_script_horizontal_direction(nScript);
};
CTextShaper.prototype.private_CheckNewSegment = function(nUnicode)
{
if (this.Buffer.length >= AscFonts.HB_STRING_MAX_LEN)
this.FlushWord();
// TODO: Check bugs 66317 66435
let nScript = this.GetTextScript(nUnicode);
if (nScript !== this.Script
&& -1 !== this.Script
&& AscFonts.HB_SCRIPT.HB_SCRIPT_INHERITED !== nScript
&& AscFonts.HB_SCRIPT.HB_SCRIPT_INHERITED !== this.Script)
this.FlushWord();
if (this.GetDirection(this.Script) !== this.GetDirection(nScript))
this.FlushWord();
let nFontSlot = this.GetFontSlot(nUnicode);
this.private_CheckFont(nFontSlot);
let nFontId = this.FontId;
let isSubst;
if (AscFonts.HB_SCRIPT.HB_SCRIPT_INHERITED === nScript && this.FontSubst)
{
let oInfo = AscCommon.g_oTextMeasurer.GetFontBySymbol(nUnicode, -1 !== nFontId ? nFontId : null, true);
nFontId = oInfo.Font;
nUnicode = oInfo.CodePoint;
isSubst = true;
}
else
{
isSubst = !AscCommon.g_oTextMeasurer.CheckUnicodeInCurrentFont(nUnicode);
if (-1 === nFontId || isSubst)
{
let oInfo = AscCommon.g_oTextMeasurer.GetFontBySymbol(nUnicode, -1 !== nFontId ? nFontId : null);
nFontId = oInfo.Font;
nUnicode = oInfo.CodePoint;
}
else
{
let nCurFontId = AscCommon.g_oTextMeasurer.GetCurrentFont();
if (nCurFontId)
nFontId = nCurFontId;
}
}
if (this.FontId !== nFontId
&& -1 !== this.FontId
&& this.FontSubst
&& isSubst
&& this.private_CheckBufferInFont(nFontId))
this.FontId = nFontId;
if (this.FontId !== nFontId && -1 !== this.FontId)
this.FlushWord();
this.Script = AscFonts.HB_SCRIPT.HB_SCRIPT_INHERITED !== nScript || -1 === this.Script ? nScript : this.Script;
this.FontSlot = AscWord.fontslot_None !== nFontSlot ? nFontSlot : this.FontSlot;
this.FontId = nFontId;
this.FontSubst = isSubst;
return nUnicode;
};
CTextShaper.prototype.private_CheckFont = function(nFontSlot)
{
if (this.FontSlot === nFontSlot && !this.ForceCheckFont)
return;
let oFontInfo = this.GetFontInfo(nFontSlot);
AscCommon.g_oTextMeasurer.SetFontInternal(oFontInfo.Name, AscFonts.MEASURE_FONTSIZE, oFontInfo.Style);
this.ForceCheckFont = false;
};
CTextShaper.prototype.private_CheckBufferInFont = function(nFontId)
{
for (let nPos = 0, nCount = this.Buffer.length; nPos < nCount; ++nPos)
{
if (!nFontId.GetGIDByUnicode(this.GetCodePoint(this.Buffer[nPos])))
return false;
}
return true;
};
CTextShaper.prototype.GetFontInfo = function(nFontSlot)
{
return DEFAULT_TEXTFONTINFO;
};
CTextShaper.prototype.Shape = function(sString)
{
for (var oIterator = sString.getUnicodeIterator(); oIterator.check(); oIterator.next())
{
let nCodePoint = oIterator.value();
this.AppendToString(nCodePoint);
}
this.FlushWord();
};
CTextShaper.prototype.GetCodePoint = function(oItem)
{
return oItem;
};
CTextShaper.prototype.FlushGrapheme = function(nGrapheme, nWidth, nCodePointsCount, isLigature)
{
if (this.IsRtlDirection())
this.BufferIndex -= nCodePointsCount;
else
this.BufferIndex += nCodePointsCount;
};
CTextShaper.prototype.IsRtlDirection = function()
{
return this.Direction === AscFonts.HB_DIRECTION.HB_DIRECTION_RTL;
};
CTextShaper.prototype.PrintAllUnicodesByScript = function(nScript)
{
let log = "";
function Flush(isForce)
{
if (log.length > 100 || isForce)
{
console.log(log);
log = "";
}
}
for (let u = 0; u < 0x10FFFF; ++u)
{
if (nScript === this.GetTextScript(u))
{
log += AscCommon.IntToHex(u) + " " + String.fromCodePoint(u) + " ";
Flush(false);
}
}
Flush(true);
};
function isRtlScript(unicode)
{
return AscFonts.hb_get_script_horizontal_direction(AscFonts.hb_get_script_by_unicode(unicode)) === AscFonts.HB_DIRECTION.HB_DIRECTION_RTL;
}
//--------------------------------------------------------export----------------------------------------------------
window['AscFonts'] = window['AscFonts'] || {};
window['AscFonts'].CTextFontInfo = CTextFontInfo;
window['AscFonts'].CTextShaper = CTextShaper;
window['AscFonts'].DEFAULT_TEXTFONTINFO = DEFAULT_TEXTFONTINFO;
window['AscFonts'].isRtlScript = isRtlScript;
})(window);