Возможно, проще всего использовать мощь CSS, а не пытаться делать это самостоятельно.
Вы можете создать фиктивный элемент div, добавить в него тег < span> и увеличивать его размер шрифта, пока он больше не будет соответствовать.
Размер шрифта до этого был правильным.
Затем вы можете просмотреть текстовое содержимое этого < span>, используя объект Range , чтобы получить разрывы строк, которые сгенерирует CSS. Range API предоставляет удобный метод getBoundingClientRect , позволяющий нам найти, где находится курсор. Нам просто нужно запомнить последнюю позицию y, и когда она меняется, мы знаем, что символ раньше был последним в строке.
Однако у этой техники есть некоторые недостатки.
В DOM несколько пробелов сжимаются в один. CanvasContext API не имеет такого поведения, поэтому мы должны избавиться от них перед анализом текста.
Меры сделаны на основе ограничивающих рамок контейнеров, это означает, что он не проверяет окрашенные пиксели, поэтому некоторые символы могут быть переполнены (например, Zalgo͚̠͓ͣ̔͐̽), а некоторые другие не подходят идеально. в поле (в зависимости от подъема и спуска каждого персонажа).
... , вероятно, другие.
function getBestFontSize(text, width, height, userstyles) {
if(!text) return null;
const cont = document.createElement('div');
cont.classList.add('best-font-size-tester');
const style = cont.style;
if(typeof width === 'number') width += 'px';
if(typeof height === 'number') height += 'px';
Object.assign(style, {width, height}, userstyles);
const span = document.createElement('span');
span.textContent = text;
cont.appendChild(span);
document.body.appendChild(cont);
let size = 0;
const max = cont.getBoundingClientRect();
while(true) {
style.fontSize = size + 'px';
let rect = span.getBoundingClientRect();
if(rect.bottom > max.bottom || rect.right > max.right) {
// overflown
size -= 1; // the correct size was the one before
break;
}
size++;
}
if(size === 0) {
// even at 0 it doesn't fit...
return null;
}
// now we'll get the line breaks by walking through our text content
style.fontSize = size + 'px';
const lines = getLineBreaks(span.childNodes[0], max.top);
// cleanup
document.body.removeChild(cont);
return {
fontSize: size,
lines: lines
};
}
function getLineBreaks(node, contTop) {
if(!node) return [];
const range = document.createRange();
const lines = [];
range.setStart(node, 0);
let prevBottom = range.getBoundingClientRect().bottom;
let str = node.textContent;
let current = 1;
let lastFound = 0;
let bottom = 0;
while(current <= str.length) {
range.setStart(node, current);
bottom = range.getBoundingClientRect().bottom;
if(bottom > prevBottom) {
lines.push({
y: prevBottom - (contTop || 0),
text: str.substr(lastFound , (current - 1) - lastFound)
});
prevBottom = bottom;
lastFound = current - 1;
}
current++;
}
// push the last line
lines.push({
y: bottom - (contTop || 0),
text: str.substr(lastFound)
});
return lines;
}
const ctx = canvas.getContext('2d');
ctx.textBaseline = 'bottom';
txt_area.oninput = e => {
const input = txt_area.value
.replace(/(\s)(?=\1)/g, ''); // remove all double spaces
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(19.5,19.5);
ctx.strokeRect(0,0,100,100);
if(!input.length) return;
const bestFit = getBestFontSize(input, 100, 100, {
fontFamily: 'sans-serif',
fontWeight: '600',
textAlign: 'center'
});
// apply thesame options we passed
ctx.font = '600 ' + bestFit.fontSize + 'px sans-serif';
ctx.textAlign = 'center';
// translate again because text-align: center
ctx.translate(50.5,0);
bestFit.lines.forEach(({text, y}) => ctx.fillText(text, 0, y));
};
txt_area.oninput();
.best-font-size-tester {
border: 1px solid;
position: absolute;
overflow: visible;
opacity: 0;
z-index: -1;
pointer-events: none;
}
Необходимо определить обработчик сигналов. Это сделано в системах Unix с помощью функции sigaction
. Я сделал это с тем же кодом Fedora 64-и 32-разрядный, и Sun Solaris.
Ну, SIGSEGV trappable, и это - POSIX, таким образом, это портативно в этом смысле.
Bu я обеспокоен, что Вы, кажется, хотите обработать segfault, а не решить проблему, которая вызывает segfault. Если я должен был выбрать, было ли это ОС в отказе или моим собственным кодом, я знаю, который я выбрал бы. Я предлагаю, чтобы Вы выследили ту ошибку, зафиксировали ее, затем записали тестовый сценарий, чтобы удостовериться, что она никогда не кусает Вас снова.
Можно использовать функциональный сигнал установить новый обработчик сигналов для сигнала:
#include <signal.h>
void (*signal(int signum, void (*sighandler)(int)))(int);
Что-то как следующий код:
signal(SIGINT , clean_exit_on_sig);
signal(SIGABRT , clean_exit_on_sig);
signal(SIGILL , clean_exit_on_sig);
signal(SIGFPE , clean_exit_on_sig);
signal(SIGSEGV, clean_exit_on_sig); // <-- this one is for segmentation fault
signal(SIGTERM , clean_exit_on_sig);
void
clean_exit_on_sig(int sig_num)
{
printf ("\n Signal %d received",sig_num);
}
Безопасные действия в обработчике сигналов очень ограничены. Небезопасно назвать любую библиотечную функцию не известной быть повторно используемым, который исключит, например, free()
и printf()
. Лучшая практика должна установить переменную и возврат, но это не помогает Вам очень. Также безопасно использовать системные вызовы такой как write()
.
Обратите внимание на это в двух примерах следа, данных здесь, backtrace_symbols_fd()
функция будет безопасна, потому что она использует сырые данные fd непосредственно, но вызов к fprintf()
является неправильным, и должен быть заменен использованием write()
.
Я думаю, что Вы пытаетесь решить проблему, которая не существует. По крайней мере, Вы работаете над неправильным концом. Вы не сможете поймать отказ сегментации, поскольку эта ошибка/исключение брошена ОС (это вызывается Вашей программой, ОС просто ловит его).
Я советовал бы Вам заново продумать свою стратегию относительно входа: Почему невозможно санировать его? Самой важной, чтобы сделать является проверка размера для этого, C stdlib имеет соответствующие функции. Затем, конечно, необходимо было бы проверить на допустимый вход относительно содержания. Да, это, вероятно, приведет к большой работе, но это - единственный способ записать устойчивую программу.
Править: Я не большая часть эксперта C, не знал, что даже отказ сегментации мог быть обработан обработчиком сигналов. Однако, я думаю, что это не правильный способ пойти по упомянутым выше причинам.
обработка сигнала является (относительно) портативной через машины Unix (это включает Mac и Linux). Большие различия находятся в деталях исключения, которые передаются как аргумент стандартной программе обработки сигнала. Sorrty, но Вам, вероятно, будет нужен набор #ifdefs для этого, если Вы захотите распечатать более разумные сообщения об ошибках (такой как, где и из-за которого адреса отказ произошел)...
хорошо, вот фрагмент кода для Вас для запуска с:
#include <signal.h>
/* reached when a segv occurrs */
void
SEGVFunction( SIGARGS )
{
...
}
...
main(...) {
signal(SIGSEGV, SEGVFunction); /* tell the OS, where to go in case... */
...
... do your work ...
}
Ваша задача к:
в теории Вы могли даже исправить ПК в обработчике сигналов (к после дающей сбой инструкции) и продолжить двигаться. Однако типичные обработчики сигналов любой выход () или к longjmp () назад в сохранение помещают в основном.
с уважением
Необходимо будет обеспечить обработчик SIGSEGV, эти довольно достойные взгляды.
Существует пример того, как поймать SIGSEGV и распечатать отслеживание стека с помощью следа glibc () здесь:
как генерировать stacktrace когда мои сбои приложения C++
Можно использовать это, чтобы поймать segfault и вымыться, но быть предупрежденными: Вы не должны делать слишком большого количества материала в обработчике сигналов, особенно вещи, которые включают звонки совершения как malloc (). Существует много вызовов, которые не являются безопасным сигналом, и можно закончить тем, что стреляли себе в ногу при создании, скажем, вызова к malloc из malloc.