Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<meta charset="UTF-8">
<title>OffscreenCanvas test: 2d.text.measure.index-from-offset.tentative</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/html/canvas/resources/canvas-tests.js"></script>
<h1>2d.text.measure.index-from-offset.tentative</h1>
<script>
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('left' == 'center') {
offset -= width / 2;
} else if ('left' == 'right' ||
('ltr' == 'ltr' && 'left' == 'end') ||
('ltr' == 'rtl' && 'left' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('left' == 'center') {
text_align_dx = text_width / 2;
} else if ('left' == 'right' ||
('ltr' == 'ltr' && 'left' == 'end') ||
('ltr' == 'rtl' && 'left' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'left';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align left, 0px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('left' == 'center') {
offset -= width / 2;
} else if ('left' == 'right' ||
('rtl' == 'ltr' && 'left' == 'end') ||
('rtl' == 'rtl' && 'left' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('left' == 'center') {
text_align_dx = text_width / 2;
} else if ('left' == 'right' ||
('rtl' == 'ltr' && 'left' == 'end') ||
('rtl' == 'rtl' && 'left' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'left';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align left, 0px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('center' == 'center') {
offset -= width / 2;
} else if ('center' == 'right' ||
('ltr' == 'ltr' && 'center' == 'end') ||
('ltr' == 'rtl' && 'center' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('center' == 'center') {
text_align_dx = text_width / 2;
} else if ('center' == 'right' ||
('ltr' == 'ltr' && 'center' == 'end') ||
('ltr' == 'rtl' && 'center' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'center';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align center, 0px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('center' == 'center') {
offset -= width / 2;
} else if ('center' == 'right' ||
('rtl' == 'ltr' && 'center' == 'end') ||
('rtl' == 'rtl' && 'center' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('center' == 'center') {
text_align_dx = text_width / 2;
} else if ('center' == 'right' ||
('rtl' == 'ltr' && 'center' == 'end') ||
('rtl' == 'rtl' && 'center' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'center';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align center, 0px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('right' == 'center') {
offset -= width / 2;
} else if ('right' == 'right' ||
('ltr' == 'ltr' && 'right' == 'end') ||
('ltr' == 'rtl' && 'right' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('right' == 'center') {
text_align_dx = text_width / 2;
} else if ('right' == 'right' ||
('ltr' == 'ltr' && 'right' == 'end') ||
('ltr' == 'rtl' && 'right' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'right';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align right, 0px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('right' == 'center') {
offset -= width / 2;
} else if ('right' == 'right' ||
('rtl' == 'ltr' && 'right' == 'end') ||
('rtl' == 'rtl' && 'right' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('right' == 'center') {
text_align_dx = text_width / 2;
} else if ('right' == 'right' ||
('rtl' == 'ltr' && 'right' == 'end') ||
('rtl' == 'rtl' && 'right' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'right';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align right, 0px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('start' == 'center') {
offset -= width / 2;
} else if ('start' == 'right' ||
('ltr' == 'ltr' && 'start' == 'end') ||
('ltr' == 'rtl' && 'start' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('start' == 'center') {
text_align_dx = text_width / 2;
} else if ('start' == 'right' ||
('ltr' == 'ltr' && 'start' == 'end') ||
('ltr' == 'rtl' && 'start' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'start';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align start, 0px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('start' == 'center') {
offset -= width / 2;
} else if ('start' == 'right' ||
('rtl' == 'ltr' && 'start' == 'end') ||
('rtl' == 'rtl' && 'start' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('start' == 'center') {
text_align_dx = text_width / 2;
} else if ('start' == 'right' ||
('rtl' == 'ltr' && 'start' == 'end') ||
('rtl' == 'rtl' && 'start' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'start';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align start, 0px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('end' == 'center') {
offset -= width / 2;
} else if ('end' == 'right' ||
('ltr' == 'ltr' && 'end' == 'end') ||
('ltr' == 'rtl' && 'end' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('end' == 'center') {
text_align_dx = text_width / 2;
} else if ('end' == 'right' ||
('ltr' == 'ltr' && 'end' == 'end') ||
('ltr' == 'rtl' && 'end' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'end';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align end, 0px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('end' == 'center') {
offset -= width / 2;
} else if ('end' == 'right' ||
('rtl' == 'ltr' && 'end' == 'end') ||
('rtl' == 'rtl' && 'end' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('end' == 'center') {
text_align_dx = text_width / 2;
} else if ('end' == 'right' ||
('rtl' == 'ltr' && 'end' == 'end') ||
('rtl' == 'rtl' && 'end' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'end';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align end, 0px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('left' == 'center') {
offset -= width / 2;
} else if ('left' == 'right' ||
('ltr' == 'ltr' && 'left' == 'end') ||
('ltr' == 'rtl' && 'left' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('left' == 'center') {
text_align_dx = text_width / 2;
} else if ('left' == 'right' ||
('ltr' == 'ltr' && 'left' == 'end') ||
('ltr' == 'rtl' && 'left' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'left';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align left, 10px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('left' == 'center') {
offset -= width / 2;
} else if ('left' == 'right' ||
('rtl' == 'ltr' && 'left' == 'end') ||
('rtl' == 'rtl' && 'left' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('left' == 'center') {
text_align_dx = text_width / 2;
} else if ('left' == 'right' ||
('rtl' == 'ltr' && 'left' == 'end') ||
('rtl' == 'rtl' && 'left' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'left';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align left, 10px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('center' == 'center') {
offset -= width / 2;
} else if ('center' == 'right' ||
('ltr' == 'ltr' && 'center' == 'end') ||
('ltr' == 'rtl' && 'center' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('center' == 'center') {
text_align_dx = text_width / 2;
} else if ('center' == 'right' ||
('ltr' == 'ltr' && 'center' == 'end') ||
('ltr' == 'rtl' && 'center' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'center';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align center, 10px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('center' == 'center') {
offset -= width / 2;
} else if ('center' == 'right' ||
('rtl' == 'ltr' && 'center' == 'end') ||
('rtl' == 'rtl' && 'center' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('center' == 'center') {
text_align_dx = text_width / 2;
} else if ('center' == 'right' ||
('rtl' == 'ltr' && 'center' == 'end') ||
('rtl' == 'rtl' && 'center' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'center';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align center, 10px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('right' == 'center') {
offset -= width / 2;
} else if ('right' == 'right' ||
('ltr' == 'ltr' && 'right' == 'end') ||
('ltr' == 'rtl' && 'right' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('right' == 'center') {
text_align_dx = text_width / 2;
} else if ('right' == 'right' ||
('ltr' == 'ltr' && 'right' == 'end') ||
('ltr' == 'rtl' && 'right' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'right';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align right, 10px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('right' == 'center') {
offset -= width / 2;
} else if ('right' == 'right' ||
('rtl' == 'ltr' && 'right' == 'end') ||
('rtl' == 'rtl' && 'right' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('right' == 'center') {
text_align_dx = text_width / 2;
} else if ('right' == 'right' ||
('rtl' == 'ltr' && 'right' == 'end') ||
('rtl' == 'rtl' && 'right' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'right';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align right, 10px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('start' == 'center') {
offset -= width / 2;
} else if ('start' == 'right' ||
('ltr' == 'ltr' && 'start' == 'end') ||
('ltr' == 'rtl' && 'start' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('start' == 'center') {
text_align_dx = text_width / 2;
} else if ('start' == 'right' ||
('ltr' == 'ltr' && 'start' == 'end') ||
('ltr' == 'rtl' && 'start' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'start';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align start, 10px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('start' == 'center') {
offset -= width / 2;
} else if ('start' == 'right' ||
('rtl' == 'ltr' && 'start' == 'end') ||
('rtl' == 'rtl' && 'start' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('start' == 'center') {
text_align_dx = text_width / 2;
} else if ('start' == 'right' ||
('rtl' == 'ltr' && 'start' == 'end') ||
('rtl' == 'rtl' && 'start' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'start';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align start, 10px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('end' == 'center') {
offset -= width / 2;
} else if ('end' == 'right' ||
('ltr' == 'ltr' && 'end' == 'end') ||
('ltr' == 'rtl' && 'end' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('end' == 'center') {
text_align_dx = text_width / 2;
} else if ('end' == 'right' ||
('ltr' == 'ltr' && 'end' == 'end') ||
('ltr' == 'rtl' && 'end' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'end';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align end, 10px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('end' == 'center') {
offset -= width / 2;
} else if ('end' == 'right' ||
('rtl' == 'ltr' && 'end' == 'end') ||
('rtl' == 'rtl' && 'end' == 'start')) {
offset -= width;
}
return offset;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('end' == 'center') {
text_align_dx = text_width / 2;
} else if ('end' == 'right' ||
('rtl' == 'ltr' && 'end' == 'end') ||
('rtl' == 'rtl' && 'end' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'end';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align end, 10px letter spacing and no-directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('left' == 'center') {
offset -= width / 2;
} else if ('left' == 'right' ||
('ltr' == 'ltr' && 'left' == 'end') ||
('ltr' == 'rtl' && 'left' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('left' == 'center') {
text_align_dx = text_width / 2;
} else if ('left' == 'right' ||
('ltr' == 'ltr' && 'left' == 'end') ||
('ltr' == 'rtl' && 'left' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'left';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align left, 0px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('left' == 'center') {
offset -= width / 2;
} else if ('left' == 'right' ||
('rtl' == 'ltr' && 'left' == 'end') ||
('rtl' == 'rtl' && 'left' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('left' == 'center') {
text_align_dx = text_width / 2;
} else if ('left' == 'right' ||
('rtl' == 'ltr' && 'left' == 'end') ||
('rtl' == 'rtl' && 'left' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'left';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align left, 0px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('center' == 'center') {
offset -= width / 2;
} else if ('center' == 'right' ||
('ltr' == 'ltr' && 'center' == 'end') ||
('ltr' == 'rtl' && 'center' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('center' == 'center') {
text_align_dx = text_width / 2;
} else if ('center' == 'right' ||
('ltr' == 'ltr' && 'center' == 'end') ||
('ltr' == 'rtl' && 'center' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'center';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align center, 0px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('center' == 'center') {
offset -= width / 2;
} else if ('center' == 'right' ||
('rtl' == 'ltr' && 'center' == 'end') ||
('rtl' == 'rtl' && 'center' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('center' == 'center') {
text_align_dx = text_width / 2;
} else if ('center' == 'right' ||
('rtl' == 'ltr' && 'center' == 'end') ||
('rtl' == 'rtl' && 'center' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'center';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align center, 0px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('right' == 'center') {
offset -= width / 2;
} else if ('right' == 'right' ||
('ltr' == 'ltr' && 'right' == 'end') ||
('ltr' == 'rtl' && 'right' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('right' == 'center') {
text_align_dx = text_width / 2;
} else if ('right' == 'right' ||
('ltr' == 'ltr' && 'right' == 'end') ||
('ltr' == 'rtl' && 'right' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'right';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align right, 0px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('right' == 'center') {
offset -= width / 2;
} else if ('right' == 'right' ||
('rtl' == 'ltr' && 'right' == 'end') ||
('rtl' == 'rtl' && 'right' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('right' == 'center') {
text_align_dx = text_width / 2;
} else if ('right' == 'right' ||
('rtl' == 'ltr' && 'right' == 'end') ||
('rtl' == 'rtl' && 'right' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'right';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align right, 0px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('start' == 'center') {
offset -= width / 2;
} else if ('start' == 'right' ||
('ltr' == 'ltr' && 'start' == 'end') ||
('ltr' == 'rtl' && 'start' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('start' == 'center') {
text_align_dx = text_width / 2;
} else if ('start' == 'right' ||
('ltr' == 'ltr' && 'start' == 'end') ||
('ltr' == 'rtl' && 'start' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'start';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align start, 0px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('start' == 'center') {
offset -= width / 2;
} else if ('start' == 'right' ||
('rtl' == 'ltr' && 'start' == 'end') ||
('rtl' == 'rtl' && 'start' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('start' == 'center') {
text_align_dx = text_width / 2;
} else if ('start' == 'right' ||
('rtl' == 'ltr' && 'start' == 'end') ||
('rtl' == 'rtl' && 'start' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'start';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align start, 0px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('end' == 'center') {
offset -= width / 2;
} else if ('end' == 'right' ||
('ltr' == 'ltr' && 'end' == 'end') ||
('ltr' == 'rtl' && 'end' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('end' == 'center') {
text_align_dx = text_width / 2;
} else if ('end' == 'right' ||
('ltr' == 'ltr' && 'end' == 'end') ||
('ltr' == 'rtl' && 'end' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'end';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align end, 0px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('end' == 'center') {
offset -= width / 2;
} else if ('end' == 'right' ||
('rtl' == 'ltr' && 'end' == 'end') ||
('rtl' == 'rtl' && 'end' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '0px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('end' == 'center') {
text_align_dx = text_width / 2;
} else if ('end' == 'right' ||
('rtl' == 'ltr' && 'end' == 'end') ||
('rtl' == 'rtl' && 'end' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'end';
ctx.letterSpacing = '0px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('0px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align end, 0px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('left' == 'center') {
offset -= width / 2;
} else if ('left' == 'right' ||
('ltr' == 'ltr' && 'left' == 'end') ||
('ltr' == 'rtl' && 'left' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('left' == 'center') {
text_align_dx = text_width / 2;
} else if ('left' == 'right' ||
('ltr' == 'ltr' && 'left' == 'end') ||
('ltr' == 'rtl' && 'left' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'left';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align left, 10px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('left' == 'center') {
offset -= width / 2;
} else if ('left' == 'right' ||
('rtl' == 'ltr' && 'left' == 'end') ||
('rtl' == 'rtl' && 'left' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('left' == 'center') {
text_align_dx = text_width / 2;
} else if ('left' == 'right' ||
('rtl' == 'ltr' && 'left' == 'end') ||
('rtl' == 'rtl' && 'left' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'left';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align left, 10px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('center' == 'center') {
offset -= width / 2;
} else if ('center' == 'right' ||
('ltr' == 'ltr' && 'center' == 'end') ||
('ltr' == 'rtl' && 'center' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('center' == 'center') {
text_align_dx = text_width / 2;
} else if ('center' == 'right' ||
('ltr' == 'ltr' && 'center' == 'end') ||
('ltr' == 'rtl' && 'center' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'center';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align center, 10px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('center' == 'center') {
offset -= width / 2;
} else if ('center' == 'right' ||
('rtl' == 'ltr' && 'center' == 'end') ||
('rtl' == 'rtl' && 'center' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('center' == 'center') {
text_align_dx = text_width / 2;
} else if ('center' == 'right' ||
('rtl' == 'ltr' && 'center' == 'end') ||
('rtl' == 'rtl' && 'center' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'center';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align center, 10px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('right' == 'center') {
offset -= width / 2;
} else if ('right' == 'right' ||
('ltr' == 'ltr' && 'right' == 'end') ||
('ltr' == 'rtl' && 'right' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('right' == 'center') {
text_align_dx = text_width / 2;
} else if ('right' == 'right' ||
('ltr' == 'ltr' && 'right' == 'end') ||
('ltr' == 'rtl' && 'right' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'right';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align right, 10px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('right' == 'center') {
offset -= width / 2;
} else if ('right' == 'right' ||
('rtl' == 'ltr' && 'right' == 'end') ||
('rtl' == 'rtl' && 'right' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('right' == 'center') {
text_align_dx = text_width / 2;
} else if ('right' == 'right' ||
('rtl' == 'ltr' && 'right' == 'end') ||
('rtl' == 'rtl' && 'right' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'right';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align right, 10px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('start' == 'center') {
offset -= width / 2;
} else if ('start' == 'right' ||
('ltr' == 'ltr' && 'start' == 'end') ||
('ltr' == 'rtl' && 'start' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('start' == 'center') {
text_align_dx = text_width / 2;
} else if ('start' == 'right' ||
('ltr' == 'ltr' && 'start' == 'end') ||
('ltr' == 'rtl' && 'start' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'start';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align start, 10px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('start' == 'center') {
offset -= width / 2;
} else if ('start' == 'right' ||
('rtl' == 'ltr' && 'start' == 'end') ||
('rtl' == 'rtl' && 'start' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('start' == 'center') {
text_align_dx = text_width / 2;
} else if ('start' == 'right' ||
('rtl' == 'ltr' && 'start' == 'end') ||
('rtl' == 'rtl' && 'start' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'start';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align start, 10px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('end' == 'center') {
offset -= width / 2;
} else if ('end' == 'right' ||
('ltr' == 'ltr' && 'end' == 'end') ||
('ltr' == 'rtl' && 'end' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'ltr';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('end' == 'center') {
text_align_dx = text_width / 2;
} else if ('end' == 'right' ||
('ltr' == 'ltr' && 'end' == 'end') ||
('ltr' == 'rtl' && 'end' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'ltr';
ctx.textAlign = 'end';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction ltr, text align end, 10px letter spacing and directional-override.");
test(t => {
const canvas = new OffscreenCanvas(100, 50);
const ctx = canvas.getContext('2d');
function alignOffset(offset, width) {
if ('end' == 'center') {
offset -= width / 2;
} else if ('end' == 'right' ||
('rtl' == 'ltr' && 'end' == 'end') ||
('rtl' == 'rtl' && 'end' == 'start')) {
offset -= width;
}
return offset;
}
function addDirectionalOverrideCharacters(text, direction_is_ltr) {
// source: www.w3.org/International/questions/qa-bidi-unicode-controls.en
const LTR_OVERRIDE = '\u202D';
const RTL_OVERRIDE = '\u202E';
const OVERRIDE_END = '\u202C';
if (direction_is_ltr) {
return LTR_OVERRIDE + text + OVERRIDE_END;
}
return RTL_OVERRIDE + text + OVERRIDE_END;
}
function placeAndMeasureTextInDOM(text, text_width, point) {
const el = document.createElement("p");
el.innerHTML = text;
el.style.font = '50px sans-serif';
el.style.direction = 'rtl';
el.style.letterSpacing = '10px';
// Put the text top left to make offsets simpler.
el.style.padding = '0px';
el.style.margin = '0px';
el.style.position = 'absolute';
el.style.x = '0px';
el.style.y = '0px';
document.body.appendChild(el);
text_bound = el.getBoundingClientRect();
text_x = text_bound.x;
text_y = text_bound.y + text_bound.height / 2;
// Offset to the requested point determined by textAlign and direction.
let text_align_dx = 0;
if ('end' == 'center') {
text_align_dx = text_width / 2;
} else if ('end' == 'right' ||
('rtl' == 'ltr' && 'end' == 'end') ||
('rtl' == 'rtl' && 'end' == 'start')) {
text_align_dx = text_width;
}
position = document.caretPositionFromPoint(point + text_align_dx + text_x, text_y);
_assertSame(position.offsetNode.parentNode, el, "position.offsetNode.parentNode", "el");
document.body.removeChild(el);
return position.offset;
}
ctx.font = '50px sans-serif';
ctx.direction = 'rtl';
ctx.textAlign = 'end';
ctx.letterSpacing = '10px';
const kTexts = [
'UNAVAILABLE',
'🏁🎢🏁',
'οΌ‰οΌˆγ‚οΌ‰οΌˆ',
'οΌ‰οΌˆγ‚γ‚οΌ‰οΌˆ',
'γ‚γ‚οΌ‰οΌˆγ‚γ‚',
'--abcd__'
]
for (text of kTexts) {
text = addDirectionalOverrideCharacters(text, ctx.direction == 'ltr');
const tm = ctx.measureText(text);
text_width = tm.width;
step = 30;
if ('10px' == '10px') {
step = 40;
}
offset = step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 - 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width / 2 + 10;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
offset = text_width - step;
adjusted_offset = alignOffset(offset, text_width);
tm_position = tm.getIndexFromOffset(adjusted_offset);
doc_position = placeAndMeasureTextInDOM(text, text_width, adjusted_offset);
assert_equals(tm_position,
doc_position,
"for " + text + " offset " + offset);
}
}, "Check that TextMetrics::getIndexFromOffset() matches its DOM equivalent, where possible, with direction rtl, text align end, 10px letter spacing and directional-override.");
</script>