Files
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

360 lines
9.1 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 CRasterHeapLineFree()
{
this.Y = 0;
this.Height = 0;
}
function CRasterDataInfo()
{
this.Chunk = null;
this.Line = null;
this.Index = 0;
}
function CRasterHeapLine()
{
this.Y = 0;
this.Height = 0;
this.Count = 0;
this.CountBusy = 0;
this.Images = null;
this.Index = 0;
}
CRasterHeapLine.prototype.CreatePlaces = function(width, height, widthLine)
{
this.Height = height;
this.Count = (widthLine / width) >> 0;
var _size = this.Count;
var arr = null;
if (typeof(Int8Array) != 'undefined' && !window.opera)
arr = new Int8Array(_size);
else
arr = new Array(_size);
for (var i=0;i<_size;i++)
arr[i] = 0;
this.Images = arr;
};
CRasterHeapLine.prototype.Alloc = function()
{
if (this.Count == this.CountBusy)
return -1;
var arr = this.Images;
if (arr[this.CountBusy] == 0)
{
arr[this.CountBusy] = 1;
this.CountBusy += 1;
return this.CountBusy - 1;
}
var _len = this.Count;
for (var i = 0; i < _len; i++)
{
if (arr[i] == 0)
{
arr[i] = 1;
this.CountBusy += 1;
return i;
}
}
return -1;
};
CRasterHeapLine.prototype.Free = function(index)
{
if (this.Images[index] == 1)
{
this.Images[index] = 0;
this.CountBusy -= 1;
}
return this.CountBusy;
};
function CRasterHeapChuck()
{
this.CanvasImage = null;
this.CanvasCtx = null;
this.Width = 0;
this.Height = 0;
this.LinesFree = [];
this.LinesBusy = [];
this.CurLine = null;
this.FindOnlyEqualHeight = false;
}
CRasterHeapChuck.prototype.Create = function(width, height)
{
this.Width = width;
this.Height = height;
this.CanvasImage = document.createElement('canvas');
this.CanvasImage.width = width;
this.CanvasImage.height = height;
this.CanvasCtx = this.CanvasImage.getContext('2d');
this.CanvasCtx.globalCompositeOperation = "source-atop";
var _freeLine = new CRasterHeapLineFree();
_freeLine.Y = 0;
_freeLine.Height = this.Height;
this.LinesFree[0] = _freeLine;
};
CRasterHeapChuck.prototype.Clear = function()
{
this.LinesBusy.splice(0, this.LinesBusy.length);
this.LinesFree.splice(0, this.LinesFree.length);
var _freeLine = new CRasterHeapLineFree();
_freeLine.Y = 0;
_freeLine.Height = this.Height;
this.LinesFree[0] = _freeLine;
};
CRasterHeapChuck.prototype.Alloc = function(width, height)
{
var _need_height = Math.max(width, height);
var _busy_len = this.LinesBusy.length;
for (var i = 0; i < _busy_len; i++)
{
var _line = this.LinesBusy[i];
if (_line.Height >= _need_height)
{
var _index = _line.Alloc();
if (-1 != _index)
{
var _ret = new CRasterDataInfo();
_ret.Chunk = this;
_ret.Line = _line;
_ret.Index = _index;
return _ret;
}
}
}
// линию не нашли. Начинаем искать из свободной памяти
// ищем 3/2 от нужного размера. и параллельно 1
var _need_height1 = (3 * _need_height) >> 1;
if (this.FindOnlyEqualHeight)
_need_height1 = _need_height;
var _free_len = this.LinesFree.length;
var _index_found_koef1 = -1;
for (var i = 0; i < _free_len; i++)
{
var _line = this.LinesFree[i];
if (_line.Height >= _need_height1)
{
// нашли
var _new_line = new CRasterHeapLine();
_new_line.CreatePlaces(_need_height1, _need_height1, this.Width);
_new_line.Y = _line.Y;
_new_line.Index = this.LinesBusy.length;
this.LinesBusy.push(_new_line);
_line.Y += _need_height1;
_line.Height -= _need_height1;
if (_line.Height == 0)
this.LinesFree.splice(i, 1);
var _ret = new CRasterDataInfo();
_ret.Chunk = this;
_ret.Line = _new_line;
_ret.Index = _new_line.Alloc();
return _ret;
}
else if (_line.Height >= _need_height && -1 == _index_found_koef1)
{
_index_found_koef1 = i;
}
}
// 3/2 не нашли. если нашли для 1, то выделяем там
if (-1 != _index_found_koef1)
{
var _line = this.LinesFree[_index_found_koef1];
var _new_line = new CRasterHeapLine();
_new_line.CreatePlaces(_need_height, _need_height, this.Width);
_new_line.Y = _line.Y;
_new_line.Index = this.LinesBusy.length;
this.LinesBusy.push(_new_line);
_line.Y += _need_height;
_line.Height -= _need_height;
if (_line.Height == 0)
this.LinesFree.splice(i, 1);
var _ret = new CRasterDataInfo();
_ret.Chunk = this;
_ret.Line = _new_line;
_ret.Index = _new_line.Alloc();
return _ret;
}
// не нашли.
return null;
};
CRasterHeapChuck.prototype.Free = function(obj)
{
var _refs = obj.Line.Free(obj.Index);
if (_refs == 0)
{
// нужно удалить линию и перебить всем оставшимся индексы
var _line = obj.Line;
this.LinesBusy.splice(_line.Index, 1);
var _lines_busy = this.LinesBusy;
var _busy_len = _lines_busy.length;
for (var i = _line.Index; i < _busy_len; i++)
_lines_busy[i].Index = i;
// теперь нужно поправить linesfree
var y1 = _line.Y;
var y2 = _line.Y + _line.Height;
var _lines_free = this.LinesFree;
var _free_len = _lines_free.length;
var _ind_prev = -1;
var _ind_next = -1;
for (var i = 0; i < _free_len; i++)
{
var _line_f = _lines_free[i];
if (-1 == _ind_prev)
{
if (y1 == (_line_f.Y + _line_f.Height))
_ind_prev = i;
}
else if (-1 == _ind_next)
{
if (y2 == _line_f.Y)
_ind_next = i;
}
else
{
break;
}
}
// нашли прилегаюую свободную память. теперь нужно их склеить, или создать новую
if (-1 != _ind_prev && -1 != _ind_next)
{
_lines_free[_ind_prev].Height += (_line.Height + _lines_free[_ind_next].Height);
_lines_free.splice(_ind_next, 1);
}
else if (-1 != _ind_prev)
{
_lines_free[_ind_prev].Height += _line.Height;
}
else if (-1 != _ind_next)
{
_lines_free[_ind_next].Y -= _line.Height;
_lines_free[_ind_next].Height += _line.Height;
}
else
{
var _new_line = new CRasterHeapLineFree();
_new_line.Y = _line.Y;
_new_line.Height = _line.Height;
_lines_free.push(_new_line);
}
_line = null;
}
};
function CRasterHeapTotal(_size)
{
this.ChunkHeapSize = (undefined === _size) ? 3000 : _size; // 4 * 3000 * 3000 = 36Mb
this.Chunks = [];
}
CRasterHeapTotal.prototype.Clear = function()
{
var _len = this.Chunks.length;
for (var i = 0; i < _len; i++)
{
this.Chunks[i].Clear();
}
// теперь наверное удалим и память лишнюю
if (_len > 1)
this.Chunks.splice(1, _len - 1);
};
CRasterHeapTotal.prototype.Alloc = function(width, height)
{
var _len = this.Chunks.length;
for (var i = 0; i < _len; i++)
{
var _ret = this.Chunks[i].Alloc(width, height);
if (null != _ret)
return _ret;
}
this.HeapAlloc(this.ChunkHeapSize, this.ChunkHeapSize);
return this.Chunks[_len].Alloc(width, height);
};
CRasterHeapTotal.prototype.HeapAlloc = function(width, height)
{
var _chunk = new CRasterHeapChuck();
_chunk.Create(width, height);
this.Chunks[this.Chunks.length] = _chunk;
};
CRasterHeapTotal.prototype.CreateFirstChuck = function(_w, _h)
{
if (0 == this.Chunks.length)
{
this.Chunks[0] = new CRasterHeapChuck();
this.Chunks[0].Create((undefined == _w) ? this.ChunkHeapSize : _w, (undefined == _h) ? this.ChunkHeapSize : _h);
}
};
window['AscFonts'] = window['AscFonts'] || {};
window['AscFonts'].CRasterHeapTotal = CRasterHeapTotal;
})(window, undefined);