blob: c1820edaa8e4704690551912becedda2d725ea29 [file] [log] [blame]
<!DOCTYPE HTML>
<head>
<meta charset="UTF-8">
<style>
@font-face {
font-family: Libertine;
src: url('../../third_party/Libertine/LinLibertine_R.woff');
}
</style>
</head>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script>
const kAligns = [ "left", "right", "center", "start", "end" ];
const kTexts = [
{ text: "Hello", rtl: false },
{ text: "傳統是假的", rtl: false },
{ text: "フェミニズム", rtl: false },
{ text: "ليس", rtl: true },
{ text: "ليس في اسمنا", rtl: true },
{ text: "\u202EHello", rtl: true },
{ text: "\u202EHello World", rtl: true },
{ text: "الله", rtl: true }, // Special ligatures.
{ text: "اين المكتبة؟", rtl: true }, // Special ligatures.
{ text: "🏁🎶🏁", rtl: false }, // One glyph with two "characters".
{ text: "एक आम भाषा", rtl: false }, // Special post-modifying characters.
{ text: "a\u0301", rtl: false }, // Combining diacritical marks
]
function forEachExample(fn) {
for (const ex of kTexts) {
for (const align of kAligns) {
fn(ex, align);
}
}
}
function isNonIncreasing(array) {
for (var i = 1; i < array.length; i++) {
if (array[i] > array[i-1]) {
return false;
}
}
return true;
}
function isNonDecreasing(array) {
for (var i = 1; i < array.length; i++) {
if (array[i] < array[i-1]) {
return false;
}
}
return true;
}
function getTextMetrics(ctx, text, align="left", direction="ltr") {
ctx.font = '25px Libertine';
ctx.textAlign = align;
ctx.direction = direction;
return ctx.measureText(text);
}
function testEmptyStringReturnsEmptyAdvances(ctx) {
const tm = getTextMetrics(ctx, "");
assert_array_equals(tm.advances, [], "Empty string must return empty advances");
}
function testAllPositive(ctx) {
forEachExample((ex, align) => {
const tm = getTextMetrics(ctx, ex.text, align, ex.rtl ? "rtl" : "ltr", );
assert_true(tm.advances.every(function isPositive(i) {return i >= 0; }),
"Advances must be all positive (" + ex.text + ")");
});
}
function testNonIncreasingForRtl(ctx) {
forEachExample((ex, align) => {
if (ex.rtl) {
const tm = getTextMetrics(ctx, ex.text, align, ex.rtl ? "rtl" : "ltr");
assert_true(isNonIncreasing(tm.advances),
"RTL advances must be non-increasing (" + ex.text + ")");
}
});
}
function testNonDecreasingForLtr(ctx) {
forEachExample((ex, align) => {
if (! ex.rtl) {
const tm = getTextMetrics(ctx, ex.text, align, ex.rtl ? "rtl" : "ltr");
assert_true(isNonDecreasing(tm.advances),
"LTR advances must be non-decreasing (" + ex.text + ")");
}
});
}
function testLastAdvanceLessThanWith(ctx) {
forEachExample((ex, align) => {
const tm = getTextMetrics(ctx, ex.text, align, ex.rtl ? "rtl" : "ltr");
assert_less_than(tm.advances.slice(-1)[0], tm.width,
"Last advance must be strictly less than total width (" + ex.text + ")");
});
}
function testAdvances(ctx) {
testEmptyStringReturnsEmptyAdvances(ctx);
testAllPositive(ctx);
testNonIncreasingForRtl(ctx);
testNonDecreasingForLtr(ctx);
testLastAdvanceLessThanWith(ctx);
}
async_test(t => {
var canvas = document.createElement('canvas');
canvas.width = 100;
canvas.height = 100;
var ctx = canvas.getContext('2d');
// Kick off loading of the font
ctx.font = '50px Libertine';
ctx.fillText(" ", 0, 0);
document.fonts.ready.then(t.step_func_done(testAdvances(ctx)));
}, "Test TextMetrics advances.");
</script>