...

четверг, 31 июля 2014 г.

ONLYOFFICE. Голая правда об исходном коде облачного офиса



В начале июля Teamlab переименовался в ONLYOFFICE и полностью открыл исходный код своего приложения, включая онлайн редакторы документов, совместное редактирование, диаграмму Ганта и функционал выставления счетов.

За две недели мы получили массу вопросов на эту тему, поэтому на правах сотрудника компании возьмусь разъяснить, что к чему. Если у вас нет времени читать пост, просто скачайте инсталляцию ONLYOFFICE с Sourceforge. Разверните на своем сервере. Готово! У вас есть свой облачный офис. Вы великолепны.



Почему Teamlab стал ONLYOFFICE


Идея ребрендинга существовала довольно давно. В своем блоге мы написали целый пост о том, почему мы выбрали ONLY в качестве новой приставки к своему офису, однако, были и вполне конкретные причины. Во-первых, название Teamlab перестало отражать идею продукта, ведь «team» ассоциируется с небольшой командой, в то время как среди наших клиентов все чаще появляются компании по 300 и 400 человек. Во-вторых, помимо нас, к сожалению, это слово облюбовали дизайнеры интерактивных вешалок из Японии.

Почему мы открыли исходный код (Honesty is the best policy потому что)


Основная причина — это, безусловно, доверие. Не только со стороны клиентов, но и со стороны наших партнеров. В сегодняшней ситуации мы получаем довольно много вопросов о безопасности хранения корпоративных данных, особенно от зарубежных клиентов. Публикуя код ONLYOFFICE на Sourceforge и GitHub, мы делаем еще один шаг им навстречу.

Выбор лицензии


Публикуя исходные коды своего продукта, мы преследовали несколько целей:


  • Привлечь внимание opensource сообщества.

  • Закрепить авторство продукта.

  • Усилить доверие зарубежных клиентов и партнеров.




Взвесив все за и против, мы выбрали AGPL v3. В двух словах она означает следующее: вы можете использовать ONLYOFFICE в своей компании бесплатно и без ограничений, но если хотите встроить наш код в собственное приложение, вам придется открыть исходные коды своего продукта под той же лицензией. Подробнее здесь.

Что говорят наши программисты


Переходим к самой интересной части нашего поста. Open Source версия ONLYOFFICE готовилась к выпуску довольно долго — один только текстовый редактор содержит более 500 000 строк кода! Конечно же, нам есть, о чем рассказать:
Особое внимание к Internet Explorer


Основа алгоритма растеризации взята из freetype, так как это качественный, проверенный временем открытый шрифтовый движок. Сами алгоритмы немного изменили, чтобы скорость выполнения была выше именно в браузере, поскольку мы пишем на javascript.


А вот, например, кэш букв нам пришлось писать в двух вариантах: для Internet Explorer и для всех остальных. Из-за специфика браузера в IE первая реализация была медленной.



Олег, ведущий программист
Что вы знаете о ширине столбцов в Excel?


Существует два основных сценария использования Excel:



  • финансовые расчёты,

  • создание бланков (счетов) для дальнейшего заполнения и распечатки.




Большое количество бланков были созданы еще до появления нашего редактора таблиц, поэтому нашей задачей было не только научиться правильно их открывать, но и корректно рассчитывать ширины столбцов и высоты строк. В противном случае при печати бланк мог бы не убраться на лист.

Например, стандартная ширина столбца в Microsoft Excel — 8.43 символа (characters). Она рассчитывается из ширины по умолчанию в 8 символов, которая переводится в пиксели в зависимости от стиля Normal. Затем, как оказалось, полученное число округляется до ближайшего кратного 8-ми.

Еще одна особенность — это высота строки. В Excel нельзя задать межстрочный интервал, как, например, в Word, поэтому расчет высоты строки в Excel отличается от расчета высоты строки в Word. Вот, например, сравнение в шрифте Cambria Math 11:



В итоге мы реализовали расчёт так, чтобы ни один символ не оказался обрезанным.

Александр, ведущий программист
Как мы связали дерево зависимостей и топологическую сортировку


Большая часть электронных таблиц так или иначе содержит в себе формулы. Для решения задач разбора и подсчета формул было реализованы парсер и калькулятор. Также в работе с формулами особого внимания заслуживает построение зависимостей между ячейками. Для этой цели был использован алгоритм топологической сортировки, позволяющий строить порядок обхода дерева зависимостей.



Дмитрий, программист
Пятнадцать тысяч тестов и 80 машин


Чтобы протестировать инсталляцию ONLYOFFICE, мы развернули её у себя и запустили уже привычный процесс. В сумме набежало порядка 15000 тестов, которые запускаются на 80 машинах. Кстати, хостим мы их теперь на Digital Ocean и в ближайшее время расскажем о том, как перенесли туда всю тестовую структуру.



Стас, руководитель отдела тестирования
Hopes&Fears


Боимся ли мы того, что наш код кто-то позаимствует в корыстных целях? Нет. Использование кода ONLYOFFICE четко прописано в лицензии, и здесь мы защищены международным правом.

Не думаем ли мы, что кто-то «подсмотрит» и сделает аналогичный продукт? Конечно, думаем. Но на это у ребят уйдет не менее 3 лет, так что мы не вот уж сильно переживаем. Впрочем, мы давно уже привыкли находиться и выживать в высококонкурентной среде.



Александра, руководитель отдела продвижения
Что вам стоит свой редактор на канве построить?

Любой текстовый редактор начинается с разбивки текста на строки и отрисовки. Первый рабочий вариант состоял из 150 строк кода и был реализован следующим образом:

// Класс ParaText
function ParaText(value)
{
this.Value = value;
this.Type = para_Text;

this.Width = 0;
this.Height = 0;
}

ParaText.prototype.Draw = function(X, Y, Context);
ParaText.prototype.Measure = function(Context);




Еще 140 строк кода


// Класс ParaSpace
function ParaSpace()
{
this.Type = para_Space;

this.Width = 0;
this.Height = 0;
}

ParaSpace.prototype.Draw = function(X,Y, Context);
ParaSpace.prototype.Measure = function(Context);


// Класс ParaNewLineRendered
function ParaNewLineRendered()
{
this.Type = para_NewLineRendered;
this.Width = 0;
this.Height = 0;
}

ParaNewLineRendered.prototype.Draw = function();
ParaNewLineRendered.prototype.Measure = function();

// Класс Paragraph
function CParagraph()
{
//...................

// Начальный сдвиг
this.X = 0;
this.Y = 0;

// Ширина строки
this.XLimit = 0;

// Содержимое параграфа, состоящее из объектов типа ParaText, ParaSpace и ParaNewLineRendered
this.Content = new Array();

// Высота строки. Пусть у нас она будет одинаковая для всех строк
this.dLineHeight = 0;
//...................
}

CParagraph.prototype.Recalculate = function()
{
// Подготовка к новому пересчету. Здесь мы удаляем старые элементы ParaNewLineRendered
//..............................

// Смещаемся в начало параграфа
var X = this.X, Y = this.Y;

// Рассчитываем параграф
var CurLine = 0;

var bNewLine = false;
var bFirstItemOnLine = true;
var bWord = false;
var nWordStartPos = 0;
var dWordLen = 0;

for ( var nPos = 0; nPos < this.Content.length; nPos++ )
{
var Item = this.Content[nPos];

switch( Item.Type )
{
case para_Text:
{
var dLetterLen = Item.Measure( Context ).Width;

if ( !bWord )
{
// Если слово только началось, и до него на строке ничего не было, тогда не надо проверять убирается ли оно на строке.
if ( !bFirstItemOnLine )
{
if ( X + dLetterLen > this.XLimit )
{
// Уже первая буква в слове не убралась в строке - ставим перенос строки
this.Content.splice( nPos, 0, new ParaNewLineRendered() );
bNewLine = true;
}
}

if ( !bNewLine )
{
nWordStartPos = nPos;
dWordLen = dLetterLen;
bWord = true;
}
}
else
{
if ( X + dWordLen + dLetterLen > this.XLimit )
{
if ( bFirstItemOnLine )
{
// Слово оказалось единственным элементом строки и все равно
// не умещается целиком. Ставим перенос строки на текущей позиции.
X += dWordLen;
this.Content.splice( nPos, 0, new ParaNewLineRendered() );

bNewLine = true;
}
else
{
// Смещаемся к началу слова и перед ним ставим перенос строки
this.Content.splice( nWordStartPos, 0, new ParaNewLineRendered() );
nPos = nWordStartPos;

bNewLine = true;
}
}

if ( !bNewLine )
{
dWordLen += dLetterLen;
}
}
break;
}
case para_Space:
{
bFirstItemOnLine = false;

var dSpaceLen = Item.Measure( Canvas ).Width;
if ( bWord )
{
// Не надо проверять, убирается ли слово - мы это проверяем при добавлении букв
X += dWordLen;

bWord = false;
dWordLen = 0;
}

if ( X + dSpaceLen > this.XLimit )
{
bNewLine = true;
}
else
X += dSpaceLen;

break;
}
}

// Переходим на новую строку
if ( bNewLine )
{
bNewLine = false;
bFirstItemOnLine = true;
bWord = false;
dWordLen = 0;

// По горизонтали смещаемся в начало параграфа, а по вертикали смещаемся вниз на высоту строки
X = this.X;
Y += this.dLineHeight;

CurLine++;
}
}
}

CParagraph.prototype.Draw = function(Context)
{
var Y = this.Y;
var X = this.X;

var nCount = this.Content.length;
for ( var nPos = 0; nPos < nCount; nPos++ )
{
var Item = this.Content[nPos];

Item.Draw( X, Y, Context );

X += Item.Width;

if ( para_NewLineRendered == Item.Type )
{
Y += this.dLineHeight;
X = this.X;
}
}
}





Илья, ведущий программист


Через две недели после начала разработки был готов первый тестовый пример:


Скачать и протестировать пример можно здесь.

Нет ничего приятнее, чем сравнивать его с тем, чего мы достигли за несколько лет. И с тем, на каком этапе находятся сейчас редакторы конкурентов.


Протестировать все редакторы можно без регистрации на сайте personal.teamlab.com. Им, кстати, вообще можно активно пользоваться — он бесплатный.


Наша цель? Пользователи ONLYOFFICE по всему миру


Планов у нас действительно много. Уже сейчас мы активно работаем над мобильными и десктопными приложениями, помимо этого к осени выйдет версия офисных редакторов 3.0, а еще мы подумываем над тем, чтобы коммитить разработку на GitHub в режиме реального времени.

Кажется, все. Перемещаем обсуждение в комментарии)


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий